/** * gst_buffer_pool_release_buffer: * @pool: a #GstBufferPool * @buffer: (transfer full): a #GstBuffer * * Release @buffer to @pool. @buffer should have previously been allocated from * @pool with gst_buffer_pool_acquire_buffer(). * * This function is usually called automatically when the last ref on @buffer * disappears. */ void gst_buffer_pool_release_buffer (GstBufferPool * pool, GstBuffer * buffer) { GstBufferPoolClass *pclass; g_return_if_fail (GST_IS_BUFFER_POOL (pool)); g_return_if_fail (buffer != NULL); /* check that the buffer is ours, all buffers returned to the pool have the * pool member set to NULL and the pool refcount decreased */ if (!g_atomic_pointer_compare_and_exchange (&buffer->pool, pool, NULL)) return; pclass = GST_BUFFER_POOL_GET_CLASS (pool); /* reset the buffer when needed */ if (G_LIKELY (pclass->reset_buffer)) pclass->reset_buffer (pool, buffer); if (G_LIKELY (pclass->release_buffer)) pclass->release_buffer (pool, buffer); dec_outstanding (pool); /* decrease the refcount that the buffer had to us */ gst_object_unref (pool); }
/** * gst_buffer_pool_acquire_buffer: * @pool: a #GstBufferPool * @buffer: (out): a location for a #GstBuffer * @params: (transfer none) (allow-none) parameters. * * Acquire a buffer from @pool. @buffer should point to a memory location that * can hold a pointer to the new buffer. * * @params can be NULL or contain optional parameters to influence the allocation. * * Returns: a #GstFlowReturn such as GST_FLOW_FLUSHING when the pool is * inactive. */ GstFlowReturn gst_buffer_pool_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params) { GstBufferPoolClass *pclass; GstFlowReturn result; g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), GST_FLOW_ERROR); g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); pclass = GST_BUFFER_POOL_GET_CLASS (pool); /* assume we'll have one more outstanding buffer we need to do that so * that concurrent set_active doesn't clear the buffers */ g_atomic_int_inc (&pool->priv->outstanding); if (G_LIKELY (pclass->acquire_buffer)) result = pclass->acquire_buffer (pool, buffer, params); else result = GST_FLOW_NOT_SUPPORTED; if (G_LIKELY (result == GST_FLOW_OK)) { /* all buffers from the pool point to the pool and have the refcount of the * pool incremented */ (*buffer)->pool = gst_object_ref (pool); } else { dec_outstanding (pool); } return result; }
/* the default implementation for preallocating the buffers * in the pool */ static gboolean default_start (GstBufferPool * pool) { guint i; GstBufferPoolPrivate *priv = pool->priv; GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); /* we need to prealloc buffers */ for (i = 0; i < priv->min_buffers; i++) { GstBuffer *buffer; if (do_alloc_buffer (pool, &buffer, NULL) != GST_FLOW_OK) goto alloc_failed; /* release to the queue, we call the vmethod directly, we don't need to do * the other refcount handling right now. */ if (G_LIKELY (pclass->release_buffer)) pclass->release_buffer (pool, buffer); } return TRUE; /* ERRORS */ alloc_failed: { GST_WARNING_OBJECT (pool, "failed to allocate buffer"); return FALSE; } }
/* must be called with the lock */ static void do_set_flushing (GstBufferPool * pool, gboolean flushing) { GstBufferPoolPrivate *priv = pool->priv; GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); if (GST_BUFFER_POOL_IS_FLUSHING (pool) == flushing) return; if (flushing) { g_atomic_int_set (&pool->flushing, 1); gst_poll_write_control (priv->poll); if (pclass->flush_start) pclass->flush_start (pool); } else { if (pclass->flush_stop) pclass->flush_stop (pool); gst_poll_read_control (priv->poll); g_atomic_int_set (&pool->flushing, 0); } }
/** * gst_buffer_pool_set_config: * @pool: a #GstBufferPool * @config: (transfer full): a #GstStructure * * Set the configuration of the pool. The pool must be inactive and all buffers * allocated form this pool must be returned or else this function will do * nothing and return FALSE. * * @config is a #GstStructure that contains the configuration parameters for * the pool. A default and mandatory set of parameters can be configured with * gst_buffer_pool_config_set_params(), gst_buffer_pool_config_set_allocator() * and gst_buffer_pool_config_add_option(). * * If the parameters in @config can not be set exactly, this function returns * FALSE and will try to update as much state as possible. The new state can * then be retrieved and refined with gst_buffer_pool_get_config(). * * This function takes ownership of @config. * * Returns: TRUE when the configuration could be set. */ gboolean gst_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) { gboolean result; GstBufferPoolClass *pclass; GstBufferPoolPrivate *priv; g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE); g_return_val_if_fail (config != NULL, FALSE); priv = pool->priv; GST_BUFFER_POOL_LOCK (pool); /* can't change the settings when active */ if (priv->active) goto was_active; /* we can't change when outstanding buffers */ if (g_atomic_int_get (&priv->outstanding) != 0) goto have_outstanding; pclass = GST_BUFFER_POOL_GET_CLASS (pool); /* set the new config */ if (G_LIKELY (pclass->set_config)) result = pclass->set_config (pool, config); else result = FALSE; if (result) { if (priv->config) gst_structure_free (priv->config); priv->config = config; /* now we are configured */ priv->configured = TRUE; } else { gst_structure_free (config); } GST_BUFFER_POOL_UNLOCK (pool); return result; /* ERRORS */ was_active: { gst_structure_free (config); GST_WARNING_OBJECT (pool, "can't change config, we are active"); GST_BUFFER_POOL_UNLOCK (pool); return FALSE; } have_outstanding: { gst_structure_free (config); GST_WARNING_OBJECT (pool, "can't change config, have outstanding buffers"); GST_BUFFER_POOL_UNLOCK (pool); return FALSE; } }
static GstFlowReturn do_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params) { GstBufferPoolPrivate *priv = pool->priv; GstFlowReturn result; gint cur_buffers, max_buffers; GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); if (G_UNLIKELY (!pclass->alloc_buffer)) goto no_function; max_buffers = priv->max_buffers; /* increment the allocation counter */ cur_buffers = g_atomic_int_add (&priv->cur_buffers, 1); if (max_buffers && cur_buffers >= max_buffers) goto max_reached; result = pclass->alloc_buffer (pool, buffer, params); if (G_UNLIKELY (result != GST_FLOW_OK)) goto alloc_failed; /* lock all metadata and mark as pooled, we want this to remain on * the buffer and we want to remove any other metadata that gets added * later */ gst_buffer_foreach_meta (*buffer, mark_meta_pooled, pool); /* un-tag memory, this is how we expect the buffer when it is * released again */ GST_BUFFER_FLAG_UNSET (*buffer, GST_BUFFER_FLAG_TAG_MEMORY); GST_LOG_OBJECT (pool, "allocated buffer %d/%d, %p", cur_buffers, max_buffers, *buffer); return result; /* ERRORS */ no_function: { GST_ERROR_OBJECT (pool, "no alloc function"); return GST_FLOW_NOT_SUPPORTED; } max_reached: { GST_DEBUG_OBJECT (pool, "max buffers reached"); g_atomic_int_add (&priv->cur_buffers, -1); return GST_FLOW_EOS; } alloc_failed: { GST_WARNING_OBJECT (pool, "alloc function failed"); g_atomic_int_add (&priv->cur_buffers, -1); return result; } }
static GstFlowReturn do_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params) { GstBufferPoolPrivate *priv = pool->priv; GstFlowReturn result; gint cur_buffers, max_buffers; GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); if (G_UNLIKELY (!pclass->alloc_buffer)) goto no_function; max_buffers = priv->max_buffers; /* increment the allocation counter */ cur_buffers = g_atomic_int_add (&priv->cur_buffers, 1); if (max_buffers && cur_buffers >= max_buffers) goto max_reached; result = pclass->alloc_buffer (pool, buffer, params); if (G_UNLIKELY (result != GST_FLOW_OK)) goto alloc_failed; gst_buffer_foreach_meta (*buffer, mark_meta_pooled, pool); GST_LOG_OBJECT (pool, "allocated buffer %d/%d, %p", cur_buffers, max_buffers, buffer); return result; /* ERRORS */ no_function: { GST_ERROR_OBJECT (pool, "no alloc function"); return GST_FLOW_NOT_SUPPORTED; } max_reached: { GST_DEBUG_OBJECT (pool, "max buffers reached"); g_atomic_int_add (&priv->cur_buffers, -1); return GST_FLOW_EOS; } alloc_failed: { GST_WARNING_OBJECT (pool, "alloc function failed"); g_atomic_int_add (&priv->cur_buffers, -1); return result; } }
static void do_free_buffer (GstBufferPool * pool, GstBuffer * buffer) { GstBufferPoolPrivate *priv; GstBufferPoolClass *pclass; priv = pool->priv; pclass = GST_BUFFER_POOL_GET_CLASS (pool); g_atomic_int_add (&priv->cur_buffers, -1); GST_LOG_OBJECT (pool, "freeing buffer %p (%u left)", buffer, priv->cur_buffers); if (G_LIKELY (pclass->free_buffer)) pclass->free_buffer (pool, buffer); }
/* must be called with the lock */ static gboolean do_stop (GstBufferPool * pool) { GstBufferPoolPrivate *priv = pool->priv; if (priv->started) { GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); GST_LOG_OBJECT (pool, "stopping"); if (G_LIKELY (pclass->stop)) { if (!pclass->stop (pool)) return FALSE; } priv->started = FALSE; } return TRUE; }
/* must be called with the lock */ static gboolean default_stop (GstBufferPool * pool) { GstBufferPoolPrivate *priv = pool->priv; GstBuffer *buffer; GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); /* clear the pool */ while ((buffer = gst_atomic_queue_pop (priv->queue))) { GST_LOG_OBJECT (pool, "freeing %p", buffer); gst_poll_read_control (priv->poll); if (G_LIKELY (pclass->free_buffer)) pclass->free_buffer (pool, buffer); } priv->cur_buffers = 0; return TRUE; }
/* must be called with the lock */ static gboolean do_start (GstBufferPool * pool) { GstBufferPoolPrivate *priv = pool->priv; if (!priv->started) { GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); GST_LOG_OBJECT (pool, "starting"); /* start the pool, subclasses should allocate buffers and put them * in the queue */ if (G_LIKELY (pclass->start)) { if (!pclass->start (pool)) return FALSE; } priv->started = TRUE; } return TRUE; }
/* must be called with the lock */ static void do_set_flushing (GstBufferPool * pool, gboolean flushing) { GstBufferPoolPrivate *priv = pool->priv; GstBufferPoolClass *pclass; pclass = GST_BUFFER_POOL_GET_CLASS (pool); if (GST_BUFFER_POOL_IS_FLUSHING (pool) == flushing) return; if (flushing) { g_atomic_int_set (&pool->flushing, 1); /* Write the flush token to wake up any waiters */ gst_poll_write_control (priv->poll); if (pclass->flush_start) pclass->flush_start (pool); } else { if (pclass->flush_stop) pclass->flush_stop (pool); while (!gst_poll_read_control (priv->poll)) { if (errno == EWOULDBLOCK) { /* This should not really happen unless flushing and unflushing * happens on different threads. Let's wait a bit to get back flush * token from the thread that was setting it to flushing */ g_thread_yield (); continue; } else { /* Critical error but GstPoll already complained */ break; } } g_atomic_int_set (&pool->flushing, 0); } }
static gboolean gst_v4l2_buffer_pool_stop (GstBufferPool * bpool) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class); gboolean ret; gint i; GST_DEBUG_OBJECT (pool, "stopping pool"); if (pool->group_released_handler > 0) { g_signal_handler_disconnect (pool->vallocator, pool->group_released_handler); pool->group_released_handler = 0; } if (pool->other_pool) { gst_object_unref (pool->other_pool); pool->other_pool = NULL; } if (!gst_v4l2_buffer_pool_streamoff (pool)) goto streamoff_failed; if (pool->vallocator) gst_v4l2_allocator_flush (pool->vallocator); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (pool->buffers[i]) { GstBuffer *buffer = pool->buffers[i]; pool->buffers[i] = NULL; if (V4L2_TYPE_IS_OUTPUT (pool->obj->type)) gst_buffer_unref (buffer); else pclass->release_buffer (bpool, buffer); g_atomic_int_add (&pool->num_queued, -1); } } ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool); if (ret && pool->vallocator) { GstV4l2Return vret; vret = gst_v4l2_allocator_stop (pool->vallocator); if (vret == GST_V4L2_BUSY) GST_WARNING_OBJECT (pool, "some buffers are still outstanding"); ret = (vret == GST_V4L2_OK); } return ret; /* ERRORS */ streamoff_failed: GST_ERROR_OBJECT (pool, "device refused to stop streaming"); return FALSE; }
/** * gst_buffer_pool_set_config: * @pool: a #GstBufferPool * @config: (transfer full): a #GstStructure * * Set the configuration of the pool. If the pool is already configured, and * the configuration haven't change, this function will return %TRUE. If the * pool is active, this method will return %FALSE and active configuration * will remain. Buffers allocated form this pool must be returned or else this * function will do nothing and return %FALSE. * * @config is a #GstStructure that contains the configuration parameters for * the pool. A default and mandatory set of parameters can be configured with * gst_buffer_pool_config_set_params(), gst_buffer_pool_config_set_allocator() * and gst_buffer_pool_config_add_option(). * * If the parameters in @config can not be set exactly, this function returns * %FALSE and will try to update as much state as possible. The new state can * then be retrieved and refined with gst_buffer_pool_get_config(). * * This function takes ownership of @config. * * Returns: %TRUE when the configuration could be set. */ gboolean gst_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) { gboolean result; GstBufferPoolClass *pclass; GstBufferPoolPrivate *priv; g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE); g_return_val_if_fail (config != NULL, FALSE); priv = pool->priv; GST_BUFFER_POOL_LOCK (pool); /* nothing to do if config is unchanged */ if (priv->configured && gst_structure_is_equal (config, priv->config)) goto config_unchanged; /* can't change the settings when active */ if (priv->active) goto was_active; /* we can't change when outstanding buffers */ if (g_atomic_int_get (&priv->outstanding) != 0) goto have_outstanding; pclass = GST_BUFFER_POOL_GET_CLASS (pool); /* set the new config */ if (G_LIKELY (pclass->set_config)) result = pclass->set_config (pool, config); else result = FALSE; /* save the config regardless of the result so user can read back the * modified config and evaluate if the changes are acceptable */ if (priv->config) gst_structure_free (priv->config); priv->config = config; if (result) { /* now we are configured */ priv->configured = TRUE; } GST_BUFFER_POOL_UNLOCK (pool); return result; config_unchanged: { gst_structure_free (config); GST_BUFFER_POOL_UNLOCK (pool); return TRUE; } /* ERRORS */ was_active: { gst_structure_free (config); GST_INFO_OBJECT (pool, "can't change config, we are active"); GST_BUFFER_POOL_UNLOCK (pool); return FALSE; } have_outstanding: { gst_structure_free (config); GST_WARNING_OBJECT (pool, "can't change config, have outstanding buffers"); GST_BUFFER_POOL_UNLOCK (pool); return FALSE; } }
static gboolean gst_v4l2_buffer_pool_start (GstBufferPool * bpool) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class); GstV4l2Object *obj = pool->obj; GstStructure *config; GstCaps *caps; guint size, min_buffers, max_buffers; guint max_latency, min_latency, copy_threshold = 0; gboolean can_allocate = FALSE; GST_DEBUG_OBJECT (pool, "activating pool"); config = gst_buffer_pool_get_config (bpool); if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers)) goto wrong_config; min_latency = MAX (GST_V4L2_MIN_BUFFERS, obj->min_buffers); switch (obj->mode) { case GST_V4L2_IO_RW: can_allocate = TRUE; break; case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: { guint count; can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP); /* first, lets request buffers, and see how many we can get: */ GST_DEBUG_OBJECT (pool, "requesting %d MMAP buffers", min_buffers); count = gst_v4l2_allocator_start (pool->vallocator, min_buffers, V4L2_MEMORY_MMAP); if (count < GST_V4L2_MIN_BUFFERS) { min_buffers = count; goto no_buffers; } /* V4L2 buffer pool are often very limited in the amount of buffers it * can offer. The copy_threshold will workaround this limitation by * falling back to copy if the pipeline needed more buffers. This also * prevent having to do REQBUFS(N)/REQBUFS(0) everytime configure is * called. */ if (count != min_buffers) { GST_WARNING_OBJECT (pool, "using %u buffers instead of %u", count, min_buffers); min_buffers = count; copy_threshold = min_latency; /* The initial minimum could be provide either by GstBufferPool or * driver needs. */ min_buffers = count; } break; } case GST_V4L2_IO_USERPTR: { guint count; can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, USERPTR); GST_DEBUG_OBJECT (pool, "requesting %d USERPTR buffers", min_buffers); count = gst_v4l2_allocator_start (pool->vallocator, min_buffers, V4L2_MEMORY_USERPTR); /* There is no rational to not get what we asked */ if (count < min_buffers) { min_buffers = count; goto no_buffers; } min_buffers = count; break; } case GST_V4L2_IO_DMABUF_IMPORT: { guint count; can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, DMABUF); GST_DEBUG_OBJECT (pool, "requesting %d DMABUF buffers", min_buffers); count = gst_v4l2_allocator_start (pool->vallocator, min_buffers, V4L2_MEMORY_DMABUF); /* There is no rational to not get what we asked */ if (count < min_buffers) { min_buffers = count; goto no_buffers; } min_buffers = count; break; } default: min_buffers = 0; copy_threshold = 0; g_assert_not_reached (); break; } if (can_allocate) max_latency = max_buffers; else max_latency = min_buffers; pool->size = size; pool->copy_threshold = copy_threshold; pool->max_latency = max_latency; pool->min_latency = min_latency; pool->num_queued = 0; if (max_buffers < min_buffers) max_buffers = min_buffers; gst_buffer_pool_config_set_params (config, caps, size, min_buffers, max_buffers); pclass->set_config (bpool, config); gst_structure_free (config); if (pool->other_pool) if (!gst_buffer_pool_set_active (pool->other_pool, TRUE)) goto other_pool_failed; /* now, allocate the buffers: */ if (!pclass->start (bpool)) goto start_failed; if (!V4L2_TYPE_IS_OUTPUT (obj->type)) pool->group_released_handler = g_signal_connect_swapped (pool->vallocator, "group-released", G_CALLBACK (gst_v4l2_buffer_pool_group_released), pool); return TRUE; /* ERRORS */ wrong_config: { GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config); gst_structure_free (config); return FALSE; } no_buffers: { GST_ERROR_OBJECT (pool, "we received %d buffer from device '%s', we want at least %d", min_buffers, obj->videodev, GST_V4L2_MIN_BUFFERS); gst_structure_free (config); return FALSE; } start_failed: { GST_ERROR_OBJECT (pool, "failed to start streaming"); return FALSE; } other_pool_failed: { GST_ERROR_OBJECT (pool, "failed to active the other pool %" GST_PTR_FORMAT, pool->other_pool); return FALSE; } }
static void gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) { GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class); GstV4l2Object *obj = pool->obj; GST_DEBUG_OBJECT (pool, "release buffer %p", buffer); switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: /* capture, put the buffer back in the queue so that we can refill it * later. */ switch (obj->mode) { case GST_V4L2_IO_RW: /* release back in the pool */ pclass->release_buffer (bpool, buffer); break; case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: { if (gst_v4l2_is_buffer_valid (buffer, NULL)) { /* queue back in the device */ if (pool->other_pool) gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL); if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK) pclass->release_buffer (bpool, buffer); } else { /* Simply release invalide/modified buffer, the allocator will * give it back later */ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); pclass->release_buffer (bpool, buffer); } break; } default: g_assert_not_reached (); break; } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: switch (obj->mode) { case GST_V4L2_IO_RW: /* release back in the pool */ pclass->release_buffer (bpool, buffer); break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: { GstV4l2MemoryGroup *group; guint index; if (!gst_v4l2_is_buffer_valid (buffer, &group)) { /* Simply release invalide/modified buffer, the allocator will * give it back later */ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); pclass->release_buffer (bpool, buffer); break; } index = group->buffer.index; if (pool->buffers[index] == NULL) { GST_LOG_OBJECT (pool, "buffer %u not queued, putting on free list", index); /* Remove qdata, this will unmap any map data in userptr */ gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer), GST_V4L2_IMPORT_QUARK, NULL, NULL); /* reset to default size */ gst_v4l2_allocator_reset_group (pool->vallocator, group); /* playback, put the buffer back in the queue to refill later. */ pclass->release_buffer (bpool, buffer); } else { /* We keep a ref on queued buffer, so this should never happen */ g_assert_not_reached (); } break; } default: g_assert_not_reached (); break; } break; default: g_assert_not_reached (); break; } }
static GstFlowReturn gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params) { GstFlowReturn ret; GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class); GstV4l2Object *obj = pool->obj; GST_DEBUG_OBJECT (pool, "acquire"); /* If this is being called to resurect a lost buffer */ if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT) { ret = pclass->acquire_buffer (bpool, buffer, params); goto done; } switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: /* capture, This function should return a buffer with new captured data */ switch (obj->mode) { case GST_V4L2_IO_RW: { /* take empty buffer from the pool */ ret = pclass->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; break; } case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: { /* dequeue filled buffer */ ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer); break; } default: ret = GST_FLOW_ERROR; g_assert_not_reached (); break; } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: /* playback, This function should return an empty buffer */ switch (obj->mode) { case GST_V4L2_IO_RW: /* get an empty buffer */ ret = pclass->acquire_buffer (bpool, buffer, params); break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: /* get a free unqueued buffer */ ret = pclass->acquire_buffer (bpool, buffer, params); break; default: ret = GST_FLOW_ERROR; g_assert_not_reached (); break; } break; default: ret = GST_FLOW_ERROR; g_assert_not_reached (); break; } done: return ret; }