3 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4 * 2006 Edgard Lima <edgard.lima@indt.org.br>
5 * 2009 Texas Instruments, Inc - http://www.ti.com/
7 * gstv4l2bufferpool.c V4L2 buffer pool class
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
33 #include "gst/video/video.h"
34 #include "gst/video/gstmetavideo.h"
36 #include <gstv4l2bufferpool.h>
38 #include "gstv4l2src.h"
39 #include "gstv4l2sink.h"
40 #include "v4l2_calls.h"
41 #include "gst/gst-i18n-plugin.h"
43 /* videodev2.h is not versioned and we can't easily check for the presence
44 * of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
45 * was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */
46 #ifndef V4L2_CAP_VIDEO_OUTPUT_OVERLAY
47 #define V4L2_FIELD_INTERLACED_TB 8
48 #define V4L2_FIELD_INTERLACED_BT 9
52 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
53 #define GST_CAT_DEFAULT v4l2_debug
59 gst_meta_v4l2_get_info (void)
61 static const GstMetaInfo *meta_info = NULL;
63 if (meta_info == NULL) {
65 gst_meta_register ("GstMetaV4l2", "GstMetaV4l2",
66 sizeof (GstMetaV4l2), (GstMetaInitFunction) NULL,
67 (GstMetaFreeFunction) NULL, (GstMetaCopyFunction) NULL,
68 (GstMetaTransformFunction) NULL);
76 #define gst_v4l2_buffer_pool_parent_class parent_class
77 G_DEFINE_TYPE (GstV4l2BufferPool, gst_v4l2_buffer_pool, GST_TYPE_BUFFER_POOL);
79 static void gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool,
83 gst_v4l2_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
85 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
90 meta = GST_META_V4L2_GET (buffer);
91 g_assert (meta != NULL);
95 index = meta->vbuffer.index;
96 GST_LOG_OBJECT (pool, "finalizing buffer %p %d", buffer, index);
97 pool->buffers[index] = NULL;
100 "buffer %p (data %p, len %u) freed, unmapping",
101 buffer, meta->mem, meta->vbuffer.length);
102 v4l2_munmap (meta->mem, meta->vbuffer.length);
104 gst_buffer_unref (buffer);
108 gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
109 GstBufferPoolParams * params)
111 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
121 newbuf = gst_buffer_new ();
122 meta = GST_META_V4L2_ADD (newbuf);
126 GST_LOG_OBJECT (pool, "creating buffer %u, %p", index, newbuf, pool);
128 meta->vbuffer.index = index;
129 meta->vbuffer.type = obj->type;
130 meta->vbuffer.memory = V4L2_MEMORY_MMAP;
132 if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &meta->vbuffer) < 0)
133 goto querybuf_failed;
135 GST_LOG_OBJECT (pool, " index: %u", meta->vbuffer.index);
136 GST_LOG_OBJECT (pool, " type: %d", meta->vbuffer.type);
137 GST_LOG_OBJECT (pool, " bytesused: %u", meta->vbuffer.bytesused);
138 GST_LOG_OBJECT (pool, " flags: %08x", meta->vbuffer.flags);
139 GST_LOG_OBJECT (pool, " field: %d", meta->vbuffer.field);
140 GST_LOG_OBJECT (pool, " memory: %d", meta->vbuffer.memory);
141 if (meta->vbuffer.memory == V4L2_MEMORY_MMAP)
142 GST_LOG_OBJECT (pool, " MMAP offset: %u", meta->vbuffer.m.offset);
143 GST_LOG_OBJECT (pool, " length: %u", meta->vbuffer.length);
144 GST_LOG_OBJECT (pool, " input: %u", meta->vbuffer.input);
146 meta->mem = v4l2_mmap (0, meta->vbuffer.length,
147 PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd,
148 meta->vbuffer.m.offset);
149 if (meta->mem == MAP_FAILED)
152 gst_buffer_take_memory (newbuf, -1,
153 gst_memory_new_wrapped (0,
154 meta->mem, NULL, meta->vbuffer.length, 0, meta->vbuffer.length));
156 /* add metadata to raw video buffers */
158 gsize offset[GST_VIDEO_MAX_PLANES];
159 gint stride[GST_VIDEO_MAX_PLANES];
162 stride[0] = obj->bytesperline;
164 GST_DEBUG_OBJECT (pool, "adding video meta");
165 gst_buffer_add_meta_video_full (newbuf, info->flags,
166 GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
167 GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
180 gint errnosave = errno;
182 GST_WARNING ("Failed QUERYBUF: %s", g_strerror (errnosave));
183 gst_buffer_unref (newbuf);
185 return GST_FLOW_ERROR;
189 gint errnosave = errno;
191 GST_WARNING ("Failed to mmap: %s", g_strerror (errnosave));
192 gst_buffer_unref (newbuf);
194 return GST_FLOW_ERROR;
199 gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
201 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
203 guint size, min_buffers, max_buffers;
206 GST_DEBUG_OBJECT (pool, "set config");
208 /* parse the config and keep around */
209 if (!gst_buffer_pool_config_get (config, &caps, &size, &min_buffers,
210 &max_buffers, &prefix, &align))
213 GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config);
215 pool->min_buffers = min_buffers;
216 pool->max_buffers = max_buffers;
222 GST_WARNING_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config);
228 gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
230 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
231 GstV4l2Object *obj = pool->obj;
233 struct v4l2_requestbuffers breq;
236 num_buffers = pool->max_buffers;
238 /* first, lets request buffers, and see how many we can get: */
239 GST_DEBUG_OBJECT (pool, "starting, requesting %d MMAP buffers", num_buffers);
241 memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
242 breq.type = obj->type;
243 breq.count = num_buffers;
244 breq.memory = V4L2_MEMORY_MMAP;
246 if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0)
249 GST_LOG_OBJECT (pool, " count: %u", breq.count);
250 GST_LOG_OBJECT (pool, " type: %d", breq.type);
251 GST_LOG_OBJECT (pool, " memory: %d", breq.memory);
253 if (breq.count < GST_V4L2_MIN_BUFFERS)
256 if (num_buffers != breq.count) {
257 GST_WARNING_OBJECT (pool, "using %u buffers instead", breq.count);
258 num_buffers = breq.count;
262 pool->requeuebuf = (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? TRUE : FALSE);
263 pool->num_buffers = num_buffers;
264 pool->buffers = g_new0 (GstBuffer *, num_buffers);
267 /* now, map the buffers: */
268 for (n = 0; n < num_buffers; n++) {
271 if (gst_v4l2_buffer_pool_alloc_buffer (bpool, &buffer, NULL) != GST_FLOW_OK)
272 goto buffer_new_failed;
274 gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
281 GST_ERROR_OBJECT (pool,
282 "error requesting %d buffers: %s", num_buffers, g_strerror (errno));
287 GST_ERROR_OBJECT (pool,
288 "we received %d from device '%s', we want at least %d",
289 breq.count, obj->videodev, GST_V4L2_MIN_BUFFERS);
294 GST_ERROR_OBJECT (pool, "failed to create a buffer");
300 gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
303 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
306 GST_DEBUG_OBJECT (pool, "stopping pool");
308 /* first free the buffers in the queue */
309 ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
311 /* then free the remaining buffers */
312 for (n = 0; n < pool->num_buffers; n++) {
313 if (pool->buffers[n])
314 gst_v4l2_buffer_pool_free_buffer (bpool, pool->buffers[n]);
320 gst_v4l2_buffer_pool_dqbuf (GstBufferPool * bpool, GstBuffer ** buffer)
322 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
324 struct v4l2_buffer vbuffer;
325 GstV4l2Object *obj = pool->obj;
327 memset (&vbuffer, 0x00, sizeof (vbuffer));
328 vbuffer.type = obj->type;
329 vbuffer.memory = V4L2_MEMORY_MMAP;
331 if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &vbuffer) < 0)
334 /* get our GstBuffer with that index from the pool, if the buffer was
335 * outstanding we have a serious problem.
337 outbuf = pool->buffers[vbuffer.index];
341 /* mark the buffer outstanding */
342 pool->buffers[vbuffer.index] = NULL;
344 GST_LOG_OBJECT (pool,
345 "dequeued frame %d (ix=%d), used %d, flags %08x, pool-queued=%d, buffer=%p",
346 vbuffer.sequence, vbuffer.index, vbuffer.bytesused, vbuffer.flags,
347 pool->num_queued, outbuf);
350 GST_DEBUG_OBJECT (pool, "num_queued: %d", pool->num_queued);
352 /* set top/bottom field first if v4l2_buffer has the information */
353 if (vbuffer.field == V4L2_FIELD_INTERLACED_TB)
354 GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_TFF);
355 if (vbuffer.field == V4L2_FIELD_INTERLACED_BT)
356 GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_TFF);
358 /* this can change at every frame, esp. with jpeg */
359 if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
360 gst_buffer_resize (outbuf, 0, vbuffer.bytesused);
362 gst_buffer_resize (outbuf, 0, vbuffer.length);
371 GST_WARNING_OBJECT (pool,
372 "problem dequeuing frame %d (ix=%d), pool-ct=%d, buf.flags=%d",
373 vbuffer.sequence, vbuffer.index,
374 GST_MINI_OBJECT_REFCOUNT (pool), vbuffer.flags);
378 GST_WARNING_OBJECT (pool,
379 "Non-blocking I/O has been selected using O_NONBLOCK and"
380 " no buffer was in the outgoing queue. device %s", obj->videodev);
383 GST_ERROR_OBJECT (pool,
384 "The buffer type is not supported, or the index is out of bounds, "
385 "or no buffers have been allocated yet, or the userptr "
386 "or length are invalid. device %s", obj->videodev);
389 GST_ERROR_OBJECT (pool,
390 "insufficient memory to enqueue a user pointer buffer");
393 GST_INFO_OBJECT (pool,
394 "VIDIOC_DQBUF failed due to an internal error."
395 " Can also indicate temporary problems like signal loss."
396 " Note the driver might dequeue an (empty) buffer despite"
397 " returning an error, or even stop capturing."
398 " device %s", obj->videodev);
399 /* have we de-queued a buffer ? */
400 if (!(vbuffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
401 GST_DEBUG_OBJECT (pool, "reenqueing buffer");
402 /* FIXME ... should we do something here? */
406 GST_WARNING_OBJECT (pool,
407 "could not sync on a buffer on device %s", obj->videodev);
410 GST_WARNING_OBJECT (pool,
411 "Grabbing frame got interrupted on %s unexpectedly. %d: %s.",
412 obj->videodev, errno, g_strerror (errno));
415 return GST_FLOW_ERROR;
419 GST_ERROR_OBJECT (pool, "No free buffers found in the pool at index %d.",
421 return GST_FLOW_ERROR;
426 gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
427 GstBufferPoolParams * params)
429 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
432 GST_DEBUG_OBJECT (pool, "acquire");
434 if (GST_BUFFER_POOL_IS_FLUSHING (bpool))
437 if (pool->requeuebuf)
438 ret = gst_v4l2_buffer_pool_dqbuf (bpool, buffer);
440 if (pool->num_queued == pool->num_buffers) {
441 ret = gst_v4l2_buffer_pool_dqbuf (bpool, buffer);
444 GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer,
453 GST_DEBUG_OBJECT (bpool, "We are flushing");
454 return GST_FLOW_WRONG_STATE;
459 gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
461 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
463 GST_DEBUG_OBJECT (pool, "release");
465 if (pool->requeuebuf)
466 gst_v4l2_buffer_pool_qbuf (bpool, buffer);
468 GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
472 gst_v4l2_buffer_pool_finalize (GObject * object)
474 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (object);
476 if (pool->video_fd >= 0)
477 v4l2_close (pool->video_fd);
480 g_free (pool->buffers);
481 pool->buffers = NULL;
484 G_OBJECT_CLASS (parent_class)->finalize (object);
488 gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
493 gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
495 GObjectClass *object_class = G_OBJECT_CLASS (klass);
496 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass);
498 object_class->finalize = gst_v4l2_buffer_pool_finalize;
500 bufferpool_class->start = gst_v4l2_buffer_pool_start;
501 bufferpool_class->stop = gst_v4l2_buffer_pool_stop;
502 bufferpool_class->set_config = gst_v4l2_buffer_pool_set_config;
503 bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
504 bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
505 bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
506 bufferpool_class->free_buffer = gst_v4l2_buffer_pool_free_buffer;
510 * gst_v4l2_buffer_pool_new:
511 * @obj: the v4l2 object owning the pool
512 * @num_buffers: the requested number of buffers in the pool
513 * @requeuebuf: if %TRUE, and if the pool is still in the running state, a
514 * buffer with no remaining references is immediately passed back to v4l2
515 * (VIDIOC_QBUF), otherwise it is returned to the pool of available buffers
516 * (which can be accessed via gst_v4l2_buffer_pool_get().
518 * Construct a new buffer pool.
520 * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources
523 gst_v4l2_buffer_pool_new (GstV4l2Object * obj)
525 GstV4l2BufferPool *pool;
528 fd = v4l2_dup (obj->video_fd);
532 pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL);
536 return GST_BUFFER_POOL_CAST (pool);
541 GST_DEBUG ("failed to dup fd %d (%s)", errno, g_strerror (errno));
547 * gst_v4l2_buffer_pool_qbuf:
549 * @buf: the buffer to queue
551 * Queue a buffer to the driver
553 * Returns: %TRUE for success
556 gst_v4l2_buffer_pool_qbuf (GstBufferPool * bpool, GstBuffer * buf)
558 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
562 meta = GST_META_V4L2_GET (buf);
563 g_assert (meta != NULL);
565 index = meta->vbuffer.index;
567 GST_LOG_OBJECT (pool, "enqueue pool buffer %d", index);
569 if (pool->buffers[index] != NULL)
572 if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &meta->vbuffer) < 0)
575 pool->buffers[index] = buf;
578 GST_DEBUG_OBJECT (pool, "num_queued: %d", pool->num_queued);
585 GST_WARNING_OBJECT (pool, "the buffer was already queued");
590 GST_WARNING_OBJECT (pool, "could not queue a buffer");
596 * gst_v4l2_buffer_pool_available_buffers:
599 * Check the number of buffers available to the driver, ie. buffers that
600 * have been QBUF'd but not yet DQBUF'd.
602 * Returns: the number of buffers available.
605 gst_v4l2_buffer_pool_available_buffers (GstBufferPool * bpool)
607 GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
609 return pool->num_queued;