[FFmpeg-cvslog] lavd/v4l2: read the correct time per frame from devices that support a standard

Giorgio Vazzana git at videolan.org
Thu Jan 31 15:34:52 CET 2013


ffmpeg | branch: master | Giorgio Vazzana <mywing81 at gmail.com> | Wed Jan 30 15:08:04 2013 +0100| [514216d8a928cf80980ca8dc5daea46e9d41cad9] | committer: Stefano Sabatini

lavd/v4l2: read the correct time per frame from devices that support a standard

Generally speaking, there are two types of v4l2 devices [1]:

1) devices that support a standard, like PAL or NTFS (tv cards, for example). For
this class of devices the framerate is fixed by the standard (for example PAL uses
25 fps) and the v4l2 driver cannot usually negotiate a different framerate (unless
it can skip frames on the driver side, to save I/O bandwidth).

2) devices for which the notion of standard does not make sense (webcams, for example).
For these devices it is usually possibile to request a desidered framerate.

In either case, the desidered frame rate can be requested when the VIDIOC_G_PARM
ioctl returns the V4L2_CAP_TIMEPERFRAME flag in the capability field.

Currently the code does not check for V4L2_CAP_TIMEPERFRAME and supports only the
second category of devices, returning a time per frame of 0/0 for devices in the
first group that do not permit to negotiate the framerate.

This patch adds support to read the correct framerate in all cases.

[1] http://linuxtv.org/downloads/v4l-dvb-apis/standard.html

Signed-off-by: Stefano Sabatini <stefasab at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=514216d8a928cf80980ca8dc5daea46e9d41cad9
---

 libavdevice/v4l2.c |  116 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 72 insertions(+), 44 deletions(-)

diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index 76b6d64..2e4b395 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -683,12 +683,10 @@ static int v4l2_set_parameters(AVFormatContext *s1)
     struct video_data *s = s1->priv_data;
     struct v4l2_standard standard = { 0 };
     struct v4l2_streamparm streamparm = { 0 };
-    struct v4l2_fract *tpf = &streamparm.parm.capture.timeperframe;
+    struct v4l2_fract *tpf;
     AVRational framerate_q = { 0 };
     int i, ret;
 
-    streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
     if (s->framerate &&
         (ret = av_parse_video_rate(&framerate_q, s->framerate)) < 0) {
         av_log(s1, AV_LOG_ERROR, "Could not parse framerate '%s'.\n",
@@ -697,57 +695,87 @@ static int v4l2_set_parameters(AVFormatContext *s1)
     }
 
     if (s->standard) {
-        av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set standard: %s\n",
-               s->standard);
-        /* set tv standard */
-        for(i=0;;i++) {
+        if (s->std_id) {
+            av_log(s1, AV_LOG_DEBUG, "Setting standard: %s\n", s->standard);
+            /* set tv standard */
+            for (i = 0; ; i++) {
+                standard.index = i;
+                ret = v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard);
+                if (ret < 0 || !av_strcasecmp(standard.name, s->standard))
+                    break;
+            }
+            if (ret < 0) {
+                ret = errno;
+                av_log(s1, AV_LOG_ERROR, "Unknown or unsupported standard '%s'\n", s->standard);
+                return AVERROR(ret);
+            }
+
+            if (v4l2_ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) {
+                ret = errno;
+                av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_STD): %s\n", strerror(errno));
+                return AVERROR(ret);
+            }
+        } else {
+            av_log(s1, AV_LOG_WARNING,
+                   "This device does not support any standard\n");
+        }
+    }
+
+    /* get standard */
+    if (v4l2_ioctl(s->fd, VIDIOC_G_STD, &s->std_id) == 0) {
+        tpf = &standard.frameperiod;
+        for (i = 0; ; i++) {
             standard.index = i;
             ret = v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard);
-            if (ret < 0 || !av_strcasecmp(standard.name, s->standard))
+            if (ret < 0) {
+                ret = errno;
+                av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", strerror(errno));
+                return AVERROR(ret);
+            }
+            if (standard.id == s->std_id) {
+                av_log(s1, AV_LOG_DEBUG,
+                       "Current standard: %s, id: %"PRIu64", frameperiod: %d/%d\n",
+                       standard.name, (uint64_t)standard.id, tpf->numerator, tpf->denominator);
                 break;
+            }
         }
-        if (ret < 0) {
-            av_log(s1, AV_LOG_ERROR, "Unknown standard '%s'\n", s->standard);
-            return ret;
-        }
+    } else {
+        tpf = &streamparm.parm.capture.timeperframe;
+    }
 
-        av_log(s1, AV_LOG_DEBUG,
-               "The V4L2 driver set standard: %s, id: %"PRIu64"\n",
-               s->standard, (uint64_t)standard.id);
-        if (v4l2_ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) {
-            av_log(s1, AV_LOG_ERROR,
-                   "The V4L2 driver ioctl set standard(%s) failed\n",
-                   s->standard);
-            return AVERROR(EIO);
-        }
+    streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) {
+        ret = errno;
+        av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_PARM): %s\n", strerror(errno));
+        return AVERROR(ret);
     }
 
     if (framerate_q.num && framerate_q.den) {
-        av_log(s1, AV_LOG_DEBUG, "Setting time per frame to %d/%d\n",
-               framerate_q.den, framerate_q.num);
-        tpf->numerator   = framerate_q.den;
-        tpf->denominator = framerate_q.num;
-
-        if (v4l2_ioctl(s->fd, VIDIOC_S_PARM, &streamparm) != 0) {
-            av_log(s1, AV_LOG_ERROR,
-                   "ioctl set time per frame(%d/%d) failed\n",
+        if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
+            tpf = &streamparm.parm.capture.timeperframe;
+
+            av_log(s1, AV_LOG_DEBUG, "Setting time per frame to %d/%d\n",
                    framerate_q.den, framerate_q.num);
-            return AVERROR(EIO);
-        }
+            tpf->numerator   = framerate_q.den;
+            tpf->denominator = framerate_q.num;
 
-        if (framerate_q.num != tpf->denominator ||
-            framerate_q.den != tpf->numerator) {
-            av_log(s1, AV_LOG_INFO,
-                   "The driver changed the time per frame from "
-                   "%d/%d to %d/%d\n",
-                   framerate_q.den, framerate_q.num,
-                   tpf->numerator, tpf->denominator);
-        }
-    } else {
-        if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) != 0) {
-            av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_PARM): %s\n",
-                   strerror(errno));
-            return AVERROR(errno);
+            if (v4l2_ioctl(s->fd, VIDIOC_S_PARM, &streamparm) < 0) {
+                ret = errno;
+                av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_PARM): %s\n", strerror(errno));
+                return AVERROR(ret);
+            }
+
+            if (framerate_q.num != tpf->denominator ||
+                framerate_q.den != tpf->numerator) {
+                av_log(s1, AV_LOG_INFO,
+                       "The driver changed the time per frame from "
+                       "%d/%d to %d/%d\n",
+                       framerate_q.den, framerate_q.num,
+                       tpf->numerator, tpf->denominator);
+            }
+        } else {
+            av_log(s1, AV_LOG_WARNING,
+                   "The driver does not allow to change time per frame\n");
         }
     }
     s1->streams[0]->avg_frame_rate.num = tpf->denominator;



More information about the ffmpeg-cvslog mailing list