X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=sys%2Fv4l2%2Fgstv4l2bufferpool.c;h=f8851569da2a01494fbccb2d83709ddba92fcfce;hb=2e80c0d2c08d1fbda3286bfe397153ec65661322;hp=21454ec75d82850ead60956630ddb58769f2f81e;hpb=dc540c23dae5c7ecaf060fdd6fbde21c2140be89;p=platform%2Fupstream%2Fgst-plugins-good.git diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index 21454ec..f885156 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -18,8 +18,8 @@ * * 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, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -29,17 +29,20 @@ #include #include #include +#if HAVE_DECL_V4L2_MEMORY_DMABUF +#include +#endif #include "gst/video/video.h" #include "gst/video/gstvideometa.h" #include "gst/video/gstvideopool.h" +#include "gst/allocators/gstdmabuf.h" #include -#include "gstv4l2src.h" -#include "gstv4l2sink.h" #include "v4l2_calls.h" #include "gst/gst-i18n-plugin.h" +#include /* 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 @@ -56,17 +59,30 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); /* * GstV4l2Buffer: */ +GType +gst_v4l2_meta_api_get_type (void) +{ + static volatile GType type; + static const gchar *tags[] = { "memory", NULL }; + + if (g_once_init_enter (&type)) { + GType _type = gst_meta_api_type_register ("GstV4l2MetaAPI", tags); + g_once_init_leave (&type, _type); + } + return type; +} + const GstMetaInfo * gst_v4l2_meta_get_info (void) { static const GstMetaInfo *meta_info = NULL; - if (meta_info == NULL) { - meta_info = - gst_meta_register ("GstV4l2Meta", "GstV4l2Meta", + if (g_once_init_enter (&meta_info)) { + const GstMetaInfo *meta = + gst_meta_register (gst_v4l2_meta_api_get_type (), "GstV4l2Meta", sizeof (GstV4l2Meta), (GstMetaInitFunction) NULL, - (GstMetaFreeFunction) NULL, (GstMetaCopyFunction) NULL, - (GstMetaTransformFunction) NULL); + (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL); + g_once_init_leave (&meta_info, meta); } return meta_info; } @@ -90,6 +106,7 @@ gst_v4l2_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) switch (obj->mode) { case GST_V4L2_IO_RW: + case GST_V4L2_IO_DMABUF: break; case GST_V4L2_IO_MMAP: { @@ -101,7 +118,7 @@ gst_v4l2_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) index = meta->vbuffer.index; GST_LOG_OBJECT (pool, - "mmap buffer %p idx %d (data %p, len %u) freed, unmapping", buffer, + "unmap buffer %p idx %d (data %p, len %u)", buffer, index, meta->mem, meta->vbuffer.length); v4l2_munmap (meta->mem, meta->vbuffer.length); @@ -118,7 +135,7 @@ gst_v4l2_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer) static GstFlowReturn gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, - GstBufferPoolParams * params) + GstBufferPoolAcquireParams * params) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstBuffer *newbuf; @@ -134,10 +151,11 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, case GST_V4L2_IO_RW: { newbuf = - gst_buffer_new_allocate (pool->allocator, pool->size, pool->align); + gst_buffer_new_allocate (pool->allocator, pool->size, &pool->params); break; } case GST_V4L2_IO_MMAP: + case GST_V4L2_IO_DMABUF: { newbuf = gst_buffer_new (); meta = GST_V4L2_META_ADD (newbuf); @@ -161,39 +179,67 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, GST_LOG_OBJECT (pool, " memory: %d", meta->vbuffer.memory); if (meta->vbuffer.memory == V4L2_MEMORY_MMAP) GST_LOG_OBJECT (pool, " MMAP offset: %u", meta->vbuffer.m.offset); - GST_LOG_OBJECT (pool, " length: %u", meta->vbuffer.length); - GST_LOG_OBJECT (pool, " input: %u", meta->vbuffer.input); - - meta->mem = v4l2_mmap (0, meta->vbuffer.length, - PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, - meta->vbuffer.m.offset); - if (meta->mem == MAP_FAILED) - goto mmap_failed; - - gst_buffer_take_memory (newbuf, -1, - gst_memory_new_wrapped (0, - meta->mem, NULL, meta->vbuffer.length, 0, meta->vbuffer.length)); + if (obj->mode == GST_V4L2_IO_MMAP) { + meta->mem = v4l2_mmap (0, meta->vbuffer.length, + PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, + meta->vbuffer.m.offset); + if (meta->mem == MAP_FAILED) + goto mmap_failed; + + gst_buffer_append_memory (newbuf, + gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, + meta->mem, meta->vbuffer.length, 0, meta->vbuffer.length, NULL, + NULL)); + } +#if HAVE_DECL_V4L2_MEMORY_DMABUF + if (obj->mode == GST_V4L2_IO_DMABUF) { + struct v4l2_exportbuffer expbuf; + + expbuf.type = meta->vbuffer.type; + expbuf.index = meta->vbuffer.index; + expbuf.flags = O_CLOEXEC; + if (v4l2_ioctl (pool->video_fd, VIDIOC_EXPBUF, &expbuf) < 0) + goto mmap_failed; + + meta->vbuffer.memory = V4L2_MEMORY_DMABUF; + gst_buffer_append_memory (newbuf, + gst_dmabuf_allocator_alloc (pool->allocator, expbuf.fd, + meta->vbuffer.length)); + } +#endif /* add metadata to raw video buffers */ if (pool->add_videometa && info->finfo) { + const GstVideoFormatInfo *finfo = info->finfo; gsize offset[GST_VIDEO_MAX_PLANES]; - gint stride[GST_VIDEO_MAX_PLANES]; + gint width, height, n_planes, offs, i, stride[GST_VIDEO_MAX_PLANES]; + + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + n_planes = GST_VIDEO_INFO_N_PLANES (info); - offset[0] = 0; - stride[0] = obj->bytesperline; + GST_DEBUG_OBJECT (pool, "adding video meta, bytesperline %d", + obj->bytesperline); - GST_DEBUG_OBJECT (pool, "adding video meta, stride %d", stride[0]); - gst_buffer_add_video_meta_full (newbuf, info->flags, - GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info), - GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info), + offs = 0; + for (i = 0; i < n_planes; i++) { + offset[i] = offs; + stride[i] = + GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, obj->bytesperline); + + offs += + stride[i] * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, height); + } + gst_buffer_add_video_meta_full (newbuf, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT (info), width, height, n_planes, offset, stride); } break; } case GST_V4L2_IO_USERPTR: default: + newbuf = NULL; g_assert_not_reached (); - break; } pool->num_allocated++; @@ -228,9 +274,11 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstV4l2Object *obj = pool->obj; - const GstCaps *caps; - guint size, min_buffers, max_buffers; - guint prefix, align; + GstCaps *caps; + guint size, min_buffers, max_buffers, num_buffers, copy_threshold; + GstAllocator *allocator; + GstAllocationParams params; + struct v4l2_requestbuffers breq; GST_DEBUG_OBJECT (pool, "set config"); @@ -238,10 +286,12 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); - if (!pool->add_videometa) { + if (!pool->add_videometa && + GST_VIDEO_INFO_FORMAT (&obj->info) != GST_VIDEO_FORMAT_ENCODED) { gint stride; - /* we don't have video metadata, see if the strides are compatible */ + /* we don't have video metadata, and we are not dealing with raw video, + * see if the strides are compatible */ stride = GST_VIDEO_INFO_PLANE_STRIDE (&obj->info, 0); GST_DEBUG_OBJECT (pool, "no videometadata, checking strides %d and %u", @@ -252,20 +302,94 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) } /* parse the config and keep around */ - if (!gst_buffer_pool_config_get (config, &caps, &size, &min_buffers, - &max_buffers, &prefix, &align)) + if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, + &max_buffers)) + goto wrong_config; + + if (!gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms)) goto wrong_config; GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config); + switch (obj->mode) { + case GST_V4L2_IO_RW: + /* we preallocate 1 buffer, this value also instructs the latency + * calculation to have 1 frame latency max */ + num_buffers = 1; + copy_threshold = 0; + break; + case GST_V4L2_IO_DMABUF: + case GST_V4L2_IO_MMAP: + { + /* request a reasonable number of buffers when no max specified. We will + * copy when we run out of buffers */ + if (max_buffers == 0) + num_buffers = 4; + else + num_buffers = max_buffers; + + /* first, lets request buffers, and see how many we can get: */ + GST_DEBUG_OBJECT (pool, "starting, requesting %d MMAP buffers", + num_buffers); + + memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); + breq.type = obj->type; + breq.count = num_buffers; + breq.memory = V4L2_MEMORY_MMAP; + + if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0) + goto reqbufs_failed; + + GST_LOG_OBJECT (pool, " count: %u", breq.count); + GST_LOG_OBJECT (pool, " type: %d", breq.type); + GST_LOG_OBJECT (pool, " memory: %d", breq.memory); + + if (breq.count < GST_V4L2_MIN_BUFFERS) + goto no_buffers; + + if (num_buffers != breq.count) { + GST_WARNING_OBJECT (pool, "using %u buffers instead", breq.count); + num_buffers = breq.count; + } + /* update min buffers with the amount of buffers we just reserved. We need + * to configure this value in the bufferpool so that the default start + * implementation calls our allocate function */ + min_buffers = breq.count; + + if (max_buffers == 0 || num_buffers < max_buffers) { + /* if we are asked to provide more buffers than we have allocated, start + * copying buffers when we only have 2 buffers left in the pool */ + copy_threshold = 2; + } else { + /* we are certain that we have enough buffers so we don't need to + * copy */ + copy_threshold = 0; + } + break; + } + case GST_V4L2_IO_USERPTR: + default: + num_buffers = 0; + copy_threshold = 0; + g_assert_not_reached (); + break; + } + pool->size = size; - pool->max_buffers = MAX (min_buffers, max_buffers); - pool->min_buffers = MIN (pool->max_buffers, min_buffers); - pool->prefix = prefix; - pool->align = align; + pool->num_buffers = num_buffers; + pool->copy_threshold = copy_threshold; - gst_buffer_pool_config_set (config, caps, size, min_buffers, - max_buffers, prefix, align); + if (obj->mode == GST_V4L2_IO_DMABUF) + allocator = gst_dmabuf_allocator_obtain (); + + if (pool->allocator) + gst_object_unref (pool->allocator); + if ((pool->allocator = allocator)) + gst_object_ref (allocator); + pool->params = params; + + gst_buffer_pool_config_set_params (config, caps, size, min_buffers, + max_buffers); return GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config); @@ -282,6 +406,19 @@ wrong_config: GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config); return FALSE; } +reqbufs_failed: + { + GST_ERROR_OBJECT (pool, + "error requesting %d buffers: %s", num_buffers, g_strerror (errno)); + return FALSE; + } +no_buffers: + { + GST_ERROR_OBJECT (pool, + "we received %d from device '%s', we want at least %d", + breq.count, obj->videodev, GST_V4L2_MIN_BUFFERS); + return FALSE; + } } static gboolean @@ -294,6 +431,7 @@ start_streaming (GstV4l2BufferPool * pool) break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: + case GST_V4L2_IO_DMABUF: GST_DEBUG_OBJECT (pool, "STREAMON"); if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0) goto start_failed; @@ -321,68 +459,14 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstV4l2Object *obj = pool->obj; - gint n; - struct v4l2_requestbuffers breq; - gint min_buffers, max_buffers; - - min_buffers = pool->min_buffers; - max_buffers = pool->max_buffers; - - switch (obj->mode) { - case GST_V4L2_IO_RW: - { - break; - } - case GST_V4L2_IO_MMAP: - { - /* first, lets request buffers, and see how many we can get: */ - GST_DEBUG_OBJECT (pool, "starting, requesting %d MMAP buffers", - max_buffers); - - if (max_buffers == 0) - max_buffers = 4; - - memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); - breq.type = obj->type; - breq.count = max_buffers; - breq.memory = V4L2_MEMORY_MMAP; - - if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0) - goto reqbufs_failed; - - GST_LOG_OBJECT (pool, " count: %u", breq.count); - GST_LOG_OBJECT (pool, " type: %d", breq.type); - GST_LOG_OBJECT (pool, " memory: %d", breq.memory); - - if (breq.count < GST_V4L2_MIN_BUFFERS) - goto no_buffers; - - if (max_buffers != breq.count) { - GST_WARNING_OBJECT (pool, "using %u buffers instead", breq.count); - max_buffers = breq.count; - } - break; - } - case GST_V4L2_IO_USERPTR: - default: - g_assert_not_reached (); - break; - } pool->obj = obj; - pool->max_buffers = max_buffers; - pool->buffers = g_new0 (GstBuffer *, max_buffers); + pool->buffers = g_new0 (GstBuffer *, pool->num_buffers); pool->num_allocated = 0; /* now, allocate the buffers: */ - for (n = 0; n < min_buffers; n++) { - GstBuffer *buffer; - - if (gst_v4l2_buffer_pool_alloc_buffer (bpool, &buffer, NULL) != GST_FLOW_OK) - goto buffer_new_failed; - - gst_v4l2_buffer_pool_release_buffer (bpool, buffer); - } + if (!GST_BUFFER_POOL_CLASS (parent_class)->start (bpool)) + goto start_failed; /* we can start capturing now, we wait for the playback case until we queued * the first buffer */ @@ -395,24 +479,6 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) return TRUE; /* ERRORS */ -reqbufs_failed: - { - GST_ERROR_OBJECT (pool, - "error requesting %d buffers: %s", max_buffers, g_strerror (errno)); - return FALSE; - } -no_buffers: - { - GST_ERROR_OBJECT (pool, - "we received %d from device '%s', we want at least %d", - breq.count, obj->videodev, GST_V4L2_MIN_BUFFERS); - return FALSE; - } -buffer_new_failed: - { - GST_ERROR_OBJECT (pool, "failed to create a buffer"); - return FALSE; - } start_failed: { GST_ERROR_OBJECT (pool, "failed to start streaming"); @@ -438,6 +504,7 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool) break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: + case GST_V4L2_IO_DMABUF: /* we actually need to sync on all queued buffers but not * on the non-queued ones */ GST_DEBUG_OBJECT (pool, "STREAMOFF"); @@ -455,10 +522,11 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool) ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool); /* then free the remaining buffers */ - for (n = 0; n < pool->num_allocated; n++) { + for (n = 0; n < pool->num_buffers; n++) { if (pool->buffers[n]) gst_v4l2_buffer_pool_free_buffer (bpool, pool->buffers[n]); } + pool->num_queued = 0; g_free (pool->buffers); pool->buffers = NULL; @@ -500,7 +568,7 @@ gst_v4l2_object_poll (GstV4l2Object * v4l2object) stopped: { GST_DEBUG ("stop called"); - return GST_FLOW_WRONG_STATE; + return GST_FLOW_FLUSHING; } select_error: { @@ -517,16 +585,22 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf) gint index; meta = GST_V4L2_META_GET (buf); - g_assert (meta != NULL); + if (meta == NULL) { + GST_LOG_OBJECT (pool, "unref copied buffer %p", buf); + /* no meta, it was a copied buffer that we can unref */ + gst_buffer_unref (buf); + return GST_FLOW_OK; + } index = meta->vbuffer.index; - GST_LOG_OBJECT (pool, "enqueue buffer %p, index:%d, queued:%d", buf, - index, pool->num_queued); + GST_LOG_OBJECT (pool, "enqueue buffer %p, index:%d, queued:%d, flags:%08x", + buf, index, pool->num_queued, meta->vbuffer.flags); if (pool->buffers[index] != NULL) goto already_queued; + GST_LOG_OBJECT (pool, "doing QBUF"); if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &meta->vbuffer) < 0) goto queue_failed; @@ -556,6 +630,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) GstBuffer *outbuf; struct v4l2_buffer vbuffer; GstV4l2Object *obj = pool->obj; + GstClockTime timestamp; if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { /* select works for input devices when data is available. According to the @@ -567,7 +642,12 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) memset (&vbuffer, 0x00, sizeof (vbuffer)); vbuffer.type = obj->type; - vbuffer.memory = V4L2_MEMORY_MMAP; +#if HAVE_DECL_V4L2_MEMORY_DMABUF + if (obj->mode == GST_V4L2_IO_DMABUF) + vbuffer.memory = V4L2_MEMORY_DMABUF; + else +#endif + vbuffer.memory = V4L2_MEMORY_MMAP; GST_LOG_OBJECT (pool, "doing DQBUF"); if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &vbuffer) < 0) @@ -584,22 +664,27 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) pool->buffers[vbuffer.index] = NULL; pool->num_queued--; + timestamp = GST_TIMEVAL_TO_TIME (vbuffer.timestamp); + GST_LOG_OBJECT (pool, - "dequeued buffer %p seq:%d (ix=%d), used %d, flags %08x, pool-queued=%d, buffer=%p", - outbuf, vbuffer.sequence, vbuffer.index, vbuffer.bytesused, vbuffer.flags, - pool->num_queued, outbuf); + "dequeued buffer %p seq:%d (ix=%d), used %d, flags %08x, ts %" + GST_TIME_FORMAT ", pool-queued=%d, buffer=%p", outbuf, vbuffer.sequence, + vbuffer.index, vbuffer.bytesused, vbuffer.flags, + GST_TIME_ARGS (timestamp), pool->num_queued, outbuf); /* set top/bottom field first if v4l2_buffer has the information */ - if (vbuffer.field == V4L2_FIELD_INTERLACED_TB) + if (vbuffer.field == V4L2_FIELD_INTERLACED_TB) { GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); - if (vbuffer.field == V4L2_FIELD_INTERLACED_BT) + } + if (vbuffer.field == V4L2_FIELD_INTERLACED_BT) { GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); + } /* this can change at every frame, esp. with jpeg */ if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) gst_buffer_resize (outbuf, 0, vbuffer.bytesused); - else - gst_buffer_resize (outbuf, 0, vbuffer.length); + + GST_BUFFER_TIMESTAMP (outbuf) = timestamp; *buffer = outbuf; @@ -669,7 +754,7 @@ no_buffer: static GstFlowReturn gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, - GstBufferPoolParams * params) + GstBufferPoolAcquireParams * params) { GstFlowReturn ret; GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); @@ -689,16 +774,32 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer, params); break; - + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: /* just dequeue a buffer, we basically use the queue of v4l2 as the * storage for our buffers. This function does poll first so we can * interrupt it fine. */ ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto done; + + /* start copying buffers when we are running low on buffers */ + if (pool->num_queued < pool->copy_threshold) { + GstBuffer *copy; + + /* copy the memory */ + copy = gst_buffer_copy (*buffer); + GST_LOG_OBJECT (pool, "copy buffer %p->%p", *buffer, copy); + + /* and requeue so that we can continue capturing */ + ret = gst_v4l2_buffer_pool_qbuf (pool, *buffer); + *buffer = copy; + } break; case GST_V4L2_IO_USERPTR: default: + ret = GST_FLOW_ERROR; g_assert_not_reached (); break; } @@ -721,22 +822,25 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, case GST_V4L2_IO_USERPTR: default: + ret = GST_FLOW_ERROR; g_assert_not_reached (); break; } break; default: + ret = GST_FLOW_ERROR; g_assert_not_reached (); break; } +done: return ret; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (pool, "We are flushing"); - return GST_FLOW_WRONG_STATE; + return GST_FLOW_FLUSHING; } } @@ -758,6 +862,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer); break; + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: /* queue back in the device */ gst_v4l2_buffer_pool_qbuf (pool, buffer); @@ -780,12 +885,20 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) case GST_V4L2_IO_MMAP: { GstV4l2Meta *meta; + guint index; meta = GST_V4L2_META_GET (buffer); g_assert (meta != NULL); - if (pool->buffers[meta->vbuffer.index] == NULL) { - GST_LOG_OBJECT (pool, "buffer not queued, putting on free list"); + index = meta->vbuffer.index; + + if (pool->buffers[index] == NULL) { + GST_LOG_OBJECT (pool, "buffer %u not queued, putting on free list", + index); + + /* reset to the full length, in case it was changed */ + gst_buffer_resize (buffer, 0, meta->vbuffer.length); + /* playback, put the buffer back in the queue to refill later. */ GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer); @@ -793,7 +906,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) /* the buffer is queued in the device but maybe not played yet. We just * leave it there and not make it available for future calls to acquire * for now. The buffer will be dequeued and reused later. */ - GST_LOG_OBJECT (pool, "buffer is queued"); + GST_LOG_OBJECT (pool, "buffer %u is queued", index); } break; } @@ -818,7 +931,8 @@ gst_v4l2_buffer_pool_finalize (GObject * object) if (pool->video_fd >= 0) v4l2_close (pool->video_fd); - + if (pool->allocator) + gst_object_unref (pool->allocator); g_free (pool->buffers); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -858,6 +972,7 @@ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; + GstStructure *s; gint fd; fd = v4l2_dup (obj->video_fd); @@ -868,8 +983,9 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) pool->video_fd = fd; pool->obj = obj; - gst_buffer_pool_config_set (GST_BUFFER_POOL_CAST (pool)->config, caps, - obj->sizeimage, 2, 0, 0, 0); + s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0); + gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s); return GST_BUFFER_POOL (pool); @@ -887,20 +1003,20 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf) GstFlowReturn res; GstV4l2Object *obj = pool->obj; gint amount; - gpointer data; + GstMapInfo map; gint toread; toread = obj->sizeimage; GST_LOG_OBJECT (pool, "reading %d bytes into buffer %p", toread, buf); - data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE); + gst_buffer_map (buf, &map, GST_MAP_WRITE); do { if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK) goto poll_error; - amount = v4l2_read (obj->video_fd, data, toread); + amount = v4l2_read (obj->video_fd, map.data, toread); if (amount == toread) { break; @@ -916,7 +1032,8 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf) } while (TRUE); GST_LOG_OBJECT (pool, "read %d bytes", amount); - gst_buffer_unmap (buf, data, amount); + gst_buffer_unmap (buf, &map); + gst_buffer_resize (buf, 0, amount); return GST_FLOW_OK; @@ -936,7 +1053,8 @@ read_error: } cleanup: { - gst_buffer_unmap (buf, data, 0); + gst_buffer_unmap (buf, &map); + gst_buffer_resize (buf, 0, 0); return res; } } @@ -1005,7 +1123,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf) /* FIXME, do write() */ GST_WARNING_OBJECT (pool, "implement write()"); break; - + case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: { GstBuffer *to_queue;