diff --git a/common b/common
index 888e0a2..6ab11d1 160000
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 888e0a268b60904dd208b672a3c57f1ff7d9786c
+Subproject commit 6ab11d17cb8e4d1ed755da7accac9630d567a097
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c
index 2923a3d..9668cc2 100644
--- a/sys/v4l2/gstv4l2src.c
+++ b/sys/v4l2/gstv4l2src.c
@@ -67,7 +67,12 @@ GST_ELEMENT_DETAILS ("Video (video4linux2) Source",
 GST_DEBUG_CATEGORY (v4l2src_debug);
 #define GST_CAT_DEFAULT v4l2src_debug
 
-#define PROP_DEF_QUEUE_SIZE         2
+/* queue-size=1 will cause immediate copies to keep something enqueued
+ * queue-size=2 will probably cause every 2nd buffer to be copied
+ * queue-size=3 ensure that src and sink can have a bufefr enqueue and one
+ *   buffer is traveling
+ */
+#define PROP_DEF_QUEUE_SIZE         3
 #define PROP_DEF_ALWAYS_COPY        TRUE
 
 enum
@@ -1069,15 +1074,15 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
     /* error already posted */
     return FALSE;
 
+  /* now store the expected output size */
+  v4l2src->frame_byte_size = size;
+
   if (!gst_v4l2src_capture_init (v4l2src, caps))
     return FALSE;
 
   if (!gst_v4l2src_capture_start (v4l2src))
     return FALSE;
 
-  /* now store the expected output size */
-  v4l2src->frame_byte_size = size;
-
   return TRUE;
 }
 
@@ -1204,29 +1209,29 @@ gst_v4l2src_stop (GstBaseSrc * src)
 static GstFlowReturn
 gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
 {
-  gint amount;
-  gint ret;
-
-  gint buffersize;
-
-  buffersize = v4l2src->frame_byte_size;
+  GstBuffer *temp;
+  gint poll_ret;
+  GstFlowReturn ret;
+  gint size;
 
-  *buf = gst_buffer_new_and_alloc (buffersize);
+  ret = gst_pad_alloc_buffer(GST_BASE_SRC_PAD(v4l2src), 0LL, v4l2src->frame_byte_size,
+      NULL, &temp);
+  if (ret != GST_FLOW_OK)
+    goto done;
 
   do {
-    ret = gst_poll_wait (v4l2src->v4l2object->poll, GST_CLOCK_TIME_NONE);
-    if (G_UNLIKELY (ret < 0)) {
+    poll_ret = gst_poll_wait (v4l2src->v4l2object->poll, GST_CLOCK_TIME_NONE);
+    if (G_UNLIKELY (poll_ret < 0)) {
       if (errno == EBUSY)
         goto stopped;
       if (errno != EAGAIN && errno != EINTR)
         goto select_error;
     }
-    amount =
-        v4l2_read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
-        buffersize);
-    if (amount == buffersize) {
+    size = v4l2_read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (temp),
+        v4l2src->frame_byte_size);
+    if (size == v4l2src->frame_byte_size) {
       break;
-    } else if (amount == -1) {
+    } else if (size == -1) {
       if (errno == EAGAIN || errno == EINTR) {
         continue;
       } else
@@ -1238,8 +1243,9 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
   } while (TRUE);
 
   /* we set the buffer metadata in gst_v4l2src_create() */
-
-  return GST_FLOW_OK;
+  *buf = temp;
+done:
+  return ret;
 
   /* ERRORS */
 select_error:
@@ -1257,8 +1263,9 @@ read_error:
   {
     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
         (_("Error reading %d bytes from device '%s'."),
-            buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
-    gst_buffer_unref (*buf);
+            v4l2src->frame_byte_size, v4l2src->v4l2object->videodev),
+        GST_ERROR_SYSTEM);
+    gst_buffer_unref (temp);
     return GST_FLOW_ERROR;
   }
 }
@@ -1313,7 +1320,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
 
   GstFlowReturn ret;
 
-  if (v4l2src->use_mmap) {
+  if (v4l2src->use_streaming) {
     ret = gst_v4l2src_get_mmap (v4l2src, buf);
   } else {
     ret = gst_v4l2src_get_read (v4l2src, buf);
diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h
index bedae8a..34794b0 100644
--- a/sys/v4l2/gstv4l2src.h
+++ b/sys/v4l2/gstv4l2src.h
@@ -64,14 +64,15 @@ struct _GstV4l2BufferPool
   gint num_live_buffers; /* with lock */
   gint video_fd; /* a dup(2) of the v4l2object's video_fd */
   guint buffer_count;
-  GstV4l2Buffer **buffers; /* with lock; buffers[n] is NULL that buffer has been
+  GstBuffer **buffers; /* with lock; buffers[n] is NULL that buffer has been
                             * dequeued and pushed out */
+  struct v4l2_buffer *vbuffers;
 };
 
 struct _GstV4l2Buffer {
   GstBuffer   buffer;
 
-  struct v4l2_buffer vbuffer;
+  gint index;
 
   /* FIXME: have GstV4l2Src* instead, as this has GstV4l2BufferPool* */
   GstV4l2BufferPool *pool;
@@ -100,6 +101,7 @@ struct _GstV4l2Src
   GstV4l2BufferPool *pool;
 
   guint32 num_buffers;
+  gboolean use_streaming;
   gboolean use_mmap;
   guint32 frame_byte_size;
 
diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c
index 30556af..2799218 100644
--- a/sys/v4l2/v4l2src_calls.c
+++ b/sys/v4l2/v4l2src_calls.c
@@ -73,12 +73,13 @@ static void
 gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer)
 {
   GstV4l2BufferPool *pool;
+  struct v4l2_buffer *vbuffer;
   gboolean resuscitated = FALSE;
   gint index;
 
   pool = buffer->pool;
-
-  index = buffer->vbuffer.index;
+  index = buffer->index;
+  vbuffer = &pool->vbuffers[index];
 
   GST_LOG ("finalizing buffer %p %d", buffer, index);
 
@@ -88,14 +89,14 @@ gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer)
     pool->num_live_buffers--;
 
   if (pool->running) {
-    if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &buffer->vbuffer) < 0) {
+    if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, vbuffer) < 0) {
       GST_WARNING ("could not requeue buffer %p %d", buffer, index);
     } else {
       /* FIXME: check that the caps didn't change */
       GST_LOG ("reviving buffer %p, %d", buffer, index);
       gst_buffer_ref (GST_BUFFER (buffer));
       GST_BUFFER_SIZE (buffer) = 0;
-      pool->buffers[index] = buffer;
+      pool->buffers[index] = (GstBuffer *)buffer;
       resuscitated = TRUE;
     }
   } else {
@@ -106,7 +107,7 @@ gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer)
   if (!resuscitated) {
     GST_LOG ("buffer %p not recovered, unmapping", buffer);
     gst_mini_object_unref (GST_MINI_OBJECT (pool));
-    v4l2_munmap ((void *) GST_BUFFER_DATA (buffer), buffer->vbuffer.length);
+    v4l2_munmap ((void *) GST_BUFFER_DATA (buffer), vbuffer->length);
 
     GST_MINI_OBJECT_CLASS (v4l2buffer_parent_class)->finalize (GST_MINI_OBJECT
         (buffer));
@@ -148,51 +149,81 @@ gst_v4l2_buffer_get_type (void)
   return _gst_v4l2_buffer_type;
 }
 
-static GstV4l2Buffer *
-gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps)
+static GstBuffer *
+gst_v4l2_buffer_new (GstV4l2BufferPool * pool, GstV4l2Src * v4l2src, 
+  guint index, GstCaps * caps)
 {
-  GstV4l2Buffer *ret;
-  guint8 *data;
+  GstBuffer *ret = NULL;
+  GstFlowReturn flow_ret;
+  struct v4l2_buffer *vbuffer;
+
+  vbuffer = &pool->vbuffers[index];
+  vbuffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  vbuffer->index = index;
 
-  ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER);
+  GST_LOG ("creating buffer %u, in pool %p", index, pool);
 
-  GST_LOG ("creating buffer %u, %p in pool %p", index, ret, pool);
+  if (v4l2src->use_mmap) {
+    GstV4l2Buffer *buf;
+    guint8 *data;
 
-  ret->pool =
-      (GstV4l2BufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool));
+    buf = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER);
+    ret = (GstBuffer *) buf;
 
-  ret->vbuffer.index = index;
-  ret->vbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-  ret->vbuffer.memory = V4L2_MEMORY_MMAP;
+    buf->pool =
+        (GstV4l2BufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool));
+    buf->index = index;
 
-  if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &ret->vbuffer) < 0)
-    goto querybuf_failed;
+    vbuffer->memory = V4L2_MEMORY_MMAP;
 
-  GST_LOG ("  index:     %u", ret->vbuffer.index);
-  GST_LOG ("  type:      %d", ret->vbuffer.type);
-  GST_LOG ("  bytesused: %u", ret->vbuffer.bytesused);
-  GST_LOG ("  flags:     %08x", ret->vbuffer.flags);
-  GST_LOG ("  field:     %d", ret->vbuffer.field);
-  GST_LOG ("  memory:    %d", ret->vbuffer.memory);
-  if (ret->vbuffer.memory == V4L2_MEMORY_MMAP)
-    GST_LOG ("  MMAP offset:  %u", ret->vbuffer.m.offset);
-  GST_LOG ("  length:    %u", ret->vbuffer.length);
-  GST_LOG ("  input:     %u", ret->vbuffer.input);
+    if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, vbuffer) < 0)
+      goto querybuf_failed;
 
-  data = (guint8 *) v4l2_mmap (0, ret->vbuffer.length,
-      PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd,
-      ret->vbuffer.m.offset);
+    data = (guint8 *) v4l2_mmap (0, vbuffer->length, PROT_READ | PROT_WRITE,
+        MAP_SHARED, pool->video_fd, vbuffer->m.offset);
 
-  if (data == MAP_FAILED)
-    goto mmap_failed;
+    if (data == MAP_FAILED)
+      goto mmap_failed;
 
-  GST_BUFFER_DATA (ret) = data;
-  GST_BUFFER_SIZE (ret) = ret->vbuffer.length;
+    GST_BUFFER_DATA (buf) = data;
+    GST_BUFFER_SIZE (buf) = vbuffer->length;
 
-  GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
+
+    gst_buffer_set_caps (GST_BUFFER (buf), caps);
+  } else {
+    GstBuffer *buf = NULL;
 
-  gst_buffer_set_caps (GST_BUFFER (ret), caps);
+    vbuffer->memory = V4L2_MEMORY_USERPTR;
+    vbuffer->length = v4l2src->frame_byte_size;
 
+    /* VIDIOC_QUERYBUF is part of the memory mapping I/O method
+     * if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, vbuffer) < 0)
+     *  goto querybuf_failed;
+     */
+
+    flow_ret = gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (v4l2src),
+      0LL, vbuffer->length, caps, &buf);
+    if (flow_ret != GST_FLOW_OK)
+      goto pad_alloc_failed;
+
+    vbuffer->m.userptr = (unsigned int) GST_BUFFER_DATA (buf);
+    ret = buf;
+  }
+#if 1
+  GST_LOG ("  index:     %u", vbuffer->index);
+  GST_LOG ("  type:      %d", vbuffer->type);
+  GST_LOG ("  bytesused: %u", vbuffer->bytesused);
+  GST_LOG ("  flags:     %08x", vbuffer->flags);
+  GST_LOG ("  field:     %d", vbuffer->field);
+  GST_LOG ("  memory:    %d", vbuffer->memory);
+  if (vbuffer->memory == V4L2_MEMORY_MMAP)
+    GST_LOG ("  mmap offset:  %u", vbuffer->m.offset);
+  else if (vbuffer->memory == V4L2_MEMORY_USERPTR)
+    GST_LOG ("  user address: %u", vbuffer->m.userptr);
+  GST_LOG ("  length:    %u", vbuffer->length);
+  GST_LOG ("  input:     %u", vbuffer->input);
+#endif
   return ret;
 
   /* ERRORS */
@@ -214,8 +245,15 @@ mmap_failed:
     errno = errnosave;
     return NULL;
   }
+pad_alloc_failed:
+  {
+    GST_WARNING ("Failed to pad_alloc_buffer: %s", 
+      gst_flow_get_name (flow_ret));
+    return NULL;
+  }
 }
 
+
 #define GST_TYPE_V4L2_BUFFER_POOL (gst_v4l2_buffer_pool_get_type())
 #define GST_IS_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL))
 #define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
@@ -235,7 +273,10 @@ gst_v4l2_buffer_pool_finalize (GstV4l2BufferPool * pool)
     g_free (pool->buffers);
     pool->buffers = NULL;
   }
-
+  if (pool->vbuffers) {
+    g_free (pool->vbuffers);
+    pool->vbuffers = NULL;
+  }
   GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT
       (pool));
 }
@@ -284,8 +325,7 @@ gst_v4l2_buffer_pool_get_type (void)
 }
 
 static GstV4l2BufferPool *
-gst_v4l2_buffer_pool_new (GstV4l2Src * v4l2src, gint fd, gint num_buffers,
-    GstCaps * caps)
+gst_v4l2_buffer_pool_new (GstV4l2Src * v4l2src, gint fd, GstCaps * caps)
 {
   GstV4l2BufferPool *pool;
   gint n;
@@ -296,12 +336,12 @@ gst_v4l2_buffer_pool_new (GstV4l2Src * v4l2src, gint fd, gint num_buffers,
   if (pool->video_fd < 0)
     goto dup_failed;
 
-  pool->buffer_count = num_buffers;
-  pool->buffers = g_new0 (GstV4l2Buffer *, num_buffers);
+  pool->buffer_count = v4l2src->num_buffers;
+  pool->buffers = g_new0 (GstBuffer *, pool->buffer_count);
+  pool->vbuffers = g_new0 (struct v4l2_buffer, pool->buffer_count);
 
-  for (n = 0; n < num_buffers; n++) {
-    pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps);
-    if (!pool->buffers[n])
+  for (n = 0; n < pool->buffer_count; n++) {
+    if (! (pool->buffers[n] = gst_v4l2_buffer_new (pool, v4l2src, n, caps)))
       goto buffer_new_failed;
   }
 
@@ -334,17 +374,16 @@ static gboolean
 gst_v4l2_buffer_pool_activate (GstV4l2BufferPool * pool, GstV4l2Src * v4l2src)
 {
   gint n;
+  struct v4l2_buffer *vbuffer;
 
   g_mutex_lock (pool->lock);
 
   for (n = 0; n < pool->buffer_count; n++) {
-    struct v4l2_buffer *buf;
-
-    buf = &pool->buffers[n]->vbuffer;
+    vbuffer = &pool->vbuffers[n];
 
     GST_LOG ("enqueue pool buffer %d", n);
 
-    if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, buf) < 0)
+    if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, vbuffer) < 0)
       goto queue_failed;
   }
   pool->running = TRUE;
@@ -366,6 +405,41 @@ queue_failed:
   }
 }
 
+/* requeue buffers that are writable again */
+static gboolean
+gst_v4l2_buffer_pool_update (GstV4l2BufferPool * pool, GstV4l2Src * v4l2src)
+{
+  gint n;
+  struct v4l2_buffer qbuffer = {0,};
+  struct v4l2_buffer *vbuffer;
+
+  g_mutex_lock (pool->lock);
+
+  for (n = 0; n < pool->buffer_count; n++) {
+    vbuffer = &pool->vbuffers[n];
+
+    qbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    qbuffer.memory = V4L2_MEMORY_USERPTR;
+    qbuffer.index = n;
+    if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &qbuffer) >= 0) {
+      if (((qbuffer.flags & V4L2_BUF_FLAG_QUEUED) == 0) && 
+          gst_buffer_is_writable (pool->buffers[n])) {
+        if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, vbuffer) < 0) {
+          GST_WARNING_OBJECT (v4l2src, "could not requeue buffer %p at index %d",
+            pool->buffers[n], n);
+        } else {
+          GST_INFO ("reviving buffer %p, %d", pool->buffers[n], n);
+          pool->num_live_buffers--;
+        }
+      }
+    }
+  }
+
+  g_mutex_unlock (pool->lock);
+
+  return TRUE;
+}
+
 static void
 gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)
 {
@@ -398,6 +472,7 @@ gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)
   gst_mini_object_unref (GST_MINI_OBJECT (pool));
 }
 
+
 /* complete made up ranking, the values themselves are meaningless */
 #define YUV_BASE_RANK     1000
 #define JPEG_BASE_RANK     500
@@ -987,6 +1062,7 @@ GstFlowReturn
 gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
 {
 #define NUM_TRIALS 50
+  gint fd = v4l2src->v4l2object->video_fd;
   struct v4l2_buffer buffer;
   gint32 trials = NUM_TRIALS;
   GstBuffer *pool_buffer;
@@ -994,9 +1070,20 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
   gint index;
   gint ret;
 
+  if (!v4l2src->use_mmap) {
+    /* requeue buffers that are writable again */
+    gst_v4l2_buffer_pool_update (v4l2src->pool, v4l2src);
+  }
+
   memset (&buffer, 0x00, sizeof (buffer));
   buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-  buffer.memory = V4L2_MEMORY_MMAP;
+  if (v4l2src->use_mmap) {
+    buffer.memory = V4L2_MEMORY_MMAP;
+  } else {
+    buffer.memory = V4L2_MEMORY_USERPTR;
+  }
+
+  GST_LOG_OBJECT (v4l2src, "grabing buffer");
 
   for (;;) {
     ret = gst_poll_wait (v4l2src->v4l2object->poll, GST_CLOCK_TIME_NONE);
@@ -1007,7 +1094,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
         goto select_error;
     }
 
-    if (v4l2_ioctl (v4l2src->v4l2object->video_fd, VIDIOC_DQBUF, &buffer) >= 0)
+    if (v4l2_ioctl (fd, VIDIOC_DQBUF, &buffer) >= 0)
       break;
 
     GST_WARNING_OBJECT (v4l2src,
@@ -1051,7 +1138,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
            * return.
            */
           /*
-             if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer) < 0) {
+             if (ioctl (fd, VIDIOC_QBUF, &buffer) < 0) {
              goto qbuf_failed;
              }
            */
@@ -1076,7 +1163,11 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
     } else {
       memset (&buffer, 0x00, sizeof (buffer));
       buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-      buffer.memory = V4L2_MEMORY_MMAP;
+      if (v4l2src->use_mmap) {
+        buffer.memory = V4L2_MEMORY_MMAP;
+      } else {
+        buffer.memory = V4L2_MEMORY_USERPTR;
+      }
     }
   }
 
@@ -1084,18 +1175,27 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
 
   index = buffer.index;
 
-  /* get our GstBuffer with that index from the pool, if the buffer was
-   * outstanding we have a serious problem. */
+  /* get our GstBuffer with that index from the pool, if the buffer is
+   * in use (NULL) we have a serious problem (should only be possible in mmap
+   * case). */
   pool_buffer = GST_BUFFER (v4l2src->pool->buffers[index]);
 
-  if (pool_buffer == NULL)
+  if (G_UNLIKELY (pool_buffer == NULL))
     goto no_buffer;
 
-  GST_LOG_OBJECT (v4l2src, "grabbed buffer %p at index %d", pool_buffer, index);
+  GST_LOG_OBJECT (v4l2src, "grabbed buffer %p at index %d (refct = %d)",
+    pool_buffer, index, GST_MINI_OBJECT_REFCOUNT(pool_buffer));
 
-  /* we have the  buffer now, mark the spot in the pool empty */
-  v4l2src->pool->buffers[index] = NULL;
   v4l2src->pool->num_live_buffers++;
+  if (v4l2src->use_mmap) {
+    /* we have the buffer now, mark the spot in the pool empty */
+    v4l2src->pool->buffers[index] = NULL;
+  }
+  else {
+    /* ref the buffer and requeue, when if becomes writable again */
+    v4l2src->pool->buffers[index] = gst_buffer_ref (pool_buffer);
+  }
+
   /* 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 = v4l2src->always_copy
@@ -1107,6 +1207,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
   GST_BUFFER_SIZE (pool_buffer) = buffer.bytesused;
 
   if (G_UNLIKELY (need_copy)) {
+    GST_INFO_OBJECT (v4l2src, "copying buffer");
     *buf = gst_buffer_copy (pool_buffer);
     GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
     /* this will requeue */
@@ -1330,6 +1431,18 @@ invalid_pixelformat:
   }
 }
 
+static gint
+gst_v4l2src_probe_buffer_memory_type (GstV4l2Src * v4l2src,
+  struct v4l2_requestbuffers *breq, gint num_buffers, enum v4l2_memory memory)
+{
+    memset (breq, 0, sizeof (struct v4l2_requestbuffers));
+    breq->count = num_buffers;
+    breq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    breq->memory = memory;
+
+    return v4l2_ioctl (v4l2src->v4l2object->video_fd, VIDIOC_REQBUFS, breq);
+}
+
 /******************************************************
  * gst_v4l2src_capture_init():
  *   initialize the capture system
@@ -1341,50 +1454,66 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
   gint fd = v4l2src->v4l2object->video_fd;
   struct v4l2_requestbuffers breq;
 
-  memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
-
   GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
 
   GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
   GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
 
   if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
-
-    GST_DEBUG_OBJECT (v4l2src, "STREAMING, requesting %d MMAP CAPTURE buffers",
-        v4l2src->num_buffers);
-
-    breq.count = v4l2src->num_buffers;
-    breq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-    breq.memory = V4L2_MEMORY_MMAP;
-
-    if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0)
-      goto reqbufs_failed;
-
-    GST_LOG_OBJECT (v4l2src, " count:  %u", breq.count);
-    GST_LOG_OBJECT (v4l2src, " type:   %d", breq.type);
-    GST_LOG_OBJECT (v4l2src, " memory: %d", breq.memory);
-
-    if (breq.count < GST_V4L2_MIN_BUFFERS)
-      goto no_buffers;
-
-    if (v4l2src->num_buffers != breq.count) {
-      GST_WARNING_OBJECT (v4l2src, "using %u buffers instead", breq.count);
-      v4l2src->num_buffers = breq.count;
-      g_object_notify (G_OBJECT (v4l2src), "queue-size");
+    gint ioret;
+
+    /* negotiate memory mapping or user pointer i/o */
+    if ((ioret = gst_v4l2src_probe_buffer_memory_type(v4l2src, &breq, 0,
+        V4L2_MEMORY_USERPTR) < 0)) {
+      /* libv4l2 returns EINVAL for num_buffers==0, but the spec says otherwise
+       * http://www.linuxtv.org/downloads/video4linux/API/V4L2_API/spec/r9579.htm
+       */
+      GST_DEBUG_OBJECT (v4l2src,
+          "VIDIOC_REQBUFS(V4L2_MEMORY_USERPTR) failed %d:%s",
+          errno,g_strerror (errno));
+      if ((ioret = gst_v4l2src_probe_buffer_memory_type(v4l2src, &breq, 
+          v4l2src->num_buffers, V4L2_MEMORY_USERPTR) < 0)) {
+        GST_DEBUG_OBJECT (v4l2src,
+            "VIDIOC_REQBUFS(V4L2_MEMORY_USERPTR) for %d buffers failed %d:%s",
+            v4l2src->num_buffers, errno,g_strerror (errno));
+        if ((ioret = gst_v4l2src_probe_buffer_memory_type(v4l2src, &breq, 
+            v4l2src->num_buffers, V4L2_MEMORY_MMAP) < 0)) {
+          GST_DEBUG_OBJECT (v4l2src,
+              "VIDIOC_REQBUFS(V4L2_MEMORY_MMAP) for %d buffers failed %d:%s",
+              v4l2src->num_buffers, errno, g_strerror (errno));
+          goto reqbufs_failed;
+        } else {
+          GST_INFO_OBJECT (v4l2src, "allocate buffers via mmap");
+          if (breq.count < GST_V4L2_MIN_BUFFERS)
+            goto no_buffers;
+      
+          if (v4l2src->num_buffers != breq.count) {
+            GST_WARNING_OBJECT (v4l2src, "using %u buffers instead", breq.count);
+            v4l2src->num_buffers = breq.count;
+            g_object_notify (G_OBJECT (v4l2src), "queue-size");
+          }
+          v4l2src->use_mmap = TRUE;
+        }
+      } else {
+        GST_INFO_OBJECT (v4l2src, "allocate buffers via pad_alloc");
+        v4l2src->use_mmap = FALSE;
+      }
+    } else {
+      GST_INFO_OBJECT (v4l2src, "allocate buffers via pad_alloc");
+      v4l2src->use_mmap = FALSE;
     }
 
-    /* Map the buffers */
+    /* Obtain the buffers */
     GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
 
-    if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (v4l2src, fd,
-                v4l2src->num_buffers, caps)))
+    if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (v4l2src, fd, caps)))
       goto buffer_pool_new_failed;
 
-    GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
-    v4l2src->use_mmap = TRUE;
+    GST_INFO_OBJECT (v4l2src, "capturing buffers via streaming");
+    v4l2src->use_streaming = TRUE;
   } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
-    GST_INFO_OBJECT (v4l2src, "capturing buffers via read()");
-    v4l2src->use_mmap = FALSE;
+    GST_INFO_OBJECT (v4l2src, "capturing buffers via read");
+    v4l2src->use_streaming = FALSE;
     v4l2src->pool = NULL;
   } else {
     goto no_supported_capture_method;
@@ -1448,7 +1577,7 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
 
   v4l2src->quit = FALSE;
 
-  if (v4l2src->use_mmap) {
+  if (v4l2src->use_streaming) {
     if (!gst_v4l2_buffer_pool_activate (v4l2src->pool, v4l2src))
       goto pool_activate_failed;
 
@@ -1494,7 +1623,7 @@ gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
     goto done;
   }
 
-  if (v4l2src->use_mmap) {
+  if (v4l2src->use_streaming) {
     /* we actually need to sync on all queued buffers but not
      * on the non-queued ones */
     if (v4l2_ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0)
