v4l2codecs: Add remove buffers helpers

Add helpers function to call VIDIOC_REMOVE_BUFS ioctl.
If the driver support this feature buffers are removed from the queue when:
- the pool when is detached from the decoded.
- the pool is released.
- allocation failed.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7684>
This commit is contained in:
Benjamin Gaignard 2024-05-27 14:28:18 +02:00 committed by GStreamer Marge Bot
parent fecdfe18ca
commit ad537ef934
3 changed files with 81 additions and 3 deletions

View file

@ -173,6 +173,7 @@ gst_v4l2_codec_allocator_prepare (GstV4l2CodecAllocator * self)
{
GstV4l2Decoder *decoder = self->decoder;
GstPadDirection direction = self->direction;
GstV4l2CodecBuffer *buf;
guint i;
GST_DEBUG_OBJECT (self, "Try to create %d buffers", self->pool_size);
@ -198,7 +199,16 @@ gst_v4l2_codec_allocator_prepare (GstV4l2CodecAllocator * self)
return TRUE;
failed:
gst_v4l2_decoder_request_buffers (decoder, direction, 0);
/* If buffer allocation failed remove them all either by
* calling delete_buffers IOCTL if the driver support it,
* either by using legacy request_buf IOCTL with 0 has parameter */
if (gst_v4l2_decoder_has_remove_bufs (decoder)) {
while (i-- && (buf = g_queue_pop_tail (&self->pool))) {
gst_v4l2_decoder_remove_buffers (decoder, direction, buf->index, 1);
}
} else {
gst_v4l2_decoder_request_buffers (decoder, direction, 0);
}
return FALSE;
}
@ -212,10 +222,16 @@ static void
gst_v4l2_codec_allocator_dispose (GObject * object)
{
GstV4l2CodecAllocator *self = GST_V4L2_CODEC_ALLOCATOR (object);
GstV4l2Decoder *decoder = self->decoder;
GstPadDirection direction = self->direction;
GstV4l2CodecBuffer *buf;
while ((buf = g_queue_pop_head (&self->pool)))
while ((buf = g_queue_pop_head (&self->pool))) {
if (gst_v4l2_decoder_has_remove_bufs (decoder)) {
gst_v4l2_decoder_remove_buffers (decoder, direction, buf->index, 1);
}
gst_v4l2_codec_buffer_free (buf);
}
if (self->decoder) {
gst_v4l2_codec_allocator_detach (self);
@ -349,10 +365,21 @@ gst_v4l2_codec_allocator_get_pool_size (GstV4l2CodecAllocator * self)
void
gst_v4l2_codec_allocator_detach (GstV4l2CodecAllocator * self)
{
GstV4l2Decoder *decoder = self->decoder;
GST_OBJECT_LOCK (self);
if (!self->detached) {
self->detached = TRUE;
gst_v4l2_decoder_request_buffers (self->decoder, self->direction, 0);
if (!gst_v4l2_decoder_has_remove_bufs (decoder)) {
gst_v4l2_decoder_request_buffers (self->decoder, self->direction, 0);
} else {
GstV4l2CodecBuffer *buf;
while ((buf = g_queue_pop_tail (&self->pool)))
gst_v4l2_decoder_remove_buffers (self->decoder, self->direction,
buf->index, 1);
}
}
GST_OBJECT_UNLOCK (self);
}

View file

@ -78,6 +78,7 @@ struct _GstV4l2Decoder
GstVecDeque *request_pool;
GstVecDeque *pending_requests;
guint version;
GstVideoInfo *info;
enum v4l2_buf_type src_buf_type;
enum v4l2_buf_type sink_buf_type;
@ -90,6 +91,7 @@ struct _GstV4l2Decoder
/* detected features */
gboolean supports_holding_capture;
gboolean supports_remove_buffers;
};
G_DEFINE_TYPE_WITH_CODE (GstV4l2Decoder, gst_v4l2_decoder, GST_TYPE_OBJECT,
@ -225,6 +227,11 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
return FALSE;
}
if (createbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS)
self->supports_remove_buffers = TRUE;
else
self->supports_remove_buffers = FALSE;
self->opened = TRUE;
return TRUE;
@ -550,6 +557,31 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self,
return caps;
}
gboolean
gst_v4l2_decoder_remove_buffers (GstV4l2Decoder * self,
GstPadDirection direction, guint index, guint num_buffers)
{
gint ret;
struct v4l2_remove_buffers remove_bufs = {
.type = direction_to_buffer_type (self, direction),
.index = index,
.count = num_buffers,
};
if (!self->supports_remove_buffers)
return FALSE;
GST_DEBUG_OBJECT (self, "remove buffers %d from index %d", remove_bufs.count,
remove_bufs.index);
ret = ioctl (self->video_fd, VIDIOC_REMOVE_BUFS, &remove_bufs);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_REMOVE_BUF failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
}
gboolean
gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps,
GstVideoInfo * vinfo, GstVideoInfoDmaDrm * vinfo_drm)
@ -1233,6 +1265,19 @@ gst_v4l2_decoder_get_render_delay (GstV4l2Decoder * self)
return self->render_delay;
}
/**
* gst_v4l2_decoder_has_remove_bufs:
* @self: a #GstV4l2Decoder pointer
*
* Returns: TRUE if the video decoder driver allows to remove
* buffers from CAPTURE queue.
*/
gboolean
gst_v4l2_decoder_has_remove_bufs (GstV4l2Decoder * self)
{
return self->supports_remove_buffers;
}
GstV4l2Request *
gst_v4l2_request_ref (GstV4l2Request * request)
{

View file

@ -90,6 +90,11 @@ gint gst_v4l2_decoder_create_buffers (GstV4l2Decoder * self,
GstPadDirection direction,
guint num_buffers);
gint gst_v4l2_decoder_remove_buffers (GstV4l2Decoder * self,
GstPadDirection direction,
guint index,
guint num_buffers);
gboolean gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
GstPadDirection directon,
gint index,
@ -145,6 +150,7 @@ void gst_v4l2_decoder_set_render_delay (GstV4l2Decoder * self,
guint gst_v4l2_decoder_get_render_delay (GstV4l2Decoder * self);
gboolean gst_v4l2_decoder_has_remove_bufs (GstV4l2Decoder * self);
GstV4l2Request * gst_v4l2_request_ref (GstV4l2Request * request);