mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 07:28:53 +00:00
v4l2: Move output details to device object
Move the details of how a buffer is rendered to the device object.
This commit is contained in:
parent
7c5f5b1b7f
commit
33d93069c1
5 changed files with 81 additions and 78 deletions
|
@ -86,6 +86,8 @@ GstV4l2BufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object *obj, gint num_b
|
||||||
void gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool);
|
void gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool);
|
||||||
|
|
||||||
GstBuffer * gst_v4l2_buffer_pool_get (GstV4l2BufferPool *pool, gboolean blocking);
|
GstBuffer * gst_v4l2_buffer_pool_get (GstV4l2BufferPool *pool, gboolean blocking);
|
||||||
|
|
||||||
|
|
||||||
gboolean gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool *pool, GstBuffer *buf);
|
gboolean gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool *pool, GstBuffer *buf);
|
||||||
GstBuffer * gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool *pool);
|
GstBuffer * gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool *pool);
|
||||||
|
|
||||||
|
|
|
@ -2689,5 +2689,76 @@ gst_v4l2_object_get_buffer (GstV4l2Object * v4l2object, GstBuffer ** buf)
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
gst_v4l2_object_output_buffer (GstV4l2Object * v4l2object, GstBuffer * buf)
|
gst_v4l2_object_output_buffer (GstV4l2Object * v4l2object, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
return GST_FLOW_ERROR;
|
GstBuffer *newbuf = NULL;
|
||||||
|
GstMetaV4l2 *meta;
|
||||||
|
|
||||||
|
meta = GST_META_V4L2_GET (buf);
|
||||||
|
|
||||||
|
if (meta == NULL || meta->pool != v4l2object->pool) {
|
||||||
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
/* not our buffer */
|
||||||
|
GST_DEBUG_OBJECT (v4l2object->element, "slow-path.. need to memcpy");
|
||||||
|
newbuf = gst_v4l2_buffer_pool_get (v4l2object->pool, TRUE);
|
||||||
|
|
||||||
|
if (v4l2object->info.finfo) {
|
||||||
|
GstVideoFrame src_frame, dest_frame;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (v4l2object->element, "copy video frame");
|
||||||
|
/* we have raw video, use videoframe copy to get strides right */
|
||||||
|
gst_video_frame_map (&src_frame, &v4l2object->info, buf, GST_MAP_READ);
|
||||||
|
gst_video_frame_map (&dest_frame, &v4l2object->info, newbuf,
|
||||||
|
GST_MAP_WRITE);
|
||||||
|
|
||||||
|
gst_video_frame_copy (&dest_frame, &src_frame);
|
||||||
|
|
||||||
|
gst_video_frame_unmap (&src_frame);
|
||||||
|
gst_video_frame_unmap (&dest_frame);
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (v4l2object->element, "copy raw bytes");
|
||||||
|
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
|
gst_buffer_fill (newbuf, 0, data, size);
|
||||||
|
gst_buffer_unmap (buf, data, size);
|
||||||
|
}
|
||||||
|
GST_DEBUG_OBJECT (v4l2object->element, "render copied buffer: %p", newbuf);
|
||||||
|
buf = newbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_v4l2_buffer_pool_qbuf (v4l2object->pool, buf))
|
||||||
|
goto queue_failed;
|
||||||
|
|
||||||
|
if (!v4l2object->streaming) {
|
||||||
|
if (!gst_v4l2_object_start (v4l2object)) {
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!newbuf)
|
||||||
|
gst_buffer_ref (buf);
|
||||||
|
|
||||||
|
/* if the driver has more than one buffer, ie. more than just the one we
|
||||||
|
* just queued, then dequeue one immediately to make it available via
|
||||||
|
* _buffer_alloc():
|
||||||
|
*/
|
||||||
|
if (gst_v4l2_buffer_pool_available_buffers (v4l2object->pool) >
|
||||||
|
v4l2object->min_queued_bufs) {
|
||||||
|
GstBuffer *v4l2buf = gst_v4l2_buffer_pool_dqbuf (v4l2object->pool);
|
||||||
|
|
||||||
|
/* note: if we get a buf, we don't want to use it directly (because
|
||||||
|
* someone else could still hold a ref).. but instead we release our
|
||||||
|
* reference to it, and if no one else holds a ref it will be returned
|
||||||
|
* to the pool of available buffers.. and if not, we keep looping.
|
||||||
|
*/
|
||||||
|
if (v4l2buf) {
|
||||||
|
gst_buffer_unref (v4l2buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
queue_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (v4l2object->element, "failed to queue buffer");
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,7 @@ struct _GstV4l2Object {
|
||||||
|
|
||||||
/* optional pool */
|
/* optional pool */
|
||||||
guint32 num_buffers;
|
guint32 num_buffers;
|
||||||
|
guint32 min_queued_bufs;
|
||||||
gboolean always_copy;
|
gboolean always_copy;
|
||||||
gboolean use_mmap;
|
gboolean use_mmap;
|
||||||
GstV4l2BufferPool *pool;
|
GstV4l2BufferPool *pool;
|
||||||
|
|
|
@ -247,7 +247,7 @@ gst_v4l2sink_init (GstV4l2Sink * v4l2sink)
|
||||||
|
|
||||||
/* number of buffers requested */
|
/* number of buffers requested */
|
||||||
v4l2sink->v4l2object->num_buffers = PROP_DEF_QUEUE_SIZE;
|
v4l2sink->v4l2object->num_buffers = PROP_DEF_QUEUE_SIZE;
|
||||||
v4l2sink->min_queued_bufs = PROP_DEF_MIN_QUEUED_BUFS;
|
v4l2sink->v4l2object->min_queued_bufs = PROP_DEF_MIN_QUEUED_BUFS;
|
||||||
|
|
||||||
v4l2sink->probed_caps = NULL;
|
v4l2sink->probed_caps = NULL;
|
||||||
v4l2sink->current_caps = NULL;
|
v4l2sink->current_caps = NULL;
|
||||||
|
@ -397,7 +397,7 @@ gst_v4l2sink_set_property (GObject * object,
|
||||||
v4l2sink->v4l2object->num_buffers = g_value_get_uint (value);
|
v4l2sink->v4l2object->num_buffers = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
case PROP_MIN_QUEUED_BUFS:
|
case PROP_MIN_QUEUED_BUFS:
|
||||||
v4l2sink->min_queued_bufs = g_value_get_uint (value);
|
v4l2sink->v4l2object->min_queued_bufs = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
case PROP_OVERLAY_TOP:
|
case PROP_OVERLAY_TOP:
|
||||||
v4l2sink->overlay.top = g_value_get_int (value);
|
v4l2sink->overlay.top = g_value_get_int (value);
|
||||||
|
@ -460,7 +460,7 @@ gst_v4l2sink_get_property (GObject * object,
|
||||||
g_value_set_uint (value, v4l2sink->v4l2object->num_buffers);
|
g_value_set_uint (value, v4l2sink->v4l2object->num_buffers);
|
||||||
break;
|
break;
|
||||||
case PROP_MIN_QUEUED_BUFS:
|
case PROP_MIN_QUEUED_BUFS:
|
||||||
g_value_set_uint (value, v4l2sink->min_queued_bufs);
|
g_value_set_uint (value, v4l2sink->v4l2object->min_queued_bufs);
|
||||||
break;
|
break;
|
||||||
case PROP_OVERLAY_TOP:
|
case PROP_OVERLAY_TOP:
|
||||||
g_value_set_int (value, v4l2sink->overlay.top);
|
g_value_set_int (value, v4l2sink->overlay.top);
|
||||||
|
@ -666,84 +666,15 @@ invalid_format:
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
GstFlowReturn ret;
|
||||||
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
|
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
|
||||||
GstBuffer *newbuf = NULL;
|
|
||||||
GstMetaV4l2 *meta;
|
|
||||||
GstV4l2Object *obj = v4l2sink->v4l2object;
|
GstV4l2Object *obj = v4l2sink->v4l2object;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (v4l2sink, "render buffer: %p", buf);
|
GST_DEBUG_OBJECT (v4l2sink, "render buffer: %p", buf);
|
||||||
|
|
||||||
meta = GST_META_V4L2_GET (buf);
|
ret = gst_v4l2_object_output_buffer (obj, buf);
|
||||||
|
|
||||||
if (meta == NULL || meta->pool != obj->pool) {
|
return ret;
|
||||||
guint8 *data;
|
|
||||||
gsize size;
|
|
||||||
|
|
||||||
/* not our buffer */
|
|
||||||
GST_DEBUG_OBJECT (v4l2sink, "slow-path.. need to memcpy");
|
|
||||||
newbuf = gst_v4l2_buffer_pool_get (obj->pool, TRUE);
|
|
||||||
|
|
||||||
if (obj->info.finfo) {
|
|
||||||
GstVideoFrame src_frame, dest_frame;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (v4l2sink, "copy video frame");
|
|
||||||
/* we have raw video, use videoframe copy to get strides right */
|
|
||||||
gst_video_frame_map (&src_frame, &obj->info, buf, GST_MAP_READ);
|
|
||||||
gst_video_frame_map (&dest_frame, &obj->info, newbuf, GST_MAP_WRITE);
|
|
||||||
|
|
||||||
gst_video_frame_copy (&dest_frame, &src_frame);
|
|
||||||
|
|
||||||
gst_video_frame_unmap (&src_frame);
|
|
||||||
gst_video_frame_unmap (&dest_frame);
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (v4l2sink, "copy raw bytes");
|
|
||||||
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
|
||||||
gst_buffer_fill (newbuf, 0, data, size);
|
|
||||||
gst_buffer_unmap (buf, data, size);
|
|
||||||
}
|
|
||||||
GST_DEBUG_OBJECT (v4l2sink, "render copied buffer: %p", newbuf);
|
|
||||||
buf = newbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gst_v4l2_buffer_pool_qbuf (obj->pool, buf))
|
|
||||||
goto queue_failed;
|
|
||||||
|
|
||||||
if (!obj->streaming) {
|
|
||||||
if (!gst_v4l2_object_start (obj)) {
|
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newbuf) {
|
|
||||||
gst_buffer_ref (buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the driver has more than one buffer, ie. more than just the one we
|
|
||||||
* just queued, then dequeue one immediately to make it available via
|
|
||||||
* _buffer_alloc():
|
|
||||||
*/
|
|
||||||
if (gst_v4l2_buffer_pool_available_buffers (obj->pool) >
|
|
||||||
v4l2sink->min_queued_bufs) {
|
|
||||||
GstBuffer *v4l2buf = gst_v4l2_buffer_pool_dqbuf (obj->pool);
|
|
||||||
|
|
||||||
/* note: if we get a buf, we don't want to use it directly (because
|
|
||||||
* someone else could still hold a ref).. but instead we release our
|
|
||||||
* reference to it, and if no one else holds a ref it will be returned
|
|
||||||
* to the pool of available buffers.. and if not, we keep looping.
|
|
||||||
*/
|
|
||||||
if (v4l2buf) {
|
|
||||||
gst_buffer_unref (v4l2buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
queue_failed:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (v4l2sink, "failed to queue buffer");
|
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_XVIDEO
|
#ifdef HAVE_XVIDEO
|
||||||
|
|
|
@ -57,8 +57,6 @@ struct _GstV4l2Sink {
|
||||||
GstCaps *probed_caps; /* all supported caps of underlying v4l2 device */
|
GstCaps *probed_caps; /* all supported caps of underlying v4l2 device */
|
||||||
GstCaps *current_caps; /* the current negotiated caps */
|
GstCaps *current_caps; /* the current negotiated caps */
|
||||||
|
|
||||||
guint32 min_queued_bufs;
|
|
||||||
|
|
||||||
gint video_width, video_height; /* original (unscaled) video w/h */
|
gint video_width, video_height; /* original (unscaled) video w/h */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue