v4l2: don't extract data from caps twice
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2object.c
index 79f1b78..8de234a 100644 (file)
  * PURPOSE.  See the GNU Library General Public License for more details.
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  * USA.
  */
 
+/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -69,6 +73,7 @@ enum
   V4L2_STD_OBJECT_PROPS,
 };
 
+#if 0
 G_LOCK_DEFINE_STATIC (probe_lock);
 
 const GList *
@@ -290,6 +295,7 @@ gst_v4l2_probe_get_values (GstPropertyProbe * probe,
 
   return array;
 }
+#endif
 
 #define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ())
 static GType
@@ -383,6 +389,7 @@ gst_v4l2_io_mode_get_type (void)
       {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"},
       {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
       {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
+      {GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"},
 
       {0, NULL, NULL}
     };
@@ -483,6 +490,47 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
           "I/O mode",
           GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:extra-controls
+   *
+   * Additional v4l2 controls for the device. The controls are identified
+   * by the control name (lowercase with '_' for any non-alphanumeric
+   * characters).
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
+      g_param_spec_boxed ("extra-controls", "Extra Controls",
+          "Extra v4l2 controls (CIDs) for the device",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:pixel-aspect-ratio
+   *
+   * The pixel aspect ratio of the device. This overwrites the pixel aspect
+   * ratio queried from the device.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
+      g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+          "Overwrite the pixel aspect ratio of the device", "1/1",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:force-aspect-ratio
+   *
+   * When enabled, the pixel aspect ratio queried from the device or set
+   * with the pixel-aspect-ratio property will be enforced.
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
+      g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
+          "When enabled, the pixel aspect ratio will be enforced", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
 }
 
 GstV4l2Object *
@@ -519,6 +567,8 @@ gst_v4l2_object_new (GstElement * element,
 
   v4l2object->xwindow_id = 0;
 
+  v4l2object->keep_aspect = TRUE;
+
   return v4l2object;
 }
 
@@ -647,6 +697,32 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
     case PROP_IO_MODE:
       v4l2object->req_mode = g_value_get_enum (value);
       break;
+    case PROP_EXTRA_CONTROLS:{
+      const GstStructure *s = gst_value_get_structure (value);
+
+      if (v4l2object->extra_controls)
+        gst_structure_free (v4l2object->extra_controls);
+
+      v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
+      if (GST_V4L2_IS_OPEN (v4l2object))
+        gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
+      break;
+    }
+    case PROP_PIXEL_ASPECT_RATIO:
+      g_free (v4l2object->par);
+      v4l2object->par = g_new0 (GValue, 1);
+      g_value_init (v4l2object->par, GST_TYPE_FRACTION);
+      if (!g_value_transform (value, v4l2object->par)) {
+        g_warning ("Could not transform string to aspect ratio");
+        gst_value_set_fraction (v4l2object->par, 1, 1);
+      }
+      GST_DEBUG_OBJECT (v4l2object->element, "set PAR to %d/%d",
+          gst_value_get_fraction_numerator (v4l2object->par),
+          gst_value_get_fraction_denominator (v4l2object->par));
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      v4l2object->keep_aspect = g_value_get_boolean (value);
+      break;
     default:
       return FALSE;
       break;
@@ -723,6 +799,16 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
     case PROP_IO_MODE:
       g_value_set_enum (value, v4l2object->req_mode);
       break;
+    case PROP_EXTRA_CONTROLS:
+      gst_value_set_structure (value, v4l2object->extra_controls);
+      break;
+    case PROP_PIXEL_ASPECT_RATIO:
+      if (v4l2object->par)
+        g_value_transform (v4l2object->par, value);
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      g_value_set_boolean (value, v4l2object->keep_aspect);
+      break;
     default:
       return FALSE;
       break;
@@ -873,6 +959,16 @@ static const GstV4L2FormatDesc gst_v4l2_formats[] = {
 #endif
   {V4L2_PIX_FMT_DV, TRUE},
   {V4L2_PIX_FMT_MPEG, FALSE},
+#ifdef V4L2_PIX_FMT_MPEG4
+  {V4L2_PIX_FMT_MPEG4, TRUE},
+#endif
+
+#ifdef V4L2_PIX_FMT_H263
+  {V4L2_PIX_FMT_H263, TRUE},
+#endif
+#ifdef V4L2_PIX_FMT_H264
+  {V4L2_PIX_FMT_H264, TRUE},
+#endif
 
   /*  Vendor-specific formats   */
   {V4L2_PIX_FMT_WNVA, TRUE},
@@ -933,6 +1029,8 @@ gst_v4l2_object_get_format_from_fourcc (GstV4l2Object * v4l2object,
 
 
 /* complete made up ranking, the values themselves are meaningless */
+/* These ranks MUST be X such that X<<15 fits on a signed int - see
+   the comment at the end of gst_v4l2_object_format_get_rank. */
 #define YUV_BASE_RANK     1000
 #define JPEG_BASE_RANK     500
 #define DV_BASE_RANK       200
@@ -1185,12 +1283,30 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
     case V4L2_PIX_FMT_PJPG:    /* Progressive-JPEG */
 #endif
     case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
-      structure = gst_structure_new ("image/jpeg", NULL);
+      structure = gst_structure_new_empty ("image/jpeg");
       break;
     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
       /* FIXME: get correct fourccs here */
       break;
+#ifdef V4L2_PIX_FMT_MPEG4
+    case V4L2_PIX_FMT_MPEG4:
+      structure = gst_structure_new ("video/mpeg",
+          "mpegversion", G_TYPE_INT, 4, "systemstream",
+          G_TYPE_BOOLEAN, FALSE, NULL);
+      break;
+#endif
+#ifdef V4L2_PIX_FMT_H263
+    case V4L2_PIX_FMT_H263:
+      structure = gst_structure_new ("video/x-h263",
+          "variant", G_TYPE_STRING, "itu", NULL);
+      break;
+#endif
+#ifdef V4L2_PIX_FMT_H264
+    case V4L2_PIX_FMT_H264:    /* H.264 */
+      structure = gst_structure_new_empty ("video/x-h264");
+      break;
+#endif
     case V4L2_PIX_FMT_RGB332:
     case V4L2_PIX_FMT_RGB555X:
     case V4L2_PIX_FMT_RGB565X:
@@ -1284,6 +1400,7 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
           break;
 #endif
         default:
+          format = GST_VIDEO_FORMAT_UNKNOWN;
           g_assert_not_reached ();
           break;
       }
@@ -1297,28 +1414,28 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
           NULL);
       break;
     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
-      structure = gst_structure_new ("video/mpegts", NULL);
+      structure = gst_structure_new_empty ("video/mpegts");
       break;
     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
       break;
 #ifdef V4L2_PIX_FMT_SBGGR8
     case V4L2_PIX_FMT_SBGGR8:
-      structure = gst_structure_new ("video/x-raw-bayer", NULL);
+      structure = gst_structure_new_empty ("video/x-bayer");
       break;
 #endif
 #ifdef V4L2_PIX_FMT_SN9C10X
     case V4L2_PIX_FMT_SN9C10X:
-      structure = gst_structure_new ("video/x-sonix", NULL);
+      structure = gst_structure_new_empty ("video/x-sonix");
       break;
 #endif
 #ifdef V4L2_PIX_FMT_PWC1
     case V4L2_PIX_FMT_PWC1:
-      structure = gst_structure_new ("video/x-pwc1", NULL);
+      structure = gst_structure_new_empty ("video/x-pwc1");
       break;
 #endif
 #ifdef V4L2_PIX_FMT_PWC2
     case V4L2_PIX_FMT_PWC2:
-      structure = gst_structure_new ("video/x-pwc2", NULL);
+      structure = gst_structure_new_empty ("video/x-pwc2");
       break;
 #endif
     default:
@@ -1385,11 +1502,10 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
 
   mimetype = gst_structure_get_name (structure);
 
-  if (g_str_equal (mimetype, "video/x-raw")) {
-    /* raw caps, parse into video info */
-    if (!gst_video_info_from_caps (info, caps))
-      goto invalid_format;
+  if (!gst_video_info_from_caps (info, caps))
+    goto invalid_format;
 
+  if (g_str_equal (mimetype, "video/x-raw")) {
     switch (GST_VIDEO_INFO_FORMAT (info)) {
       case GST_VIDEO_FORMAT_I420:
         fourcc = V4L2_PIX_FMT_YUV420;
@@ -1451,20 +1567,26 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
         break;
     }
   } else {
-    gboolean dimensions = TRUE;
-
-    /* no video caps, construct videoinfo ourselves */
-    gst_video_info_init (info);
-
     if (g_str_equal (mimetype, "video/mpegts")) {
       fourcc = V4L2_PIX_FMT_MPEG;
-      dimensions = FALSE;
     } else if (g_str_equal (mimetype, "video/x-dv")) {
       fourcc = V4L2_PIX_FMT_DV;
     } else if (g_str_equal (mimetype, "image/jpeg")) {
       fourcc = V4L2_PIX_FMT_JPEG;
+#ifdef V4L2_PIX_FMT_MPEG4
+    } else if (g_str_equal (mimetype, "video/mpeg")) {
+      fourcc = V4L2_PIX_FMT_MPEG4;
+#endif
+#ifdef V4L2_PIX_FMT_H263
+    } else if (g_str_equal (mimetype, "video/x-h263")) {
+      fourcc = V4L2_PIX_FMT_H263;
+#endif
+#ifdef V4L2_PIX_FMT_H264
+    } else if (g_str_equal (mimetype, "video/x-h264")) {
+      fourcc = V4L2_PIX_FMT_H264;
+#endif
 #ifdef V4L2_PIX_FMT_SBGGR8
-    } else if (g_str_equal (mimetype, "video/x-raw-bayer")) {
+    } else if (g_str_equal (mimetype, "video/x-bayer")) {
       fourcc = V4L2_PIX_FMT_SBGGR8;
 #endif
 #ifdef V4L2_PIX_FMT_SN9C10X
@@ -1480,25 +1602,6 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
       fourcc = V4L2_PIX_FMT_PWC2;
     }
 #endif
-
-    if (dimensions) {
-      gboolean interlaced;
-
-      if (!gst_structure_get_int (structure, "width", &info->width))
-        goto no_width;
-
-      if (!gst_structure_get_int (structure, "height", &info->height))
-        goto no_height;
-
-      if (!gst_structure_get_boolean (structure, "interlaced", &interlaced))
-        interlaced = FALSE;
-      if (interlaced)
-        info->flags |= GST_VIDEO_FLAG_INTERLACED;
-
-      if (!gst_structure_get_fraction (structure, "framerate", &info->fps_n,
-              &info->fps_d))
-        goto no_framerate;
-    }
   }
 
   if (fourcc == 0)
@@ -1513,21 +1616,6 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
   return TRUE;
 
   /* ERRORS */
-no_width:
-  {
-    GST_DEBUG_OBJECT (v4l2object, "no width");
-    return FALSE;
-  }
-no_height:
-  {
-    GST_DEBUG_OBJECT (v4l2object, "no height");
-    return FALSE;
-  }
-no_framerate:
-  {
-    GST_DEBUG_OBJECT (v4l2object, "no framerate");
-    return FALSE;
-  }
 invalid_format:
   {
     GST_DEBUG_OBJECT (v4l2object, "invalid format");
@@ -1550,6 +1638,43 @@ static gboolean
 gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
     guint32 pixelformat, gint * width, gint * height, gboolean * interlaced);
 
+static void
+gst_v4l2_object_add_aspect_ratio (GstV4l2Object * v4l2object, GstStructure * s)
+{
+  struct v4l2_cropcap cropcap;
+  int num = 1, den = 1;
+
+  if (!v4l2object->keep_aspect)
+    return;
+
+  if (v4l2object->par) {
+    num = gst_value_get_fraction_numerator (v4l2object->par);
+    den = gst_value_get_fraction_denominator (v4l2object->par);
+    goto done;
+  }
+
+  memset (&cropcap, 0, sizeof (cropcap));
+
+  cropcap.type = v4l2object->type;
+  if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
+    goto cropcap_failed;
+
+  num = cropcap.pixelaspect.numerator;
+  den = cropcap.pixelaspect.denominator;
+
+done:
+  gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, num, den,
+      NULL);
+  return;
+
+cropcap_failed:
+  if (errno != ENOTTY)
+    GST_WARNING_OBJECT (v4l2object->element,
+        "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
+        g_strerror (errno));
+  goto done;
+}
+
 
 /* The frame interval enumeration code first appeared in Linux 2.6.19. */
 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
@@ -1567,10 +1692,18 @@ gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
   gint int_width = width;
   gint int_height = height;
 
-  /* interlaced detection using VIDIOC_TRY/S_FMT */
-  if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat,
-          &int_width, &int_height, &interlaced))
-    return NULL;
+  if (!strcmp ((char *) v4l2object->vcap.driver, "uvcvideo")) {
+    /*
+     * UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
+     * causes expensive and slow USB IO, so don't probe them for interlaced
+     */
+    interlaced = FALSE;
+  } else {
+    /* Interlaced detection using VIDIOC_TRY/S_FMT */
+    if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat,
+            &int_width, &int_height, &interlaced))
+      return NULL;
+  }
 
   memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
   ival.index = 0;
@@ -1670,7 +1803,7 @@ gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
         num, denom);
     gst_value_set_fraction (&step, -num, denom);
 
-    while (gst_value_compare (&min, &max) <= 0) {
+    while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN) {
       GValue rate = { 0, };
 
       num = gst_value_get_fraction_numerator (&min);
@@ -1728,8 +1861,11 @@ gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
 return_data:
   s = gst_structure_copy (template);
   gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
-      "height", G_TYPE_INT, (gint) height,
-      "interlaced", G_TYPE_BOOLEAN, interlaced, NULL);
+      "height", G_TYPE_INT, (gint) height, NULL);
+  gst_v4l2_object_add_aspect_ratio (v4l2object, s);
+  if (g_str_equal (gst_structure_get_name (s), "video/x-raw"))
+    gst_structure_set (s, "interlace-mode", G_TYPE_STRING,
+        (interlaced ? "mixed" : "progressive"), NULL);
 
   if (G_IS_VALUE (&rates)) {
     /* only change the framerate on the template when we have a valid probed new
@@ -1791,7 +1927,7 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
   guint32 w, h;
 
   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
-    return gst_caps_new_simple ("video/mpegts", NULL);
+    return gst_caps_new_empty_simple ("video/mpegts");
 
   memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
   size.index = 0;
@@ -1839,7 +1975,7 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
         size.stepwise.step_height);
 
     for (w = size.stepwise.min_width, h = size.stepwise.min_height;
-        w < size.stepwise.max_width && h < size.stepwise.max_height;
+        w <= size.stepwise.max_width && h <= size.stepwise.max_height;
         w += size.stepwise.step_width, h += size.stepwise.step_height) {
       if (w == 0 || h == 0)
         continue;
@@ -1989,7 +2125,10 @@ default_frame_sizes:
     else
       gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
 
-    gst_structure_set (tmp, "interlaced", G_TYPE_BOOLEAN, interlaced, NULL);
+    if (g_str_equal (gst_structure_get_name (tmp), "video/x-raw"))
+      gst_structure_set (tmp, "interlace-mode", G_TYPE_STRING,
+          (interlaced ? "mixed" : "progressive"), NULL);
+    gst_v4l2_object_add_aspect_ratio (v4l2object, tmp);
 
     gst_caps_append_structure (ret, tmp);
 
@@ -2018,6 +2157,7 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
   /* Some drivers are buggy and will modify the currently set format
      when processing VIDIOC_TRY_FMT, so we remember what is set at the
      minute, and will reset it when done. */
+  prevfmt.type = v4l2object->type;
   prevfmt_valid = (v4l2_ioctl (fd, VIDIOC_G_FMT, &prevfmt) >= 0);
 
   /* get size delimiters */
@@ -2169,12 +2309,6 @@ no_supported_capture_method:
   }
 }
 
-
-/* Note about fraction simplification
- *  * n1/d1 == n2/d2  is also written as  n1 == ( n2 * d1 ) / d2
- *   */
-#define fractions_are_equal(n1,d1,n2,d2) ((n1) == gst_util_uint64_scale_int((n2), (d1), (d2)))
-
 gboolean
 gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
 {
@@ -2197,7 +2331,7 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
   fps_d = GST_VIDEO_INFO_FPS_D (&info);
   stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
 
-  if (info.flags & GST_VIDEO_FLAG_INTERLACED) {
+  if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
     GST_DEBUG_OBJECT (v4l2object->element, "interlaced video");
     /* ideally we would differentiate between types of interlaced video
      * but there is not sufficient information in the caps..
@@ -2215,10 +2349,16 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
   GST_V4L2_CHECK_OPEN (v4l2object);
   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
 
+  /* MPEG-TS source cameras don't get their format set for some reason.
+   * It looks wrong and we weren't able to track down the reason for that code
+   * so it is disabled until someone who has an mpeg-ts camera complains...
+   */
+#if 0
   /* Only unconditionally accept mpegts for sources */
   if ((v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
       (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')))
     goto done;
+#endif
 
   memset (&format, 0x00, sizeof (struct v4l2_format));
   format.type = v4l2object->type;
@@ -2397,7 +2537,7 @@ invalid_pixelformat:
 get_parm_failed:
   {
     /* it's possible that this call is not supported */
-    if (errno != EINVAL) {
+    if (errno != EINVAL && errno != ENOTTY) {
       GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
           (_("Could not get parameters on device '%s'"),
               v4l2object->videodev), GST_ERROR_SYSTEM);
@@ -2420,6 +2560,21 @@ pool_failed:
 }
 
 gboolean
+gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps)
+{
+  GstStructure *s;
+  GstCaps *oldcaps;
+
+  if (!v4l2object->pool)
+    return FALSE;
+
+  s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (v4l2object->pool));
+  gst_buffer_pool_config_get_params (s, &oldcaps, NULL, NULL, NULL);
+
+  return oldcaps && gst_caps_is_equal (caps, oldcaps);
+}
+
+gboolean
 gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
 {
   GST_LOG_OBJECT (v4l2object->element, "flush poll");
@@ -2460,120 +2615,14 @@ done:
   return TRUE;
 }
 
-#if 0
-static GstFlowReturn
-gst_v4l2_object_get_mmap (GstV4l2Object * v4l2object, GstBuffer ** buf)
-{
-  GstFlowReturn res;
-#define NUM_TRIALS 50
-  GstBufferPool *pool;
-  gint32 trials = NUM_TRIALS;
-  GstBuffer *pool_buffer;
-  gboolean need_copy;
-
-  pool = v4l2object->pool;
-  if (!pool)
-    goto no_buffer_pool;
-
-  GST_DEBUG_OBJECT (v4l2object->element, "grab frame");
-
-  for (;;) {
-    if ((res = gst_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
-      goto poll_error;
-
-    res = gst_buffer_pool_acquire_buffer (pool, &pool_buffer, NULL);
-    if (res != GST_FLOW_OK)
-      goto no_buffer;
-
-    if (v4l2object->size > 0) {
-      gsize size = gst_buffer_get_size (pool_buffer);
-
-      /* if size does not match what we expected, try again */
-      if (size != v4l2object->size) {
-        GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, READ,
-            (_("Got unexpected frame size of %u instead of %u."),
-                size, v4l2object->size), (NULL));
-        gst_buffer_unref (pool_buffer);
-        goto no_buffer;
-      }
-    }
-    /* when we get here all is fine */
-    break;
-
-  no_buffer:
-    GST_WARNING_OBJECT (v4l2object->element, "trials=%d", trials);
-
-    /* if the sync() got interrupted, we can retry */
-    switch (errno) {
-      case EINVAL:
-      case ENOMEM:
-        /* fatal */
-        return GST_FLOW_ERROR;
-
-      case EAGAIN:
-      case EIO:
-      case EINTR:
-      default:
-        /* try again, until too many trials */
-        break;
-    }
-
-    /* check nr. of attempts to capture */
-    if (--trials == -1) {
-      goto too_many_trials;
-    }
-  }
-
-
-  /* if we are handing out the last buffer in the pool, we need to make a
-   * copy and bring the buffer back in the pool. */
-  need_copy = v4l2object->always_copy
-      || !gst_v4l2_buffer_pool_available_buffers (pool);
-
-  if (G_UNLIKELY (need_copy)) {
-    if (!v4l2object->always_copy) {
-      GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2object->element,
-          "running out of buffers, making a copy to reuse current one");
-    }
-    *buf = gst_buffer_copy (pool_buffer);
-    /* this will requeue */
-    gst_buffer_unref (pool_buffer);
-  } else {
-    *buf = pool_buffer;
-  }
-
-  return GST_FLOW_OK;
-
-  /* ERRORS */
-no_buffer_pool:
-  {
-    GST_DEBUG_OBJECT (v4l2object->element, "no buffer pool");
-    return GST_FLOW_WRONG_STATE;
-  }
-poll_error:
-  {
-    return res;
-  }
-too_many_trials:
-  {
-    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, FAILED,
-        (_("Failed trying to get video frames from device '%s'."),
-            v4l2object->videodev),
-        (_("Failed after %d tries. device %s. system error: %s"),
-            NUM_TRIALS, v4l2object->videodev, g_strerror (errno)));
-    return GST_FLOW_ERROR;
-  }
-}
-#endif
-
 gboolean
 gst_v4l2_object_copy (GstV4l2Object * v4l2object, GstBuffer * dest,
     GstBuffer * src)
 {
-  guint8 *data;
-  gsize size;
+  const GstVideoFormatInfo *finfo = v4l2object->info.finfo;
 
-  if (v4l2object->info.finfo) {
+  if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
+          finfo->format != GST_VIDEO_FORMAT_ENCODED)) {
     GstVideoFrame src_frame, dest_frame;
 
     GST_DEBUG_OBJECT (v4l2object->element, "copy video frame");
@@ -2593,10 +2642,13 @@ gst_v4l2_object_copy (GstV4l2Object * v4l2object, GstBuffer * dest,
     gst_video_frame_unmap (&src_frame);
     gst_video_frame_unmap (&dest_frame);
   } else {
+    GstMapInfo map;
+
     GST_DEBUG_OBJECT (v4l2object->element, "copy raw bytes");
-    data = gst_buffer_map (src, &size, NULL, GST_MAP_READ);
-    gst_buffer_fill (dest, 0, data, size);
-    gst_buffer_unmap (src, data, size);
+    gst_buffer_map (src, &map, GST_MAP_READ);
+    gst_buffer_fill (dest, 0, map.data, gst_buffer_get_size (src));
+    gst_buffer_unmap (src, &map);
+    gst_buffer_resize (dest, 0, gst_buffer_get_size (src));
   }
   GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2object->element,
       "slow copy into buffer %p", dest);