v4l2codecs: Rework handling of queues and pending requests

Starting from this patch, all queue and dequeue operation happening
on V4L2 is now abstracted with the request. Buffers are dequeued
automatically when pending requests are marked done and only 1 in-flight
request is now used.

Along with fixing issues with request not being reused with slice
decoders, this change reduces the memory footprint by allocating only
two bitstream buffers.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1881>
This commit is contained in:
Nicolas Dufresne 2020-12-14 17:07:01 -05:00 committed by GStreamer Merge Bot
parent 180ab8377f
commit 3db6f45ca9
4 changed files with 236 additions and 172 deletions

View file

@ -337,7 +337,7 @@ gst_v4l2_codec_h264_dec_decide_allocation (GstVideoDecoder * decoder,
min = MAX (2, min);
self->sink_allocator = gst_v4l2_codec_allocator_new (self->decoder,
GST_PAD_SINK, self->min_pool_size + 2);
GST_PAD_SINK, 2);
self->src_allocator = gst_v4l2_codec_allocator_new (self->decoder,
GST_PAD_SRC, self->min_pool_size + min + 4);
self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
@ -825,24 +825,6 @@ fail:
return FALSE;
}
static gboolean
gst_v4l2_codec_h264_dec_wait (GstV4l2CodecH264Dec * self,
GstV4l2Request * request)
{
gint ret = gst_v4l2_request_poll (request, GST_SECOND);
if (ret == 0) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Decoding frame took too long"), (NULL));
return FALSE;
} else if (ret < 0) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Decoding request failed: %s", g_strerror (errno)), (NULL));
return FALSE;
}
return TRUE;
}
static GstFlowReturn
gst_v4l2_codec_h264_dec_output_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture)
@ -850,41 +832,35 @@ gst_v4l2_codec_h264_dec_output_picture (GstH264Decoder * decoder,
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
GstV4l2Request *request = gst_h264_picture_get_user_data (picture);
gint ret;
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
if (gst_v4l2_request_is_done (request))
goto finish_frame;
if (!gst_v4l2_codec_h264_dec_wait (self, request))
ret = gst_v4l2_request_poll (request, GST_SECOND);
if (ret == 0) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Decoding frame %u took too long", picture->system_frame_number),
(NULL));
goto error;
} else if (ret < 0) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Decoding request failed: %s", g_strerror (errno)), (NULL));
goto error;
while (TRUE) {
guint32 frame_num;
GstH264Picture *other_pic;
GstV4l2Request *other_request;
if (!gst_v4l2_decoder_dequeue_src (self->decoder, &frame_num)) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Decoder did not produce a frame"), (NULL));
goto error;
}
if (frame_num == picture->system_frame_number)
break;
other_pic = gst_h264_decoder_get_picture (decoder, frame_num);
if (other_pic) {
other_request = gst_h264_picture_get_user_data (other_pic);
gst_v4l2_request_set_done (other_request);
gst_h264_picture_unref (other_pic);
}
}
finish_frame:
gst_v4l2_request_set_done (request);
g_return_val_if_fail (frame->output_buffer, GST_FLOW_ERROR);
finish_frame:
if (gst_v4l2_request_failed (request)) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Failed to decode frame %u", picture->system_frame_number), (NULL));
goto error;
}
/* Hold on reference buffers for the rest of the picture lifetime */
gst_h264_picture_set_user_data (picture,
gst_buffer_ref (frame->output_buffer), (GDestroyNotify) gst_buffer_unref);
@ -937,14 +913,6 @@ gst_v4l2_codec_h264_dec_ensure_output_buffer (GstV4l2CodecH264Dec * self,
return FALSE;
}
if (!gst_v4l2_decoder_queue_src_buffer (self->decoder, buffer,
frame->system_frame_number)) {
GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
("Driver did not accept the picture buffer."), (NULL));
gst_buffer_unref (buffer);
return FALSE;
}
frame->output_buffer = buffer;
return TRUE;
}
@ -953,8 +921,7 @@ static gboolean
gst_v4l2_codec_h264_dec_submit_bitstream (GstV4l2CodecH264Dec * self,
GstH264Picture * picture, guint flags)
{
GstVideoCodecFrame *frame;
GstV4l2Request *prev_request, *request;
GstV4l2Request *prev_request, *request = NULL;
gsize bytesused;
gboolean ret = FALSE;
@ -989,23 +956,38 @@ gst_v4l2_codec_h264_dec_submit_bitstream (GstV4l2CodecH264Dec * self,
};
/* *INDENT-ON* */
request = gst_v4l2_decoder_alloc_request (self->decoder);
prev_request = gst_h264_picture_get_user_data (picture);
bytesused = self->bitstream_map.size;
gst_memory_unmap (self->bitstream, &self->bitstream_map);
self->bitstream_map = (GstMapInfo) GST_MAP_INFO_INIT;
gst_memory_resize (self->bitstream, 0, bytesused);
if (prev_request) {
request = gst_v4l2_decoder_alloc_sub_request (self->decoder, prev_request,
self->bitstream);
} else {
GstVideoCodecFrame *frame;
frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self),
picture->system_frame_number);
g_return_val_if_fail (frame, FALSE);
if (!gst_v4l2_codec_h264_dec_ensure_output_buffer (self, frame))
goto done;
request = gst_v4l2_decoder_alloc_request (self->decoder,
picture->system_frame_number, self->bitstream, frame->output_buffer);
gst_video_codec_frame_unref (frame);
}
if (!request) {
GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT,
("Failed to allocate a media request object."), (NULL));
goto done;
}
frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self),
picture->system_frame_number);
g_return_val_if_fail (frame, FALSE);
if (!gst_v4l2_codec_h264_dec_ensure_output_buffer (self, frame))
goto done;
gst_video_codec_frame_unref (frame);
if (!gst_v4l2_decoder_set_controls (self->decoder, request, control,
G_N_ELEMENTS (control))) {
GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
@ -1013,30 +995,12 @@ gst_v4l2_codec_h264_dec_submit_bitstream (GstV4l2CodecH264Dec * self,
goto done;
}
bytesused = self->bitstream_map.size;
gst_memory_unmap (self->bitstream, &self->bitstream_map);
self->bitstream_map = (GstMapInfo) GST_MAP_INFO_INIT;
if (!gst_v4l2_decoder_queue_sink_mem (self->decoder, request, self->bitstream,
picture->system_frame_number, bytesused, flags)) {
GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
("Driver did not accept the bitstream data."), (NULL));
goto done;
}
if (!gst_v4l2_request_queue (request)) {
if (!gst_v4l2_request_queue (request, flags)) {
GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
("Driver did not accept the decode request."), (NULL));
goto done;
}
prev_request = gst_h264_picture_get_user_data (picture);
if (prev_request) {
if (!gst_v4l2_codec_h264_dec_wait (self, prev_request))
goto done;
gst_v4l2_request_set_done (prev_request);
}
gst_h264_picture_set_user_data (picture, g_steal_pointer (&request),
(GDestroyNotify) gst_v4l2_request_free);
ret = TRUE;
@ -1044,6 +1008,7 @@ gst_v4l2_codec_h264_dec_submit_bitstream (GstV4l2CodecH264Dec * self,
done:
if (request)
gst_v4l2_request_free (request);
gst_v4l2_codec_h264_dec_reset_picture (self);
return ret;

View file

@ -246,7 +246,7 @@ gst_v4l2_codec_vp8_dec_decide_allocation (GstVideoDecoder * decoder,
min = MAX (2, min);
self->sink_allocator = gst_v4l2_codec_allocator_new (self->decoder,
GST_PAD_SINK, self->min_pool_size + 2);
GST_PAD_SINK, 2);
self->src_allocator = gst_v4l2_codec_allocator_new (self->decoder,
GST_PAD_SRC, self->min_pool_size + min + 4);
self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
@ -539,15 +539,10 @@ gst_v4l2_codec_vp8_dec_end_picture (GstVp8Decoder * decoder,
};
/* *INDENT-ON* */
request = gst_v4l2_decoder_alloc_request (self->decoder);
if (!request) {
GST_ELEMENT_ERROR (decoder, RESOURCE, NO_SPACE_LEFT,
("Failed to allocate a media request object."), (NULL));
goto fail;
}
gst_vp8_picture_set_user_data (picture, request,
(GDestroyNotify) gst_v4l2_request_free);
bytesused = self->bitstream_map.size;
gst_memory_unmap (self->bitstream, &self->bitstream_map);
self->bitstream_map = (GstMapInfo) GST_MAP_INFO_INIT;
gst_memory_resize (self->bitstream, 0, bytesused);
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->src_pool),
&buffer, NULL);
@ -567,6 +562,17 @@ gst_v4l2_codec_vp8_dec_end_picture (GstVp8Decoder * decoder,
frame->output_buffer = buffer;
gst_video_codec_frame_unref (frame);
request = gst_v4l2_decoder_alloc_request (self->decoder,
picture->system_frame_number, self->bitstream, buffer);
if (!request) {
GST_ELEMENT_ERROR (decoder, RESOURCE, NO_SPACE_LEFT,
("Failed to allocate a media request object."), (NULL));
goto fail;
}
gst_vp8_picture_set_user_data (picture, request,
(GDestroyNotify) gst_v4l2_request_free);
if (!gst_v4l2_decoder_set_controls (self->decoder, request, control,
G_N_ELEMENTS (control))) {
GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
@ -574,26 +580,7 @@ gst_v4l2_codec_vp8_dec_end_picture (GstVp8Decoder * decoder,
goto fail;
}
bytesused = self->bitstream_map.size;
gst_memory_unmap (self->bitstream, &self->bitstream_map);
self->bitstream_map = (GstMapInfo) GST_MAP_INFO_INIT;
if (!gst_v4l2_decoder_queue_sink_mem (self->decoder, request, self->bitstream,
picture->system_frame_number, bytesused, 0)) {
GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
("Driver did not accept the bitstream data."), (NULL));
goto fail;
}
if (!gst_v4l2_decoder_queue_src_buffer (self->decoder, buffer,
picture->system_frame_number)) {
GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
("Driver did not accept the picture buffer."), (NULL));
goto fail;
}
if (!gst_v4l2_request_queue (request)) {
if (!gst_v4l2_request_queue (request, 0)) {
GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
("Driver did not accept the decode request."), (NULL));
goto fail;
@ -663,7 +650,6 @@ gst_v4l2_codec_vp8_dec_output_picture (GstVp8Decoder * decoder,
GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
GstV4l2Request *request = gst_vp8_picture_get_user_data (picture);
gint ret;
guint32 frame_num;
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
@ -682,18 +668,16 @@ gst_v4l2_codec_vp8_dec_output_picture (GstVp8Decoder * decoder,
goto error;
}
do {
if (!gst_v4l2_decoder_dequeue_src (self->decoder, &frame_num)) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Decoder did not produce a frame"), (NULL));
goto error;
}
} while (frame_num != picture->system_frame_number);
finish_frame:
gst_v4l2_request_set_done (request);
g_return_val_if_fail (frame->output_buffer, GST_FLOW_ERROR);
finish_frame:
if (gst_v4l2_request_failed (request)) {
GST_ELEMENT_ERROR (self, STREAM, DECODE,
("Failed to decode frame %u", picture->system_frame_number), (NULL));
goto error;
}
/* Hold on reference buffers for the rest of the picture lifetime */
gst_vp8_picture_set_user_data (picture,
gst_buffer_ref (frame->output_buffer), (GDestroyNotify) gst_buffer_unref);

View file

@ -49,10 +49,17 @@ struct _GstV4l2Request
{
GstV4l2Decoder *decoder;
gint fd;
guint32 frame_num;
GstMemory *bitstream;
GstBuffer *pic_buf;
GstPoll *poll;
GstPollFD pollfd;
/* request state */
gboolean pending;
gboolean failed;
gboolean hold_pic_buf;
gboolean sub_request;
};
struct _GstV4l2Decoder
@ -225,11 +232,12 @@ gst_v4l2_decoder_streamon (GstV4l2Decoder * self, GstPadDirection direction)
gboolean
gst_v4l2_decoder_streamoff (GstV4l2Decoder * self, GstPadDirection direction)
{
GstV4l2Request *pending_req;
guint32 type = direction_to_buffer_type (self, direction);
gint ret;
if (direction == GST_PAD_SRC) {
GstV4l2Request *pending_req;
/* STREAMOFF have the effect of cancelling all requests and unqueuing all
* buffers, so clear the pending request list */
while ((pending_req = gst_queue_array_pop_head (self->pending_requests))) {
@ -530,12 +538,13 @@ gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
return TRUE;
}
gboolean
static gboolean
gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
GstV4l2Request * request, GstMemory * mem, guint32 frame_num,
gsize bytesused, guint flags)
guint flags)
{
gint ret;
gsize bytesused = gst_memory_get_sizes (mem, NULL, NULL);
struct v4l2_plane plane = {
.bytesused = bytesused,
};
@ -563,14 +572,11 @@ gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
return FALSE;
}
request->bitstream = gst_memory_ref (mem);
return TRUE;
}
gboolean
gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer,
guint32 frame_num)
static gboolean
gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer)
{
gint i, ret;
struct v4l2_plane planes[GST_VIDEO_MAX_PLANES];
@ -606,7 +612,7 @@ gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer,
return TRUE;
}
gboolean
static gboolean
gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self)
{
gint ret;
@ -632,7 +638,7 @@ gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self)
return TRUE;
}
gboolean
static gboolean
gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self, guint32 * out_frame_num)
{
gint ret;
@ -806,8 +812,23 @@ gst_v4l2_decoder_register (GstPlugin * plugin,
g_free (type_name);
}
/*
* gst_v4l2_decoder_alloc_request:
* @self a #GstV4l2Decoder pointer
* @frame_num: Used as a timestamp to identify references
* @bitstream the #GstMemory that holds the bitstream data
* @pic_buf the #GstBuffer holding the decoded picture
*
* Allocate a Linux media request file descriptor. This request wrapper will
* hold a reference to the requested bitstream memory to decoded and the
* picture buffer this request will decode to. This will be used for
* transparent management of the V4L2 queues.
*
* Returns: a new #GstV4l2Request
*/
GstV4l2Request *
gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self)
gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self, guint32 frame_num,
GstMemory * bitstream, GstBuffer * pic_buf)
{
GstV4l2Request *request = gst_queue_array_pop_head (self->request_pool);
gint ret;
@ -830,9 +851,60 @@ gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self)
}
request->decoder = g_object_ref (self);
request->bitstream = gst_memory_ref (bitstream);
request->pic_buf = gst_buffer_ref (pic_buf);
request->frame_num = frame_num;
return request;
}
/*
* gst_v4l2_decoder_alloc_sub_request:
* @self a #GstV4l2Decoder pointer
* @prev_request the #GstV4l2Request this request continue
* @bitstream the #GstMemory that holds the bitstream data
*
* Allocate a Linux media request file descriptor. Similar to
* gst_v4l2_decoder_alloc_request(), but used when a request is the
* continuation of the decoding of the same picture. This is notably the case
* for subsequent slices or for second field of a frame.
*
* Returns: a new #GstV4l2Request
*/
GstV4l2Request *
gst_v4l2_decoder_alloc_sub_request (GstV4l2Decoder * self,
GstV4l2Request * prev_request, GstMemory * bitstream)
{
GstV4l2Request *request = gst_queue_array_pop_head (self->request_pool);
gint ret;
if (!request) {
request = g_new0 (GstV4l2Request, 1);
ret = ioctl (self->media_fd, MEDIA_IOC_REQUEST_ALLOC, &request->fd);
if (ret < 0) {
GST_ERROR_OBJECT (self, "MEDIA_IOC_REQUEST_ALLOC failed: %s",
g_strerror (errno));
return NULL;
}
request->poll = gst_poll_new (FALSE);
gst_poll_fd_init (&request->pollfd);
request->pollfd.fd = request->fd;
gst_poll_add_fd (request->poll, &request->pollfd);
gst_poll_fd_ctl_pri (request->poll, &request->pollfd, TRUE);
}
request->decoder = g_object_ref (self);
request->bitstream = gst_memory_ref (bitstream);
request->pic_buf = gst_buffer_ref (prev_request->pic_buf);
request->frame_num = prev_request->frame_num;
request->sub_request = TRUE;
return request;
}
void
gst_v4l2_request_free (GstV4l2Request * request)
{
@ -847,6 +919,11 @@ gst_v4l2_request_free (GstV4l2Request * request)
}
g_clear_pointer (&request->bitstream, gst_memory_unref);
g_clear_pointer (&request->pic_buf, gst_buffer_unref);
request->frame_num = G_MAXUINT32;
request->failed = FALSE;
request->hold_pic_buf = FALSE;
request->sub_request = FALSE;
request->decoder = NULL;
if (request->pending) {
@ -879,21 +956,48 @@ gst_v4l2_request_free (GstV4l2Request * request)
}
gboolean
gst_v4l2_request_queue (GstV4l2Request * request)
gst_v4l2_request_queue (GstV4l2Request * request, guint flags)
{
GstV4l2Decoder *decoder = request->decoder;
gint ret;
GST_TRACE_OBJECT (request->decoder, "Queuing request %p.", request);
GST_TRACE_OBJECT (decoder, "Queuing request %p.", request);
if (!gst_v4l2_decoder_queue_sink_mem (decoder, request,
request->bitstream, request->frame_num, flags)) {
GST_ERROR_OBJECT (decoder, "Driver did not accept the bitstream data.");
return FALSE;
}
if (!request->sub_request &&
!gst_v4l2_decoder_queue_src_buffer (decoder, request->pic_buf)) {
GST_ERROR_OBJECT (decoder, "Driver did not accept the picture buffer.");
return FALSE;
}
ret = ioctl (request->fd, MEDIA_REQUEST_IOC_QUEUE, NULL);
if (ret < 0) {
GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s",
GST_ERROR_OBJECT (decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s",
g_strerror (errno));
return FALSE;
}
if (flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF)
request->hold_pic_buf = TRUE;
request->pending = TRUE;
gst_queue_array_push_tail (request->decoder->pending_requests, request);
gst_queue_array_push_tail (decoder->pending_requests, request);
/* FIXME to support more then one pending requests, we need the request to
* be refcounted */
if (gst_queue_array_get_length (decoder->pending_requests) > 1) {
GstV4l2Request *pending_req;
pending_req = gst_queue_array_peek_head (decoder->pending_requests);
ret = gst_v4l2_request_poll (pending_req, GST_SECOND);
if (ret > 0)
gst_v4l2_request_set_done (pending_req);
}
return TRUE;
}
@ -907,28 +1011,38 @@ gst_v4l2_request_poll (GstV4l2Request * request, GstClockTime timeout)
void
gst_v4l2_request_set_done (GstV4l2Request * request)
{
if (request->bitstream) {
GstV4l2Decoder *dec = request->decoder;
GstV4l2Request *pending_req;
GstV4l2Decoder *decoder = request->decoder;
GstV4l2Request *pending_req = NULL;
while ((pending_req = gst_queue_array_pop_head (dec->pending_requests))) {
gst_v4l2_decoder_dequeue_sink (request->decoder);
g_clear_pointer (&pending_req->bitstream, gst_memory_unref);
pending_req->pending = FALSE;
if (!request->pending)
return;
if (pending_req == request)
break;
while ((pending_req = gst_queue_array_pop_head (decoder->pending_requests))) {
gst_v4l2_decoder_dequeue_sink (decoder);
g_clear_pointer (&pending_req->bitstream, gst_memory_unref);
if (!pending_req->hold_pic_buf) {
guint32 frame_num = G_MAXUINT32;
if (!gst_v4l2_decoder_dequeue_src (decoder, &frame_num)) {
pending_req->failed = TRUE;
} else if (frame_num != pending_req->frame_num) {
GST_WARNING_OBJECT (decoder,
"Requested frame %u, but driver returned frame %u.",
pending_req->frame_num, frame_num);
pending_req->failed = TRUE;
}
}
/* Pending request should always be found in the fifo */
if (pending_req != request) {
g_warning ("Pending request not found in the pending list.");
gst_v4l2_decoder_dequeue_sink (request->decoder);
g_clear_pointer (&pending_req->bitstream, gst_memory_unref);
}
g_clear_pointer (&pending_req->pic_buf, gst_buffer_unref);
pending_req->pending = FALSE;
if (pending_req == request)
break;
}
request->pending = FALSE;
/* Pending request must be in the pending request list */
g_assert (pending_req == request);
}
gboolean
@ -936,3 +1050,9 @@ gst_v4l2_request_is_done (GstV4l2Request * request)
{
return !request->pending;
}
gboolean
gst_v4l2_request_failed (GstV4l2Request * request)
{
return request->failed;
}

View file

@ -72,22 +72,6 @@ gboolean gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
gsize * offsets,
guint *num_fds);
gboolean gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
GstV4l2Request * request,
GstMemory * mem,
guint32 frame_num,
gsize bytesused,
guint flags);
gboolean gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self);
gboolean gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self,
GstBuffer * buffer,
guint32 frame_num);
gboolean gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self,
guint32 *out_frame_num);
gboolean gst_v4l2_decoder_set_controls (GstV4l2Decoder * self,
GstV4l2Request * request,
struct v4l2_ext_control *control,
@ -115,18 +99,29 @@ void gst_v4l2_decoder_register (GstPlugin * plugin,
GstV4l2CodecDevice * device,
guint rank);
GstV4l2Request *gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self);
GstV4l2Request *gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self,
guint32 frame_num,
GstMemory *bitstream,
GstBuffer * pic_buf);
GstV4l2Request *gst_v4l2_decoder_alloc_sub_request (GstV4l2Decoder * self,
GstV4l2Request * prev_request,
GstMemory *bitstream);
void gst_v4l2_request_free (GstV4l2Request * request);
gboolean gst_v4l2_request_queue (GstV4l2Request * request);
gboolean gst_v4l2_request_queue (GstV4l2Request * request,
guint flags);
gint gst_v4l2_request_poll (GstV4l2Request * request, GstClockTime timeout);
gint gst_v4l2_request_poll (GstV4l2Request * request,
GstClockTime timeout);
void gst_v4l2_request_set_done (GstV4l2Request * request);
gboolean gst_v4l2_request_is_done (GstV4l2Request * request);
gboolean gst_v4l2_request_failed (GstV4l2Request * request);
G_END_DECLS
#endif /* __GST_V4L2_DECODER_H__ */