/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *s; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL); pool->video_fd = fd; pool->obj = obj; 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); /* ERRORS */ dup_failed: { GST_DEBUG ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } }
GstBufferPool *gst_imx_v4l2_buffer_pool_new(GstImxFDObject *fd_obj_v4l) { GstImxV4l2BufferPool *pool; pool = g_object_new(gst_imx_v4l2_buffer_pool_get_type(), NULL); pool->fd_obj_v4l = gst_imx_fd_object_ref(fd_obj_v4l); return GST_BUFFER_POOL_CAST(pool); }
GstBufferPool * gst_mmal_opaque_buffer_pool_new () { GstMMALOpaqueBufferPool *pool; pool = g_object_new (GST_TYPE_MMAL_OPAQUE_BUFFER_POOL, NULL); return GST_BUFFER_POOL_CAST (pool); }
/** * gst_video_buffer_pool_new: * * Create a new bufferpool that can allocate video frames. This bufferpool * supports all the video bufferpool options. * * Returns: (transfer floating): a new #GstBufferPool to allocate video frames */ GstBufferPool * gst_video_buffer_pool_new () { GstVideoBufferPool *pool; pool = g_object_new (GST_TYPE_VIDEO_BUFFER_POOL, NULL); GST_LOG_OBJECT (pool, "new video buffer pool %p", pool); return GST_BUFFER_POOL_CAST (pool); }
GstBufferPool * gst_wayland_buffer_pool_new (GstWlDisplay * display) { GstWaylandBufferPool *pool; g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL); pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL); pool->display = g_object_ref (display); return GST_BUFFER_POOL_CAST (pool); }
GstBufferPool * gst_wayland_buffer_pool_new (GstWaylandSink * waylandsink) { GstWaylandBufferPool *pool; g_return_val_if_fail (GST_IS_WAYLAND_SINK (waylandsink), NULL); pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL); pool->sink = gst_object_ref (waylandsink); return GST_BUFFER_POOL_CAST (pool); }
/** * gst_gl_buffer_pool_new: * @display: the #GstGLDisplay to use * * Returns: a #GstBufferPool that allocates buffers with #GstGLMemory */ GstBufferPool * gst_gl_buffer_pool_new (GstGLContext * context) { GstGLBufferPool *pool; pool = g_object_new (GST_TYPE_GL_BUFFER_POOL, NULL); pool->context = gst_object_ref (context); GST_LOG_OBJECT (pool, "new GL buffer pool %p", pool); return GST_BUFFER_POOL_CAST (pool); }
GstBufferPool * gst_xvimage_buffer_pool_new (GstXvImageAllocator * allocator) { GstXvImageBufferPool *pool; pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL); pool->allocator = gst_object_ref (allocator); GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool); return GST_BUFFER_POOL_CAST (pool); }
GstBufferPool * gst_vdp_video_buffer_pool_new (GstVdpDevice * device) { GstVdpVideoBufferPool *pool; pool = g_object_new (GST_TYPE_VDP_VIDEO_BUFFER_POOL, NULL); pool->device = gst_object_ref (device); GST_LOG_OBJECT (pool, "new VdpVideo buffer pool %p", pool); return GST_BUFFER_POOL_CAST (pool); }
static GstVlcVideoPool* gst_vlc_video_sink_create_pool( GstVlcVideoSink *p_vsink, GstCaps *p_caps, gsize i_size, gint i_min ) { GstVlcVideoPool *p_pool; GstStructure *p_config; p_pool = gst_vlc_video_pool_new( p_vsink->p_allocator, p_vsink->p_dec ); p_config = gst_buffer_pool_get_config( GST_BUFFER_POOL_CAST( p_pool )); gst_buffer_pool_config_set_params( p_config, p_caps, i_size, i_min, 0); if( !gst_buffer_pool_set_config( GST_BUFFER_POOL_CAST( p_pool ), p_config )) goto config_failed; return p_pool; config_failed: { gst_object_unref (p_pool); return NULL; } }
GstBufferPool * gst_mir_buffer_pool_new (GstMirSink * mirsink) { GstMirBufferPool *m_pool; GST_WARNING ("%s", __PRETTY_FUNCTION__); g_return_val_if_fail (GST_IS_MIR_SINK (mirsink), NULL); m_pool = g_object_new (GST_TYPE_MIR_BUFFER_POOL, NULL); m_pool->sink = gst_object_ref (mirsink); return GST_BUFFER_POOL_CAST (m_pool); }
GstBufferPool * gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink) { GstXvImageBufferPool *pool; g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL); pool->sink = gst_object_ref (xvimagesink); GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool); return GST_BUFFER_POOL_CAST (pool); }
GstBufferPool * gst_ximage_buffer_pool_new (GstXImageSink * ximagesink) { GstXImageBufferPool *pool; g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); pool = g_object_new (GST_TYPE_XIMAGE_BUFFER_POOL, NULL); pool->sink = gst_object_ref (ximagesink); pool->allocator = g_object_new (GST_TYPE_XIMAGE_MEMORY_ALLOCATOR, NULL); GST_LOG_OBJECT (pool, "new XImage buffer pool %p", pool); return GST_BUFFER_POOL_CAST (pool); }
static void gst_buffer_pool_finalize (GObject * object) { GstBufferPool *pool; GstBufferPoolPrivate *priv; pool = GST_BUFFER_POOL_CAST (object); priv = pool->priv; GST_DEBUG_OBJECT (pool, "finalize"); gst_buffer_pool_set_active (pool, FALSE); gst_atomic_queue_unref (priv->queue); gst_poll_free (priv->poll); gst_structure_free (priv->config); g_rec_mutex_clear (&priv->rec_lock); if (priv->allocator) gst_object_unref (priv->allocator); G_OBJECT_CLASS (gst_buffer_pool_parent_class)->finalize (object); }
static gboolean gst_msdkdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstMsdkDec *thiz = GST_MSDKDEC (decoder); GstBufferPool *pool = NULL; GstStructure *pool_config = NULL; GstCaps *pool_caps /*, *negotiated_caps */ ; guint size, min_buffers, max_buffers; if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder, query)) return FALSE; /* Get the buffer pool config decided by the base class. The base class ensures that there will always be at least a 0th pool in the query. */ gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); pool_config = gst_buffer_pool_get_config (pool); /* Get the caps of pool and increase the min and max buffers by async_depth, * we will always have that number of decode operations in-flight */ gst_buffer_pool_config_get_params (pool_config, &pool_caps, &size, &min_buffers, &max_buffers); min_buffers += thiz->async_depth; if (max_buffers) max_buffers += thiz->async_depth; /* increase the min_buffers by 1 for smooth display in render pipeline */ min_buffers += 1; /* this will get updated with msdk requirement */ thiz->min_prealloc_buffers = min_buffers; if (_gst_caps_has_feature (pool_caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) { GST_INFO_OBJECT (decoder, "This MSDK decoder uses DMABuf memory"); thiz->use_video_memory = thiz->use_dmabuf = TRUE; } /* Initialize MSDK decoder before new bufferpool tries to alloc each buffer, * which requires information of frame allocation. * No effect if already initialized. */ if (!gst_msdkdec_init_decoder (thiz)) return FALSE; /* get the updated min_buffers which account the msdk requirement too */ min_buffers = thiz->min_prealloc_buffers; /* Decoder always use its own pool. So we create a pool if msdk apis * previously requested for allocation (do_realloc = TRUE) */ if (thiz->do_realloc || !thiz->pool) { if (thiz->pool) gst_object_replace ((GstObject **) & thiz->pool, NULL); GST_INFO_OBJECT (decoder, "create new MSDK bufferpool"); thiz->pool = gst_msdkdec_create_buffer_pool (thiz, &thiz->output_info, min_buffers); if (!thiz->pool) goto failed_to_create_pool; } if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL) && gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { GstStructure *config; GstAllocator *allocator; /* If downstream supports video meta and video alignment, * we can replace our own msdk bufferpool and use it */ /* Remove downstream's pool */ gst_structure_free (pool_config); gst_object_unref (pool); pool = gst_object_ref (thiz->pool); /* Set the allocator of new msdk bufferpool */ config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) gst_query_set_nth_allocation_param (query, 0, allocator, NULL); gst_structure_free (config); } else { /* Unfortunately, dowstream doesn't have videometa or alignment support, * we keep msdk pool as a side-pool that will be decoded into and * then copied from. */ GST_INFO_OBJECT (decoder, "Keep MSDK bufferpool as a side-pool"); /* Update params to downstream's pool */ gst_buffer_pool_config_set_params (pool_config, pool_caps, size, min_buffers, max_buffers); if (!gst_buffer_pool_set_config (pool, pool_config)) goto error_set_config; gst_video_info_from_caps (&thiz->non_msdk_pool_info, pool_caps); /* update width and height with actual negotiated values */ GST_VIDEO_INFO_WIDTH (&thiz->non_msdk_pool_info) = GST_VIDEO_INFO_WIDTH (&thiz->output_info); GST_VIDEO_INFO_HEIGHT (&thiz->non_msdk_pool_info) = GST_VIDEO_INFO_HEIGHT (&thiz->output_info); } gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers, max_buffers); if (pool) gst_object_unref (pool); return TRUE; failed_to_create_pool: GST_ERROR_OBJECT (decoder, "failed to set buffer pool config"); if (pool) gst_object_unref (pool); return FALSE; error_set_config: GST_ERROR_OBJECT (decoder, "failed to set buffer pool config"); if (pool) gst_object_unref (pool); return FALSE; }
/** * gst_v4l2_buffer_pool_process: * @bpool: a #GstBufferPool * @buf: a #GstBuffer * * Process @buf in @bpool. For capture devices, this functions fills @buf with * data from the device. For output devices, this functions send the contents of * @buf to the device for playback. * * Returns: %GST_FLOW_OK on success. */ GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstBufferPool *bpool = GST_BUFFER_POOL_CAST (pool); GstV4l2Object *obj = pool->obj; GST_DEBUG_OBJECT (pool, "process buffer %p", buf); switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: /* capture */ switch (obj->mode) { case GST_V4L2_IO_RW: /* capture into the buffer */ ret = gst_v4l2_do_read (pool, buf); break; case GST_V4L2_IO_MMAP: { GstBuffer *tmp; if (buf->pool == bpool) /* nothing, data was inside the buffer when we did _acquire() */ goto done; /* buffer not from our pool, grab a frame and copy it into the target */ if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK) goto done; if (!gst_v4l2_object_copy (obj, buf, tmp)) goto copy_failed; /* an queue the buffer again after the copy */ if ((ret = gst_v4l2_buffer_pool_qbuf (pool, tmp)) != GST_FLOW_OK) goto done; break; } case GST_V4L2_IO_USERPTR: default: g_assert_not_reached (); break; } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: /* playback */ switch (obj->mode) { case GST_V4L2_IO_RW: /* FIXME, do write() */ GST_WARNING_OBJECT (pool, "implement write()"); break; case GST_V4L2_IO_MMAP: { GstBuffer *to_queue; if (buf->pool == bpool) { /* nothing, we can queue directly */ to_queue = buf; GST_LOG_OBJECT (pool, "processing buffer from our pool"); } else { GST_LOG_OBJECT (pool, "alloc buffer from our pool"); if (!gst_buffer_pool_is_active (bpool)) { GstStructure *config; /* this pool was not activated, configure and activate */ GST_DEBUG_OBJECT (pool, "activating pool"); config = gst_buffer_pool_get_config (bpool); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_set_config (bpool, config); if (!gst_buffer_pool_set_active (bpool, TRUE)) goto activate_failed; } /* this can block if all buffers are outstanding which would be * strange because we would expect the upstream element to have * allocated them and returned to us.. */ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, &to_queue, NULL); if (ret != GST_FLOW_OK) goto acquire_failed; /* copy into it and queue */ if (!gst_v4l2_object_copy (obj, to_queue, buf)) goto copy_failed; } if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK) goto done; /* if we are not streaming yet (this is the first buffer, start * streaming now */ if (!pool->streaming) if (!start_streaming (pool)) goto start_failed; if (pool->num_queued == pool->num_allocated) { /* all buffers are queued, try to dequeue one and release it back * into the pool so that _acquire can get to it again. */ ret = gst_v4l2_buffer_pool_dqbuf (pool, &to_queue); if (ret != GST_FLOW_OK) goto done; /* release the rendered buffer back into the pool. This wakes up any * thread waiting for a buffer in _acquire() */ gst_v4l2_buffer_pool_release_buffer (bpool, to_queue); } break; } case GST_V4L2_IO_USERPTR: default: g_assert_not_reached (); break; } break; default: g_assert_not_reached (); break; } done: return ret; /* ERRORS */ activate_failed: { GST_ERROR_OBJECT (obj->element, "failed to activate pool"); return GST_FLOW_ERROR; } acquire_failed: { GST_WARNING_OBJECT (obj->element, "failed to acquire a buffer: %s", gst_flow_get_name (ret)); return ret; } copy_failed: { GST_ERROR_OBJECT (obj->element, "failed to copy data"); return GST_FLOW_ERROR; } start_failed: { GST_ERROR_OBJECT (obj->element, "failed to start streaming"); return GST_FLOW_ERROR; } }
static GstBufferPool * gst_msdkdec_create_buffer_pool (GstMsdkDec * thiz, GstVideoInfo * info, guint num_buffers) { GstBufferPool *pool = NULL; GstStructure *config; GstAllocator *allocator = NULL; GstVideoAlignment align; GstCaps *caps = NULL; GstAllocationParams params = { 0, 31, 0, 0, }; mfxFrameAllocResponse *alloc_resp = NULL; g_return_val_if_fail (info, NULL); g_return_val_if_fail (GST_VIDEO_INFO_WIDTH (info) && GST_VIDEO_INFO_HEIGHT (info), NULL); alloc_resp = &thiz->alloc_resp; pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp); if (!pool) goto error_no_pool; if (G_UNLIKELY (!IS_ALIGNED (GST_VIDEO_INFO_WIDTH (info), 16) || !IS_ALIGNED (GST_VIDEO_INFO_HEIGHT (info), 32))) { gst_msdk_set_video_alignment (info, &align); gst_video_info_align (info, &align); } caps = gst_video_info_to_caps (info); /* allocators should use the same width/height/stride/height_alignment of * negotiated output caps which is what we configure in msdk_allocator */ if (thiz->use_dmabuf) allocator = gst_msdk_dmabuf_allocator_new (thiz->context, info, alloc_resp); else if (thiz->use_video_memory) allocator = gst_msdk_video_allocator_new (thiz->context, info, alloc_resp); else allocator = gst_msdk_system_allocator_new (info); if (!allocator) goto error_no_allocator; config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (info), num_buffers, 0); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); if (thiz->use_video_memory) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY); if (thiz->use_dmabuf) gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF); } gst_buffer_pool_config_set_video_alignment (config, &align); gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); gst_object_unref (allocator); if (!gst_buffer_pool_set_config (pool, config)) goto error_pool_config; return pool; error_no_pool: { GST_INFO_OBJECT (thiz, "failed to create bufferpool"); return NULL; } error_no_allocator: { GST_INFO_OBJECT (thiz, "failed to create allocator"); gst_object_unref (pool); return NULL; } error_pool_config: { GST_INFO_OBJECT (thiz, "failed to set config"); gst_object_unref (pool); gst_object_unref (allocator); return NULL; } }
static GstBufferPool * gst_msdkvpp_create_buffer_pool (GstMsdkVPP * thiz, GstPadDirection direction, GstCaps * caps, guint min_num_buffers) { GstBufferPool *pool = NULL; GstStructure *config; GstAllocator *allocator = NULL; GstVideoInfo info; GstVideoInfo *pool_info = NULL; GstVideoAlignment align; GstAllocationParams params = { 0, 31, 0, 0, }; mfxFrameAllocResponse *alloc_resp = NULL; gboolean use_dmabuf = FALSE; if (direction == GST_PAD_SINK) { alloc_resp = &thiz->in_alloc_resp; pool_info = &thiz->sinkpad_buffer_pool_info; use_dmabuf = thiz->use_sinkpad_dmabuf; } else if (direction == GST_PAD_SRC) { alloc_resp = &thiz->out_alloc_resp; pool_info = &thiz->srcpad_buffer_pool_info; use_dmabuf = thiz->use_srcpad_dmabuf; } pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp); if (!pool) goto error_no_pool; if (!gst_video_info_from_caps (&info, caps)) goto error_no_video_info; gst_msdk_set_video_alignment (&info, &align); gst_video_info_align (&info, &align); if (use_dmabuf) allocator = gst_msdk_dmabuf_allocator_new (thiz->context, &info, alloc_resp); else if (thiz->use_video_memory) allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp); else allocator = gst_msdk_system_allocator_new (&info); if (!allocator) goto error_no_allocator; config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (config, caps, info.size, min_num_buffers, 0); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); if (thiz->use_video_memory) { gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY); if (use_dmabuf) gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF); } gst_buffer_pool_config_set_video_alignment (config, &align); gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); gst_object_unref (allocator); if (!gst_buffer_pool_set_config (pool, config)) goto error_pool_config; /* Updating pool_info with algined info of allocator */ *pool_info = info; return pool; error_no_pool: { GST_INFO_OBJECT (thiz, "Failed to create bufferpool"); return NULL; } error_no_video_info: { GST_INFO_OBJECT (thiz, "Failed to get Video info from caps"); return NULL; } error_no_allocator: { GST_INFO_OBJECT (thiz, "Failed to create allocator"); if (pool) gst_object_unref (pool); return NULL; } error_pool_config: { GST_INFO_OBJECT (thiz, "Failed to set config"); if (pool) gst_object_unref (pool); if (allocator) gst_object_unref (allocator); return NULL; } }
/** * gst_v4l2_buffer_pool_process: * @bpool: a #GstBufferPool * @buf: a #GstBuffer, maybe be replaced * * Process @buf in @bpool. For capture devices, this functions fills @buf with * data from the device. For output devices, this functions send the contents of * @buf to the device for playback. * * Returns: %GST_FLOW_OK on success. */ GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf) { GstFlowReturn ret = GST_FLOW_OK; GstBufferPool *bpool = GST_BUFFER_POOL_CAST (pool); GstV4l2Object *obj = pool->obj; GST_DEBUG_OBJECT (pool, "process buffer %p", buf); g_return_val_if_fail (gst_buffer_pool_is_active (bpool), GST_FLOW_ERROR); if (GST_BUFFER_POOL_IS_FLUSHING (pool)) return GST_FLOW_FLUSHING; switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: /* capture */ switch (obj->mode) { case GST_V4L2_IO_RW: /* capture into the buffer */ ret = gst_v4l2_do_read (pool, *buf); break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_DMABUF: { GstBuffer *tmp; if ((*buf)->pool == bpool) { if (gst_buffer_get_size (*buf) == 0) goto eos; /* start copying buffers when we are running low on buffers */ if (g_atomic_int_get (&pool->num_queued) < pool->copy_threshold) { GstBuffer *copy; if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) { if (gst_buffer_pool_acquire_buffer (bpool, ©, NULL) == GST_FLOW_OK) { gst_v4l2_buffer_pool_release_buffer (bpool, copy); goto done; } } /* copy the buffer */ copy = gst_buffer_copy_region (*buf, GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1); GST_LOG_OBJECT (pool, "copy buffer %p->%p", *buf, copy); /* and requeue so that we can continue capturing */ gst_buffer_unref (*buf); *buf = copy; } /* nothing, data was inside the buffer when we did _acquire() */ goto done; } /* buffer not from our pool, grab a frame and copy it into the target */ if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK) goto done; /* An empty buffer on capture indicates the end of stream */ if (gst_buffer_get_size (tmp) == 0) { gst_v4l2_buffer_pool_release_buffer (bpool, tmp); goto eos; } ret = gst_v4l2_buffer_pool_copy_buffer (pool, *buf, tmp); /* an queue the buffer again after the copy */ gst_v4l2_buffer_pool_release_buffer (bpool, tmp); if (ret != GST_FLOW_OK) goto copy_failed; break; } case GST_V4L2_IO_USERPTR: { struct UserPtrData *data; /* Replace our buffer with downstream allocated buffer */ data = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf), GST_V4L2_IMPORT_QUARK); gst_buffer_replace (buf, data->buffer); _unmap_userptr_frame (data); break; } case GST_V4L2_IO_DMABUF_IMPORT: { GstBuffer *tmp; /* Replace our buffer with downstream allocated buffer */ tmp = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf), GST_V4L2_IMPORT_QUARK); gst_buffer_replace (buf, tmp); gst_buffer_unref (tmp); break; } default: g_assert_not_reached (); break; } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: /* playback */ switch (obj->mode) { case GST_V4L2_IO_RW: /* FIXME, do write() */ GST_WARNING_OBJECT (pool, "implement write()"); break; case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF_IMPORT: case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: { GstBuffer *to_queue = NULL; GstV4l2MemoryGroup *group; gint index; if ((*buf)->pool != bpool) goto copying; if (!gst_v4l2_is_buffer_valid (*buf, &group)) goto copying; index = group->buffer.index; GST_LOG_OBJECT (pool, "processing buffer %i from our pool", index); index = group->buffer.index; if (pool->buffers[index] != NULL) { GST_LOG_OBJECT (pool, "buffer %i already queued, copying", index); goto copying; } /* we can queue directly */ to_queue = gst_buffer_ref (*buf); copying: if (to_queue == NULL) { GstBufferPoolAcquireParams params = { 0 }; GST_LOG_OBJECT (pool, "alloc buffer from our pool"); /* this can return EOS if all buffers are outstanding which would * be strange because we would expect the upstream element to have * allocated them and returned to us.. */ params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT; ret = gst_buffer_pool_acquire_buffer (bpool, &to_queue, ¶ms); if (ret != GST_FLOW_OK) goto acquire_failed; ret = gst_v4l2_buffer_pool_prepare_buffer (pool, to_queue, *buf); if (ret != GST_FLOW_OK) { gst_buffer_unref (to_queue); goto prepare_failed; } } if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK) goto queue_failed; /* if we are not streaming yet (this is the first buffer, start * streaming now */ if (!gst_v4l2_buffer_pool_streamon (pool)) { /* don't check return value because qbuf would have failed */ gst_v4l2_is_buffer_valid (to_queue, &group); /* qbuf has taken the ref of the to_queue buffer but we are no in * streaming state, so the flush logic won't be performed. * To avoid leaks, flush the allocator and restore the queued * buffer as non-queued */ gst_v4l2_allocator_flush (pool->vallocator); pool->buffers[group->buffer.index] = NULL; gst_mini_object_set_qdata (GST_MINI_OBJECT (to_queue), GST_V4L2_IMPORT_QUARK, NULL, NULL); gst_buffer_unref (to_queue); g_atomic_int_add (&pool->num_queued, -1); goto start_failed; } if (g_atomic_int_get (&pool->num_queued) >= pool->min_latency) { GstBuffer *out; /* all buffers are queued, try to dequeue one and release it back * into the pool so that _acquire can get to it again. */ ret = gst_v4l2_buffer_pool_dqbuf (pool, &out); if (ret == GST_FLOW_OK) /* release the rendered buffer back into the pool. This wakes up any * thread waiting for a buffer in _acquire(). */ gst_buffer_unref (out); } break; } default: g_assert_not_reached (); break; } break; default: g_assert_not_reached (); break; } done: return ret; /* ERRORS */ copy_failed: { GST_ERROR_OBJECT (pool, "failed to copy buffer"); return ret; } eos: { GST_DEBUG_OBJECT (pool, "end of stream reached"); return GST_FLOW_EOS; } acquire_failed: { if (ret == GST_FLOW_FLUSHING) GST_DEBUG_OBJECT (pool, "flushing"); else GST_WARNING_OBJECT (pool, "failed to acquire a buffer: %s", gst_flow_get_name (ret)); return ret; } prepare_failed: { GST_ERROR_OBJECT (pool, "failed to prepare data"); return ret; } queue_failed: { GST_ERROR_OBJECT (pool, "failed to queue buffer"); return ret; } start_failed: { GST_ERROR_OBJECT (pool, "failed to start streaming"); return GST_FLOW_ERROR; } }
/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *config; gchar *name, *parent_name; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; /* setting a significant unique name */ parent_name = gst_object_get_name (GST_OBJECT (obj->element)); name = g_strconcat (parent_name, ":", "pool:", V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL); g_free (parent_name); pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, "name", name, NULL); g_free (name); gst_poll_fd_init (&pool->pollfd); pool->pollfd.fd = fd; gst_poll_add_fd (pool->poll, &pool->pollfd); if (V4L2_TYPE_IS_OUTPUT (obj->type)) gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE); else gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE); pool->video_fd = fd; pool->obj = obj; pool->can_poll_device = TRUE; pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format); if (pool->vallocator == NULL) goto allocator_failed; gst_object_ref (obj->element); config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0); /* This will simply set a default config, but will not configure the pool * because min and max are not valid */ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config); return GST_BUFFER_POOL (pool); /* ERRORS */ dup_failed: { GST_ERROR ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } allocator_failed: { GST_ERROR_OBJECT (pool, "Failed to create V4L2 allocator"); return NULL; } }
static gboolean gst_msdkvpp_propose_allocation (GstBaseTransform * trans, GstQuery * decide_query, GstQuery * query) { GstMsdkVPP *thiz = GST_MSDKVPP (trans); GstVideoInfo info; GstBufferPool *pool = NULL; GstAllocator *allocator = NULL; GstCaps *caps; GstStructure *config; gboolean need_pool; GstAllocationParams params; guint size; guint min_buffers = thiz->async_depth + 1; gst_query_parse_allocation (query, &caps, &need_pool); if (!caps) { GST_ERROR_OBJECT (thiz, "Failed to parse the allocation caps"); return FALSE; } if (!gst_video_info_from_caps (&info, caps)) { GST_ERROR_OBJECT (thiz, "Failed to get video info"); return FALSE; } /* if upstream allocation query supports dmabuf-capsfeatures, * we do allocate dmabuf backed memory */ if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) { GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory"); thiz->use_sinkpad_dmabuf = TRUE; } if (need_pool) { /* alwys provide a new pool for upstream to help re-negotiation * more info here: https://bugzilla.gnome.org/show_bug.cgi?id=748344 */ pool = gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps, min_buffers); } /* Update the internal pool if any allocation attribute changed */ if (!gst_video_info_is_equal (&thiz->sinkpad_buffer_pool_info, &info)) { gst_object_unref (thiz->sinkpad_buffer_pool); thiz->sinkpad_buffer_pool = gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps, min_buffers); } /* get the size and allocator params from configured pool and set it in query */ if (!need_pool) pool = gst_object_ref (thiz->sinkpad_buffer_pool); config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL); if (gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms)) gst_query_add_allocation_param (query, allocator, ¶ms); gst_structure_free (config); /* if upstream does't have a pool requirement, set only * size, min_buffers and max_buffers in query */ gst_query_add_allocation_pool (query, need_pool ? pool : NULL, size, min_buffers, 0); gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); gst_object_unref (pool); return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans, decide_query, query); }
static gboolean gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query) { GstV4l2Src *src; GstV4l2Object *obj; GstBufferPool *pool; guint size, min, max; gboolean update; src = GST_V4L2SRC (bsrc); obj = src->v4l2object; if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); update = TRUE; } else { pool = NULL; min = max = 0; size = 0; update = FALSE; } GST_DEBUG_OBJECT (src, "allocation: size:%u min:%u max:%u pool:%" GST_PTR_FORMAT, size, min, max, pool); if (min != 0) { /* if there is a min-buffers suggestion, use it. We add 1 because we need 1 * buffer extra to capture while the other two buffers are downstream */ min += 1; } else { min = 2; } /* select a pool */ switch (obj->mode) { case GST_V4L2_IO_RW: if (pool == NULL) { /* no downstream pool, use our own then */ GST_DEBUG_OBJECT (src, "read/write mode: no downstream pool, using our own"); pool = GST_BUFFER_POOL_CAST (obj->pool); size = obj->sizeimage; } else { /* in READ/WRITE mode, prefer a downstream pool because our own pool * doesn't help much, we have to write to it as well */ GST_DEBUG_OBJECT (src, "read/write mode: using downstream pool"); /* use the bigest size, when we use our own pool we can't really do any * other size than what the hardware gives us but for downstream pools * we can try */ size = MAX (size, obj->sizeimage); } break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF: /* in streaming mode, prefer our own pool */ pool = GST_BUFFER_POOL_CAST (obj->pool); size = obj->sizeimage; GST_DEBUG_OBJECT (src, "streaming mode: using our own pool %" GST_PTR_FORMAT, pool); break; case GST_V4L2_IO_AUTO: default: GST_WARNING_OBJECT (src, "unhandled mode"); break; } if (pool) { GstStructure *config; GstCaps *caps; config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL); gst_buffer_pool_config_set_params (config, caps, size, min, max); /* if downstream supports video metadata, add this to the pool config */ if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { GST_DEBUG_OBJECT (pool, "activate Video Meta"); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); } gst_buffer_pool_set_config (pool, config); } if (update) gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); else gst_query_add_allocation_pool (query, pool, size, min, max); return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query); }