Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Mon, 29 Aug 2011 11:43:59 +0000 (13:43 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Mon, 29 Aug 2011 11:43:59 +0000 (13:43 +0200)
Conflicts:
sys/v4l2/v4l2src_calls.c

1  2 
sys/v4l2/gstv4l2object.c

diff --combined sys/v4l2/gstv4l2object.c
  #include "v4l2_calls.h"
  #include "gstv4l2tuner.h"
  #ifdef HAVE_XVIDEO
 -#include "gstv4l2xoverlay.h"
 +#include "gstv4l2videooverlay.h"
  #endif
  #include "gstv4l2colorbalance.h"
  
  #include "gst/gst-i18n-plugin.h"
  
 +#include <gst/video/video.h>
 +
  /* videodev2.h is not versioned and we can't easily check for the presence
   * of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
   * was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */
  #endif
  
  GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
 +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
  #define GST_CAT_DEFAULT v4l2_debug
  
 -
  #define DEFAULT_PROP_DEVICE_NAME      NULL
  #define DEFAULT_PROP_DEVICE_FD          -1
  #define DEFAULT_PROP_FLAGS              0
  #define DEFAULT_PROP_TV_NORM            0
  #define DEFAULT_PROP_CHANNEL            NULL
  #define DEFAULT_PROP_FREQUENCY          0
 +#define DEFAULT_PROP_IO_MODE            GST_V4L2_IO_AUTO
  
  enum
  {
    V4L2_STD_OBJECT_PROPS,
  };
  
 +G_LOCK_DEFINE_STATIC (probe_lock);
 +
  const GList *
  gst_v4l2_probe_get_properties (GstPropertyProbe * probe)
  {
    GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
    static GList *list = NULL;
  
 -  /* well, not perfect, but better than no locking at all.
 -   * In the worst case we leak a list node, so who cares? */
 -  GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
 +  G_LOCK (probe_lock);
  
    if (!list) {
      list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
    }
  
 -  GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
 +  G_UNLOCK (probe_lock);
  
    return list;
  }
@@@ -371,26 -368,6 +371,26 @@@ gst_v4l2_tv_norm_get_type (void
    return v4l2_tv_norm;
  }
  
 +#define GST_TYPE_V4L2_IO_MODE (gst_v4l2_io_mode_get_type ())
 +static GType
 +gst_v4l2_io_mode_get_type (void)
 +{
 +  static GType v4l2_io_mode = 0;
 +
 +  if (!v4l2_io_mode) {
 +    static const GEnumValue io_modes[] = {
 +      {GST_V4L2_IO_AUTO, "GST_V4L2_IO_AUTO", "auto"},
 +      {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"},
 +
 +      {0, NULL, NULL}
 +    };
 +    v4l2_io_mode = g_enum_register_static ("GstV4l2IOMode", io_modes);
 +  }
 +  return v4l2_io_mode;
 +}
 +
  void
  gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
      const char *default_device)
            "video standard",
            GST_TYPE_V4L2_TV_NORM, DEFAULT_PROP_TV_NORM,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 +
 +  /**
 +   * GstV4l2Src:io-mode
 +   *
 +   * IO Mode
 +   */
 +  g_object_class_install_property (gobject_class, PROP_IO_MODE,
 +      g_param_spec_enum ("io-mode", "IO mode",
 +          "I/O mode",
 +          GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
 +          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }
  
  GstV4l2Object *
@@@ -510,7 -476,7 +510,7 @@@ gst_v4l2_object_new (GstElement * eleme
  
    v4l2object->video_fd = -1;
    v4l2object->poll = gst_poll_new (TRUE);
 -  v4l2object->buffer = NULL;
 +  v4l2object->active = FALSE;
    v4l2object->videodev = g_strdup (default_device);
  
    v4l2object->norms = NULL;
@@@ -644,9 -610,6 +644,9 @@@ gst_v4l2_object_set_property_helper (Gs
        }
        break;
  #endif
 +    case PROP_IO_MODE:
 +      v4l2object->req_mode = g_value_get_enum (value);
 +      break;
      default:
        return FALSE;
        break;
@@@ -720,9 -683,6 +720,9 @@@ gst_v4l2_object_get_property_helper (Gs
      case PROP_TV_NORM:
        g_value_set_enum (value, v4l2object->tv_norm);
        break;
 +    case PROP_IO_MODE:
 +      g_value_set_enum (value, v4l2object->req_mode);
 +      break;
      default:
        return FALSE;
        break;
@@@ -789,7 -749,7 +789,7 @@@ gst_v4l2_set_defaults (GstV4l2Object * 
  }
  
  gboolean
 -gst_v4l2_object_start (GstV4l2Object * v4l2object)
 +gst_v4l2_object_open (GstV4l2Object * v4l2object)
  {
    if (gst_v4l2_open (v4l2object))
      gst_v4l2_set_defaults (v4l2object);
      return FALSE;
  
  #ifdef HAVE_XVIDEO
 -  gst_v4l2_xoverlay_start (v4l2object);
 +  gst_v4l2_video_overlay_start (v4l2object);
  #endif
  
    return TRUE;
  }
  
  gboolean
 -gst_v4l2_object_stop (GstV4l2Object * v4l2object)
 +gst_v4l2_object_close (GstV4l2Object * v4l2object)
  {
  #ifdef HAVE_XVIDEO
 -  gst_v4l2_xoverlay_stop (v4l2object);
 +  gst_v4l2_video_overlay_stop (v4l2object);
  #endif
  
    if (!gst_v4l2_close (v4l2object))
@@@ -1187,22 -1147,97 +1187,22 @@@ gst_v4l2_object_v4l2fourcc_to_structur
      case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
        structure = gst_structure_new ("image/jpeg", NULL);
        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;
      case V4L2_PIX_FMT_RGB332:
 -    case V4L2_PIX_FMT_RGB555:
      case V4L2_PIX_FMT_RGB555X:
 -    case V4L2_PIX_FMT_RGB565:
      case V4L2_PIX_FMT_RGB565X:
 +      /* FIXME: get correct fourccs here */
 +      break;
 +    case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
 +    case V4L2_PIX_FMT_RGB555:
 +    case V4L2_PIX_FMT_RGB565:
      case V4L2_PIX_FMT_RGB24:
      case V4L2_PIX_FMT_BGR24:
      case V4L2_PIX_FMT_RGB32:
 -    case V4L2_PIX_FMT_BGR32:{
 -      guint depth = 0, bpp = 0;
 -
 -      gint endianness = 0;
 -
 -      guint32 r_mask = 0, b_mask = 0, g_mask = 0;
 -
 -      switch (fourcc) {
 -        case V4L2_PIX_FMT_RGB332:
 -          bpp = depth = 8;
 -          endianness = G_BYTE_ORDER;    /* 'like, whatever' */
 -          r_mask = 0xe0;
 -          g_mask = 0x1c;
 -          b_mask = 0x03;
 -          break;
 -        case V4L2_PIX_FMT_RGB555:
 -        case V4L2_PIX_FMT_RGB555X:
 -          bpp = 16;
 -          depth = 15;
 -          endianness =
 -              fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
 -          r_mask = 0x7c00;
 -          g_mask = 0x03e0;
 -          b_mask = 0x001f;
 -          break;
 -        case V4L2_PIX_FMT_RGB565:
 -        case V4L2_PIX_FMT_RGB565X:
 -          bpp = depth = 16;
 -          endianness =
 -              fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
 -          r_mask = 0xf800;
 -          g_mask = 0x07e0;
 -          b_mask = 0x001f;
 -          break;
 -        case V4L2_PIX_FMT_RGB24:
 -          bpp = depth = 24;
 -          endianness = G_BIG_ENDIAN;
 -          r_mask = 0xff0000;
 -          g_mask = 0x00ff00;
 -          b_mask = 0x0000ff;
 -          break;
 -        case V4L2_PIX_FMT_BGR24:
 -          bpp = depth = 24;
 -          endianness = G_BIG_ENDIAN;
 -          r_mask = 0x0000ff;
 -          g_mask = 0x00ff00;
 -          b_mask = 0xff0000;
 -          break;
 -        case V4L2_PIX_FMT_RGB32:
 -          bpp = depth = 32;
 -          endianness = G_BIG_ENDIAN;
 -          r_mask = 0xff000000;
 -          g_mask = 0x00ff0000;
 -          b_mask = 0x0000ff00;
 -          break;
 -        case V4L2_PIX_FMT_BGR32:
 -          bpp = depth = 32;
 -          endianness = G_BIG_ENDIAN;
 -          r_mask = 0x000000ff;
 -          g_mask = 0x0000ff00;
 -          b_mask = 0x00ff0000;
 -          break;
 -        default:
 -          g_assert_not_reached ();
 -          break;
 -      }
 -      structure = gst_structure_new ("video/x-raw-rgb",
 -          "bpp", G_TYPE_INT, bpp,
 -          "depth", G_TYPE_INT, depth,
 -          "red_mask", G_TYPE_INT, r_mask,
 -          "green_mask", G_TYPE_INT, g_mask,
 -          "blue_mask", G_TYPE_INT, b_mask,
 -          "endianness", G_TYPE_INT, endianness, NULL);
 -      break;
 -    }
 -    case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
 -      structure = gst_structure_new ("video/x-raw-gray",
 -          "bpp", G_TYPE_INT, 8, NULL);
 -      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;
 +    case V4L2_PIX_FMT_BGR32:
      case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
      case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
      case V4L2_PIX_FMT_YVU410:
      case V4L2_PIX_FMT_YUYV:
      case V4L2_PIX_FMT_YVU420:
      case V4L2_PIX_FMT_UYVY:
 +#if 0
      case V4L2_PIX_FMT_Y41P:
 +#endif
      case V4L2_PIX_FMT_YUV422P:
  #ifdef V4L2_PIX_FMT_YVYU
      case V4L2_PIX_FMT_YVYU:
  #endif
      case V4L2_PIX_FMT_YUV411P:{
 -      guint32 fcc = 0;
 +      GstVideoFormat format;
  
        switch (fourcc) {
 +        case V4L2_PIX_FMT_GREY:        /*  8  Greyscale     */
 +          format = GST_VIDEO_FORMAT_GRAY8;
 +          break;
 +        case V4L2_PIX_FMT_RGB555:
 +          format = GST_VIDEO_FORMAT_RGB15;
 +          break;
 +        case V4L2_PIX_FMT_RGB565:
 +          format = GST_VIDEO_FORMAT_RGB16;
 +          break;
 +        case V4L2_PIX_FMT_RGB24:
 +          format = GST_VIDEO_FORMAT_RGB;
 +          break;
 +        case V4L2_PIX_FMT_BGR24:
 +          format = GST_VIDEO_FORMAT_BGR;
 +          break;
 +        case V4L2_PIX_FMT_RGB32:
 +          format = GST_VIDEO_FORMAT_RGBx;
 +          break;
 +        case V4L2_PIX_FMT_BGR32:
 +          format = GST_VIDEO_FORMAT_BGRx;
 +          break;
          case V4L2_PIX_FMT_NV12:
 -          fcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
 +          format = GST_VIDEO_FORMAT_NV12;
            break;
          case V4L2_PIX_FMT_NV21:
 -          fcc = GST_MAKE_FOURCC ('N', 'V', '2', '1');
 +          format = GST_VIDEO_FORMAT_NV21;
            break;
          case V4L2_PIX_FMT_YVU410:
 -          fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9');
 +          format = GST_VIDEO_FORMAT_YVU9;
            break;
          case V4L2_PIX_FMT_YUV410:
 -          fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
 +          format = GST_VIDEO_FORMAT_YUV9;
            break;
          case V4L2_PIX_FMT_YUV420:
 -          fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
 +          format = GST_VIDEO_FORMAT_I420;
            break;
          case V4L2_PIX_FMT_YUYV:
 -          fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
 +          format = GST_VIDEO_FORMAT_YUY2;
            break;
          case V4L2_PIX_FMT_YVU420:
 -          fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
 +          format = GST_VIDEO_FORMAT_YV12;
            break;
          case V4L2_PIX_FMT_UYVY:
 -          fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
 +          format = GST_VIDEO_FORMAT_UYVY;
            break;
 +#if 0
          case V4L2_PIX_FMT_Y41P:
 -          fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
 +          format = GST_VIDEO_FORMAT_Y41P;
            break;
 +#endif
          case V4L2_PIX_FMT_YUV411P:
 -          fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
 +          format = GST_VIDEO_FORMAT_Y41B;
            break;
          case V4L2_PIX_FMT_YUV422P:
 -          fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
 +          format = GST_VIDEO_FORMAT_Y42B;
            break;
  #ifdef V4L2_PIX_FMT_YVYU
          case V4L2_PIX_FMT_YVYU:
 -          fcc = GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U');
 +          format = GST_VIDEO_FORMAT_YVYU;
            break;
  #endif
          default:
            g_assert_not_reached ();
            break;
        }
 -      structure = gst_structure_new ("video/x-raw-yuv",
 -          "format", GST_TYPE_FOURCC, fcc, NULL);
 +      structure = gst_structure_new ("video/x-raw",
 +          "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
        break;
      }
      case V4L2_PIX_FMT_DV:
@@@ -1369,180 -1379,160 +1369,180 @@@ gst_v4l2_object_get_all_caps (void
   * @fps_n/@fps_d: location for framerate
   * @size: location for expected size of the frame or 0 if unknown
   */
 -gboolean
 +static gboolean
  gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
 -    struct v4l2_fmtdesc ** format, gint * w, gint * h,
 -    gboolean * interlaced, guint * fps_n, guint * fps_d, guint * size)
 +    struct v4l2_fmtdesc **format, GstVideoInfo * info)
  {
    GstStructure *structure;
 -  const GValue *framerate;
    guint32 fourcc;
    const gchar *mimetype;
 -  guint outsize;
 +  struct v4l2_fmtdesc *fmt;
  
    /* default unknown values */
    fourcc = 0;
 -  outsize = 0;
  
    structure = gst_caps_get_structure (caps, 0);
  
    mimetype = gst_structure_get_name (structure);
  
 -  if (strcmp (mimetype, "video/mpegts") == 0) {
 -    fourcc = V4L2_PIX_FMT_MPEG;
 -    *fps_n = 0;
 -    *fps_d = 1;
 -    goto done;
 -  }
 -
 -  if (!gst_structure_get_int (structure, "width", w))
 -    return FALSE;
 -
 -  if (!gst_structure_get_int (structure, "height", h))
 -    return FALSE;
 -
 -  if (!gst_structure_get_boolean (structure, "interlaced", interlaced))
 -    *interlaced = FALSE;
 +  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;
  
 -  framerate = gst_structure_get_value (structure, "framerate");
 -  if (!framerate)
 -    return FALSE;
 -
 -  *fps_n = gst_value_get_fraction_numerator (framerate);
 -  *fps_d = gst_value_get_fraction_denominator (framerate);
 -
 -  if (!strcmp (mimetype, "video/x-raw-yuv")) {
 -    gst_structure_get_fourcc (structure, "format", &fourcc);
 -
 -    switch (fourcc) {
 -      case GST_MAKE_FOURCC ('I', '4', '2', '0'):
 -      case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
 +    switch (GST_VIDEO_INFO_FORMAT (info)) {
 +      case GST_VIDEO_FORMAT_I420:
          fourcc = V4L2_PIX_FMT_YUV420;
 -        outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
 -        outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
          break;
 -      case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
 +      case GST_VIDEO_FORMAT_YUY2:
          fourcc = V4L2_PIX_FMT_YUYV;
 -        outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
          break;
 -      case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
 +#if 0
 +      case GST_VIDEO_FORMAT_Y41P:
          fourcc = V4L2_PIX_FMT_Y41P;
 -        outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
          break;
 -      case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
 +#endif
 +      case GST_VIDEO_FORMAT_UYVY:
          fourcc = V4L2_PIX_FMT_UYVY;
 -        outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
          break;
 -      case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
 +      case GST_VIDEO_FORMAT_YV12:
          fourcc = V4L2_PIX_FMT_YVU420;
 -        outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
 -        outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
          break;
 -      case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
 +      case GST_VIDEO_FORMAT_Y41B:
          fourcc = V4L2_PIX_FMT_YUV411P;
 -        outsize = GST_ROUND_UP_4 (*w) * *h;
 -        outsize += 2 * ((GST_ROUND_UP_8 (*w) / 4) * *h);
          break;
 -      case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
 +      case GST_VIDEO_FORMAT_Y42B:
          fourcc = V4L2_PIX_FMT_YUV422P;
 -        outsize = GST_ROUND_UP_4 (*w) * *h;
 -        outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * *h);
          break;
 -      case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
 +      case GST_VIDEO_FORMAT_NV12:
          fourcc = V4L2_PIX_FMT_NV12;
 -        outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
 -        outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
          break;
 -      case GST_MAKE_FOURCC ('N', 'V', '2', '1'):
 +      case GST_VIDEO_FORMAT_NV21:
          fourcc = V4L2_PIX_FMT_NV21;
 -        outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
 -        outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
          break;
  #ifdef V4L2_PIX_FMT_YVYU
 -      case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
 +      case GST_VIDEO_FORMAT_YVYU:
          fourcc = V4L2_PIX_FMT_YVYU;
 -        outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
          break;
  #endif
 -    }
 -  } else if (!strcmp (mimetype, "video/x-raw-rgb")) {
 -    gint depth, endianness, r_mask;
 -
 -    gst_structure_get_int (structure, "depth", &depth);
 -    gst_structure_get_int (structure, "endianness", &endianness);
 -    gst_structure_get_int (structure, "red_mask", &r_mask);
 -
 -    switch (depth) {
 -      case 8:
 -        fourcc = V4L2_PIX_FMT_RGB332;
 +      case GST_VIDEO_FORMAT_RGB15:
 +        fourcc = V4L2_PIX_FMT_RGB555;
 +        break;
 +      case GST_VIDEO_FORMAT_RGB16:
 +        fourcc = V4L2_PIX_FMT_RGB565;
          break;
 -      case 15:
 -        fourcc = (endianness == G_LITTLE_ENDIAN) ?
 -            V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X;
 +      case GST_VIDEO_FORMAT_RGB:
 +        fourcc = V4L2_PIX_FMT_RGB24;
          break;
 -      case 16:
 -        fourcc = (endianness == G_LITTLE_ENDIAN) ?
 -            V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X;
 +      case GST_VIDEO_FORMAT_BGR:
 +        fourcc = V4L2_PIX_FMT_BGR24;
          break;
 -      case 24:
 -        fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24;
 +      case GST_VIDEO_FORMAT_RGBx:
 +      case GST_VIDEO_FORMAT_RGBA:
 +        fourcc = V4L2_PIX_FMT_RGB32;
          break;
 -      case 32:
 -        fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32;
 +      case GST_VIDEO_FORMAT_BGRx:
 +      case GST_VIDEO_FORMAT_BGRA:
 +        fourcc = V4L2_PIX_FMT_BGR32;
 +        break;
 +      case GST_VIDEO_FORMAT_GRAY8:
 +        fourcc = V4L2_PIX_FMT_GREY;
 +      default:
          break;
      }
 -  } else if (strcmp (mimetype, "video/x-dv") == 0) {
 -    fourcc = V4L2_PIX_FMT_DV;
 -  } else if (strcmp (mimetype, "image/jpeg") == 0) {
 -    fourcc = V4L2_PIX_FMT_JPEG;
 +  } 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_SBGGR8
 -  } else if (strcmp (mimetype, "video/x-raw-bayer") == 0) {
 -    fourcc = V4L2_PIX_FMT_SBGGR8;
 +    } else if (g_str_equal (mimetype, "video/x-raw-bayer")) {
 +      fourcc = V4L2_PIX_FMT_SBGGR8;
  #endif
  #ifdef V4L2_PIX_FMT_SN9C10X
 -  } else if (strcmp (mimetype, "video/x-sonix") == 0) {
 -    fourcc = V4L2_PIX_FMT_SN9C10X;
 +    } else if (g_str_equal (mimetype, "video/x-sonix")) {
 +      fourcc = V4L2_PIX_FMT_SN9C10X;
  #endif
  #ifdef V4L2_PIX_FMT_PWC1
 -  } else if (strcmp (mimetype, "video/x-pwc1") == 0) {
 -    fourcc = V4L2_PIX_FMT_PWC1;
 +    } else if (g_str_equal (mimetype, "video/x-pwc1")) {
 +      fourcc = V4L2_PIX_FMT_PWC1;
  #endif
  #ifdef V4L2_PIX_FMT_PWC2
 -  } else if (strcmp (mimetype, "video/x-pwc2") == 0) {
 -    fourcc = V4L2_PIX_FMT_PWC2;
 +    } else if (g_str_equal (mimetype, "video/x-pwc2")) {
 +      fourcc = V4L2_PIX_FMT_PWC2;
 +    }
  #endif
 -  } else if (strcmp (mimetype, "video/x-raw-gray") == 0) {
 -    fourcc = V4L2_PIX_FMT_GREY;
 +
 +    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)
 -    return FALSE;
 +    goto unhandled_format;
  
 -done:
 -  *format = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
 -  *size = outsize;
 +  fmt = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
 +  if (fmt == NULL)
 +    goto unsupported_format;
 +
 +  *format = fmt;
  
    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");
 +    return FALSE;
 +  }
 +unhandled_format:
 +  {
 +    GST_DEBUG_OBJECT (v4l2object, "unhandled format");
 +    return FALSE;
 +  }
 +unsupported_format:
 +  {
 +    GST_DEBUG_OBJECT (v4l2object, "unsupported format");
 +    return FALSE;
 +  }
  }
  
  
    return FALSE;
  }
  
 +static gboolean
 +gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps)
 +{
 +  GstV4l2IOMode mode;
 +
 +  GST_DEBUG_OBJECT (v4l2object->element, "initializing the capture system");
 +
 +  GST_V4L2_CHECK_OPEN (v4l2object);
 +  GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
 +
 +  /* find transport */
 +  mode = v4l2object->req_mode;
 +
 +  if (v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
 +    if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
 +      mode = GST_V4L2_IO_RW;
 +  } else if (v4l2object->req_mode == GST_V4L2_IO_RW)
 +    goto method_not_supported;
 +
 +  if (v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
 +    if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
 +      mode = GST_V4L2_IO_MMAP;
 +  } else if (v4l2object->req_mode == GST_V4L2_IO_MMAP)
 +    goto method_not_supported;
 +
 +  /* if still no transport selected, error out */
 +  if (mode == GST_V4L2_IO_AUTO)
 +    goto no_supported_capture_method;
 +
 +  GST_INFO_OBJECT (v4l2object->element, "accessing buffers via mode %d", mode);
 +  v4l2object->mode = mode;
 +
 +  /* Map the buffers */
 +  GST_LOG_OBJECT (v4l2object->element, "initiating buffer pool");
 +
 +  if (!(v4l2object->pool = gst_v4l2_buffer_pool_new (v4l2object, caps)))
 +    goto buffer_pool_new_failed;
 +
 +  GST_V4L2_SET_ACTIVE (v4l2object);
 +
 +  return TRUE;
 +
 +  /* ERRORS */
 +buffer_pool_new_failed:
 +  {
 +    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
 +        (_("Could not map buffers from device '%s'"),
 +            v4l2object->videodev),
 +        ("Failed to create buffer pool: %s", g_strerror (errno)));
 +    return FALSE;
 +  }
 +method_not_supported:
 +  {
 +    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
 +        (_("The driver of device '%s' does not support the IO method %d"),
 +            v4l2object->videodev, mode), (NULL));
 +    return FALSE;
 +  }
 +no_supported_capture_method:
 +  {
 +    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
 +        (_("The driver of device '%s' does not support any known IO "
 +                "method."), v4l2object->videodev), (NULL));
 +    return FALSE;
 +  }
 +}
 +
 +
 +/* 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, guint32 pixelformat,
 -    guint32 width, guint32 height, gboolean interlaced)
 +gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
  {
    gint fd = v4l2object->video_fd;
    struct v4l2_format format;
 +  struct v4l2_streamparm streamparm;
    enum v4l2_field field;
 -
 -  if (interlaced) {
 +  guint32 pixelformat;
 +  struct v4l2_fmtdesc *fmtdesc;
 +  GstVideoInfo info;
 +  gint width, height, fps_n, fps_d, stride;
 +
 +  if (!gst_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
 +    goto invalid_caps;
 +
 +  pixelformat = fmtdesc->pixelformat;
 +  width = GST_VIDEO_INFO_WIDTH (&info);
 +  height = GST_VIDEO_INFO_HEIGHT (&info);
 +  fps_n = GST_VIDEO_INFO_FPS_N (&info);
 +  fps_d = GST_VIDEO_INFO_FPS_D (&info);
 +  stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
 +
 +  if (info.flags & GST_VIDEO_FLAG_INTERLACED) {
      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..
      field = V4L2_FIELD_NONE;
    }
  
 -  GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
 -      "%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat));
 +  GST_DEBUG_OBJECT (v4l2object->element, "Desired format %dx%d, format "
 +      "%" GST_FOURCC_FORMAT " stride: %d", width, height,
 +      GST_FOURCC_ARGS (pixelformat), stride);
  
    GST_V4L2_CHECK_OPEN (v4l2object);
    GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
    /* Only unconditionally accept mpegts for sources */
    if ((v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
        (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')))
 -    return TRUE;
 +    goto done;
  
    memset (&format, 0x00, sizeof (struct v4l2_format));
    format.type = v4l2object->type;
    if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0)
      goto get_fmt_failed;
  
 -  if (format.type == v4l2object->type &&
 -      format.fmt.pix.width == width &&
 -      format.fmt.pix.height == height &&
 -      format.fmt.pix.pixelformat == pixelformat &&
 -      format.fmt.pix.field == field) {
 -    /* Nothing to do. We want to succeed immediately
 -     * here because setting the same format back
 -     * can still fail due to EBUSY. By short-circuiting
 -     * here, we allow pausing and re-playing pipelines
 -     * with changed caps, as long as the changed caps
 -     * do not change the webcam's format. Otherwise,
 -     * any caps change would require us to go to NULL
 -     * state to close the device and set format.
 -     */
 -    return TRUE;
 +  GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
 +      "%" GST_FOURCC_FORMAT " bytesperline %d, colorspace %d",
 +      format.fmt.pix.width, format.fmt.pix.height,
 +      GST_FOURCC_ARGS (format.fmt.pix.pixelformat), format.fmt.pix.bytesperline,
 +      format.fmt.pix.colorspace);
 +
 +  if (format.type != v4l2object->type ||
 +      format.fmt.pix.width != width ||
 +      format.fmt.pix.height != height ||
 +      format.fmt.pix.pixelformat != pixelformat ||
 +      format.fmt.pix.field != field || format.fmt.pix.bytesperline != stride) {
 +    /* something different, set the format */
 +    GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
 +        "%" GST_FOURCC_FORMAT " bytesperline %d", width, height,
 +        GST_FOURCC_ARGS (pixelformat), stride);
 +
 +    format.type = v4l2object->type;
 +    format.fmt.pix.width = width;
 +    format.fmt.pix.height = height;
 +    format.fmt.pix.pixelformat = pixelformat;
 +    format.fmt.pix.field = field;
 +    /* try to ask our prefered stride */
 +    format.fmt.pix.bytesperline = stride;
 +
 +    if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0)
 +      goto set_fmt_failed;
 +
 +    GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
 +        "%" GST_FOURCC_FORMAT " stride %d", format.fmt.pix.width,
 +        format.fmt.pix.height, GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
 +        format.fmt.pix.bytesperline);
 +
 +    if (format.fmt.pix.width != width || format.fmt.pix.height != height)
 +      goto invalid_dimensions;
 +
 +    if (format.fmt.pix.pixelformat != pixelformat)
 +      goto invalid_pixelformat;
    }
  
 -  format.type = v4l2object->type;
 -  format.fmt.pix.width = width;
 -  format.fmt.pix.height = height;
 -  format.fmt.pix.pixelformat = pixelformat;
 -  format.fmt.pix.field = field;
 +  /* figure out the frame layout */
 +  v4l2object->bytesperline = format.fmt.pix.bytesperline;
 +  v4l2object->sizeimage = format.fmt.pix.sizeimage;
 +
 +  GST_DEBUG_OBJECT (v4l2object->element, "Got sizeimage %u",
 +      v4l2object->sizeimage);
 +
 +  /* Is there a reason we require the caller to always specify a framerate? */
 +  GST_DEBUG_OBJECT (v4l2object->element, "Desired framerate: %u/%u", fps_n,
 +      fps_d);
 +
 +  memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
 +  streamparm.type = v4l2object->type;
 +
 +  if (v4l2_ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
 +    goto get_parm_failed;
 +
 +  GST_VIDEO_INFO_FPS_N (&info) =
 +      streamparm.parm.capture.timeperframe.denominator;
 +  GST_VIDEO_INFO_FPS_D (&info) = streamparm.parm.capture.timeperframe.numerator;
 +
 +  if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 +    GST_DEBUG_OBJECT (v4l2object->element, "Got framerate: %u/%u",
 +        streamparm.parm.capture.timeperframe.denominator,
 +        streamparm.parm.capture.timeperframe.numerator);
 +
-     /* Note: V4L2 provides the frame interval, we have the frame rate */
-     if (!fractions_are_equal (streamparm.parm.capture.timeperframe.numerator,
-             streamparm.parm.capture.timeperframe.denominator, fps_d, fps_n)) {
-       GST_LOG_OBJECT (v4l2object->element, "Setting framerate to %u/%u", fps_n,
-           fps_d);
-       /* We want to change the frame rate, so check whether we can. Some cheap USB
-        * cameras don't have the capability */
-       if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
-         GST_DEBUG_OBJECT (v4l2object->element,
-             "Not setting framerate (not supported)");
-         goto done;
-       }
++    /* We used to skip frame rate setup if the camera was already setup
++     * with the requested frame rate. This breaks some cameras though,
++     * causing them to not output data (several models of Thinkpad cameras
++     * have this problem at least).
++     * So, don't skip. */
++    GST_LOG_OBJECT (v4l2object->element, "Setting framerate to %u/%u", fps_n,
++        fps_d);
++    /* We want to change the frame rate, so check whether we can. Some cheap USB
++     * cameras don't have the capability */
++    if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
++      GST_DEBUG_OBJECT (v4l2object->element,
++          "Not setting framerate (not supported)");
++      goto done;
++    }
 +
-       /* Note: V4L2 wants the frame interval, we have the frame rate */
-       streamparm.parm.capture.timeperframe.numerator = fps_d;
-       streamparm.parm.capture.timeperframe.denominator = fps_n;
++    /* Note: V4L2 wants the frame interval, we have the frame rate */
++    streamparm.parm.capture.timeperframe.numerator = fps_d;
++    streamparm.parm.capture.timeperframe.denominator = fps_n;
  
-       /* some cheap USB cam's won't accept any change */
-       if (v4l2_ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
-         goto set_parm_failed;
 -  if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) {
 -    goto set_fmt_failed;
++    /* some cheap USB cam's won't accept any change */
++    if (v4l2_ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
++      goto set_parm_failed;
 +
-       /* get new values */
-       fps_d = streamparm.parm.capture.timeperframe.numerator;
-       fps_n = streamparm.parm.capture.timeperframe.denominator;
++    /* get new values */
++    fps_d = streamparm.parm.capture.timeperframe.numerator;
++    fps_n = streamparm.parm.capture.timeperframe.denominator;
 +
-       GST_INFO_OBJECT (v4l2object->element, "Set framerate to %u/%u", fps_n,
-           fps_d);
++    GST_INFO_OBJECT (v4l2object->element, "Set framerate to %u/%u", fps_n,
++        fps_d);
 +
-       GST_VIDEO_INFO_FPS_N (&info) = fps_n;
-       GST_VIDEO_INFO_FPS_D (&info) = fps_d;
-     }
++    GST_VIDEO_INFO_FPS_N (&info) = fps_n;
++    GST_VIDEO_INFO_FPS_D (&info) = fps_d;
    }
  
 -  if (format.fmt.pix.width != width || format.fmt.pix.height != height)
 -    goto invalid_dimensions;
 +done:
 +  /* if we have a framerate pre-calculate duration */
 +  if (fps_n > 0 && fps_d > 0) {
 +    v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
 +  } else {
 +    v4l2object->duration = GST_CLOCK_TIME_NONE;
 +  }
 +  v4l2object->info = info;
 +  v4l2object->fmtdesc = fmtdesc;
  
 -  if (format.fmt.pix.pixelformat != pixelformat)
 -    goto invalid_pixelformat;
 +  /* now configure ther pools */
 +  if (!gst_v4l2_object_setup_pool (v4l2object, caps))
 +    goto pool_failed;
  
    return TRUE;
  
    /* ERRORS */
 +invalid_caps:
 +  {
 +    GST_DEBUG_OBJECT (v4l2object->element, "can't parse caps %" GST_PTR_FORMAT,
 +        caps);
 +    return FALSE;
 +  }
  get_fmt_failed:
    {
      GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
@@@ -2384,220 -2202,30 +2385,220 @@@ invalid_pixelformat
              GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
      return FALSE;
    }
 +get_parm_failed:
 +  {
 +    /* it's possible that this call is not supported */
 +    if (errno != EINVAL) {
 +      GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
 +          (_("Could not get parameters on device '%s'"),
 +              v4l2object->videodev), GST_ERROR_SYSTEM);
 +    }
 +    goto done;
 +  }
 +set_parm_failed:
 +  {
 +    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
 +        (_("Video device did not accept new frame rate setting.")),
 +        GST_ERROR_SYSTEM);
 +    goto done;
 +  }
 +pool_failed:
 +  {
 +    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
 +        (_("Video device could not create buffer pool.")), GST_ERROR_SYSTEM);
 +    return FALSE;
 +  }
  }
  
  gboolean
 -gst_v4l2_object_start_streaming (GstV4l2Object * v4l2object)
 +gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
  {
 -  if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMON,
 -          &(v4l2object->type)) < 0) {
 -    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
 -        (_("Error starting streaming on device '%s'."), v4l2object->videodev),
 -        GST_ERROR_SYSTEM);
 -    return FALSE;
 +  GST_LOG_OBJECT (v4l2object->element, "flush poll");
 +  gst_poll_set_flushing (v4l2object->poll, TRUE);
 +
 +  return TRUE;
 +}
 +
 +gboolean
 +gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
 +{
 +  GST_LOG_OBJECT (v4l2object->element, "flush stop poll");
 +  gst_poll_set_flushing (v4l2object->poll, FALSE);
 +
 +  return TRUE;
 +}
 +
 +gboolean
 +gst_v4l2_object_stop (GstV4l2Object * v4l2object)
 +{
 +  GST_DEBUG_OBJECT (v4l2object->element, "stopping");
 +
 +  if (!GST_V4L2_IS_OPEN (v4l2object))
 +    goto done;
 +  if (!GST_V4L2_IS_ACTIVE (v4l2object))
 +    goto done;
 +
 +  if (v4l2object->pool) {
 +    GST_DEBUG_OBJECT (v4l2object->element, "deactivating pool");
 +    gst_buffer_pool_set_active (GST_BUFFER_POOL_CAST (v4l2object->pool), FALSE);
 +    gst_object_unref (v4l2object->pool);
 +    v4l2object->pool = NULL;
    }
 +
 +  GST_V4L2_SET_INACTIVE (v4l2object);
 +
 +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_stop_streaming (GstV4l2Object * v4l2object)
 +gst_v4l2_object_copy (GstV4l2Object * v4l2object, GstBuffer * dest,
 +    GstBuffer * src)
  {
 -  if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMOFF,
 -          &(v4l2object->type)) < 0) {
 -    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
 -        (_("Error stopping streaming on device '%s'."), v4l2object->videodev),
 -        GST_ERROR_SYSTEM);
 -    return FALSE;
 +  guint8 *data;
 +  gsize size;
 +
 +  if (v4l2object->info.finfo) {
 +    GstVideoFrame src_frame, dest_frame;
 +
 +    GST_DEBUG_OBJECT (v4l2object->element, "copy video frame");
 +
 +    /* we have raw video, use videoframe copy to get strides right */
 +    if (!gst_video_frame_map (&src_frame, &v4l2object->info, src, GST_MAP_READ))
 +      goto invalid_buffer;
 +
 +    if (!gst_video_frame_map (&dest_frame, &v4l2object->info, dest,
 +            GST_MAP_WRITE)) {
 +      gst_video_frame_unmap (&src_frame);
 +      goto invalid_buffer;
 +    }
 +
 +    gst_video_frame_copy (&dest_frame, &src_frame);
 +
 +    gst_video_frame_unmap (&src_frame);
 +    gst_video_frame_unmap (&dest_frame);
 +  } else {
 +    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_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2object->element,
 +      "slow copy into buffer %p", dest);
 +
    return TRUE;
 +
 +  /* ERRORS */
 +invalid_buffer:
 +  {
 +    /* No Window available to put our image into */
 +    GST_WARNING_OBJECT (v4l2object->element, "could not map image");
 +    return FALSE;
 +  }
  }