mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-22 14:06:23 +00:00
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:
parent
180ab8377f
commit
3db6f45ca9
4 changed files with 236 additions and 172 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in a new issue