Commit cd4578a1 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

v4l2: rationalize/factorize frame rate handling

parent 3e73ad2a
...@@ -765,21 +765,25 @@ int SetupInput (vlc_object_t *obj, int fd) ...@@ -765,21 +765,25 @@ int SetupInput (vlc_object_t *obj, int fd)
} }
/** Compares two V4L2 fractions. */ /** Compares two V4L2 fractions. */
static int64_t fcmp (struct v4l2_fract a, struct v4l2_fract b) static int64_t fcmp (const struct v4l2_fract *a,
const struct v4l2_fract *b)
{ {
return (uint64_t)a.numerator * b.denominator return (uint64_t)a->numerator * b->denominator
- (uint64_t)b.numerator * a.denominator; - (uint64_t)b->numerator * a->denominator;
} }
static const struct v4l2_fract infinity = { 1, 0 };
/** /**
* Finds the highest frame rate possible of a certain V4L2 format. * Finds the highest frame rate possible of a certain V4L2 format.
* @param fmt V4L2 capture format [IN] * @param fmt V4L2 capture format [IN]
* @param parm V4L2 capture streaming parameters [IN]
* @param it V4L2 frame interval [OUT] * @param it V4L2 frame interval [OUT]
* @return 0 on success, -1 on failure.
*/ */
static int FindMaxRate (vlc_object_t *obj, int fd, static void FindMaxRate (vlc_object_t *obj, int fd,
const struct v4l2_format *restrict fmt, const struct v4l2_format *restrict fmt,
struct v4l2_fract *restrict it) const struct v4l2_streamparm *restrict parm,
struct v4l2_fract *restrict it)
{ {
struct v4l2_frmivalenum fie = { struct v4l2_frmivalenum fie = {
.pixel_format = fmt->fmt.pix.pixelformat, .pixel_format = fmt->fmt.pix.pixelformat,
...@@ -787,21 +791,30 @@ static int FindMaxRate (vlc_object_t *obj, int fd, ...@@ -787,21 +791,30 @@ static int FindMaxRate (vlc_object_t *obj, int fd,
.height = fmt->fmt.pix.height, .height = fmt->fmt.pix.height,
}; };
/* Mind that maximum rate means minimum interval */ /* Mind that maximum rate means minimum interval */
struct v4l2_fract min = { 1, 0 }; /* infinity */
if (!(parm->parm.capture.capability & V4L2_CAP_TIMEPERFRAME))
{
*it = parm->parm.capture.timeperframe;
msg_Dbg (obj, " constant frame interval: %"PRIu32"/%"PRIu32,
it->numerator, it->denominator);
}
else
if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie) < 0) if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie) < 0)
{ {
msg_Dbg (obj, " unknown frame internals: %m"); msg_Warn (obj, " unknown frame intervals: %m");
return -1; *it = parm->parm.capture.timeperframe;
msg_Dbg (obj, " default frame interval: %"PRIu32"/%"PRIu32,
it->numerator, it->denominator);
} }
else
switch (fie.type) switch (fie.type)
{ {
case V4L2_FRMIVAL_TYPE_DISCRETE: case V4L2_FRMIVAL_TYPE_DISCRETE:
*it = infinity;
do do
{ {
if (fcmp (fie.discrete, min) < 0) if (fcmp (&fie.discrete, it) < 0)
min = fie.discrete; *it = fie.discrete;
msg_Dbg (obj, " discrete frame interval: %"PRIu32"/%"PRIu32, msg_Dbg (obj, " discrete frame interval: %"PRIu32"/%"PRIu32,
fie.discrete.numerator, fie.discrete.denominator); fie.discrete.numerator, fie.discrete.denominator);
fie.index++; fie.index++;
...@@ -809,7 +822,7 @@ static int FindMaxRate (vlc_object_t *obj, int fd, ...@@ -809,7 +822,7 @@ static int FindMaxRate (vlc_object_t *obj, int fd,
while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie) >= 0); while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie) >= 0);
msg_Dbg (obj, " best discrete frame interval: %"PRIu32"/%"PRIu32, msg_Dbg (obj, " best discrete frame interval: %"PRIu32"/%"PRIu32,
min.numerator, min.denominator); it->numerator, it->denominator);
break; break;
case V4L2_FRMIVAL_TYPE_STEPWISE: case V4L2_FRMIVAL_TYPE_STEPWISE:
...@@ -822,12 +835,9 @@ static int FindMaxRate (vlc_object_t *obj, int fd, ...@@ -822,12 +835,9 @@ static int FindMaxRate (vlc_object_t *obj, int fd,
msg_Dbg (obj, " with %"PRIu32"/%"PRIu32" step", msg_Dbg (obj, " with %"PRIu32"/%"PRIu32" step",
fie.stepwise.step.numerator, fie.stepwise.step.numerator,
fie.stepwise.step.denominator); fie.stepwise.step.denominator);
min = fie.stepwise.min; *it = fie.stepwise.min;
break; break;
} }
*it = min;
return 0;
} }
#undef SetupFormat #undef SetupFormat
...@@ -865,7 +875,7 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc, ...@@ -865,7 +875,7 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc,
struct v4l2_frmsizeenum fse = { struct v4l2_frmsizeenum fse = {
.pixel_format = fourcc, .pixel_format = fourcc,
}; };
struct v4l2_fract best_it = { 1, 0 }; /* infinity */ struct v4l2_fract best_it = infinity;
uint64_t best_area = 0; uint64_t best_area = 0;
if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &fse) < 0) if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &fse) < 0)
...@@ -874,13 +884,7 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc, ...@@ -874,13 +884,7 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc,
msg_Dbg (obj, " unknown frame sizes: %m"); msg_Dbg (obj, " unknown frame sizes: %m");
msg_Dbg (obj, " default frame size: %"PRIu32"x%"PRIu32, msg_Dbg (obj, " default frame size: %"PRIu32"x%"PRIu32,
fmt->fmt.pix.width, fmt->fmt.pix.height); fmt->fmt.pix.width, fmt->fmt.pix.height);
if (!(parm->parm.capture.capability & V4L2_CAP_TIMEPERFRAME) FindMaxRate (obj, fd, fmt, parm, &best_it);
|| FindMaxRate (obj, fd, fmt, &best_it))
{
best_it = parm->parm.capture.timeperframe;
msg_Dbg (obj, " constant frame interval: %"PRIu32"/%"PRIu32,
best_it.numerator, best_it.denominator);
}
} }
else else
switch (fse.type) switch (fse.type)
...@@ -892,11 +896,9 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc, ...@@ -892,11 +896,9 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc,
msg_Dbg (obj, " frame size %"PRIu32"x%"PRIu32, msg_Dbg (obj, " frame size %"PRIu32"x%"PRIu32,
fse.discrete.width, fse.discrete.height); fse.discrete.width, fse.discrete.height);
if (FindMaxRate (obj, fd, fmt, &cur_it)) FindMaxRate (obj, fd, fmt, parm, &cur_it);
/* If frame rate is not known, find largest resolution */
cur_it.denominator = 0;
int64_t c = fcmp (cur_it, best_it); int64_t c = fcmp (&cur_it, &best_it);
uint64_t area = fse.discrete.width * fse.discrete.height; uint64_t area = fse.discrete.width * fse.discrete.height;
if (c < 0 || (c == 0 && area > best_area)) if (c < 0 || (c == 0 && area > best_area))
{ {
...@@ -934,10 +936,9 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc, ...@@ -934,10 +936,9 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc,
{ {
struct v4l2_fract cur_it; struct v4l2_fract cur_it;
if (FindMaxRate (obj, fd, fmt, &cur_it)) FindMaxRate (obj, fd, fmt, parm, &cur_it);
continue;
int64_t c = fcmp (cur_it, best_it); int64_t c = fcmp (&cur_it, &best_it);
uint64_t area = width * height; uint64_t area = width * height;
if (c < 0 || (c == 0 && area > best_area)) if (c < 0 || (c == 0 && area > best_area))
...@@ -954,15 +955,16 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc, ...@@ -954,15 +955,16 @@ int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc,
break; break;
} }
parm->parm.capture.timeperframe = best_it;
if (v4l2_ioctl (fd, VIDIOC_S_FMT, fmt) < 0) if (v4l2_ioctl (fd, VIDIOC_S_FMT, fmt) < 0)
{ {
msg_Err (obj, "cannot set format: %m"); msg_Err (obj, "cannot set format: %m");
return -1; return -1;
} }
parm->parm.capture.timeperframe = best_it;
if (v4l2_ioctl (fd, VIDIOC_S_PARM, parm) < 0) if (v4l2_ioctl (fd, VIDIOC_S_PARM, parm) < 0)
msg_Warn (obj, "cannot set streaming parameters: %m"); msg_Warn (obj, "cannot set streaming parameters: %m");
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment