]> git.sesse.net Git - ffmpeg/blobdiff - libavdevice/v4l2.c
Merge commit 'b9ba5253dd1232be4b48cfe61c31ff4b3de3d10a'
[ffmpeg] / libavdevice / v4l2.c
index 5f0102746d59b554151e3a258fd0fd9ce80d938f..2e4b3955059d2087945249130b054b6965cfa141 100644 (file)
@@ -116,6 +116,7 @@ struct video_data {
     int channel;
     char *pixel_format; /**< Set by a private option. */
     int list_format;    /**< Set by a private option. */
+    int list_standard;  /**< Set by a private option. */
     char *framerate;    /**< Set by a private option. */
 };
 
@@ -381,6 +382,30 @@ static void list_formats(AVFormatContext *ctx, int fd, int type)
     }
 }
 
+static void list_standards(AVFormatContext *ctx)
+{
+    int ret;
+    struct video_data *s = ctx->priv_data;
+    struct v4l2_standard standard;
+
+    if (s->std_id == 0)
+        return;
+
+    for (standard.index = 0; ; standard.index++) {
+        ret = v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard);
+        if (ret < 0) {
+            if (errno == EINVAL)
+                break;
+            else {
+                av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", strerror(errno));
+                return;
+            }
+        }
+        av_log(ctx, AV_LOG_INFO, "%2d, %16llx, %s\n",
+               standard.index, standard.id, standard.name);
+    }
+}
+
 static int mmap_init(AVFormatContext *ctx)
 {
     int i, res;
@@ -658,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",
@@ -672,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;
@@ -824,6 +877,11 @@ static int v4l2_read_header(AVFormatContext *s1)
         return AVERROR_EXIT;
     }
 
+    if (s->list_standard) {
+        list_standards(s1);
+        return AVERROR_EXIT;
+    }
+
     avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
 
     if (s->pixel_format) {
@@ -952,6 +1010,9 @@ static const AVOption options[] = {
     { "raw",          "show only non-compressed formats",                         OFFSET(list_format),  AV_OPT_TYPE_CONST,  {.i64 = V4L_RAWFORMATS  },    0, INT_MAX, DEC, "list_formats" },
     { "compressed",   "show only compressed formats",                             OFFSET(list_format),  AV_OPT_TYPE_CONST,  {.i64 = V4L_COMPFORMATS },    0, INT_MAX, DEC, "list_formats" },
 
+    { "list_standards", "list supported standards and exit",                      OFFSET(list_standard), AV_OPT_TYPE_INT,   {.i64 = 0 },  0, 1, DEC, "list_standards" },
+    { "all",            "show all supported standards",                           OFFSET(list_standard), AV_OPT_TYPE_CONST, {.i64 = 1 },  0, 0, DEC, "list_standards" },
+
     { "timestamps",   "set type of timestamps for grabbed frames",                OFFSET(ts_mode),      AV_OPT_TYPE_INT,    {.i64 = 0 }, 0, 2, DEC, "timestamps" },
     { "ts",           "set type of timestamps for grabbed frames",                OFFSET(ts_mode),      AV_OPT_TYPE_INT,    {.i64 = 0 }, 0, 2, DEC, "timestamps" },
     { "default",      "use timestamps from the kernel",                           OFFSET(ts_mode),      AV_OPT_TYPE_CONST,  {.i64 = V4L_TS_DEFAULT  }, 0, 2, DEC, "timestamps" },