summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.com>2020-07-01 12:28:05 -0400
committerNicolas Dufresne <nicolas.dufresne@collabora.com>2020-07-02 12:21:51 -0400
commit1bef43f9d4a8ff7b5f4ca72a9bf83f21776d1224 (patch)
tree3f3c01f736671925a8c9eb3b80c4ff0baac9fa69
parenta88e63dd2ff8cb3991b79f140915810da9b5ca8d (diff)
v4l2decoder: Track pending request
With the asynchronous slice decoding, we only queue up to 2 slices per frames. That side effect is that now we are dequeuing bitstream buffers in both decoding and presentation order. This would lead to a bitstream buffer from a previous frame being dequeued instead of the expected last slice buffer and lead to us trying to queue an already queued bitstream buffer. We now fix this by tracking pending requests. As request are executed in decoding order, we marking a request done, we can effectively dequeue bitstream buffer from all previous request, as they have been executed already. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1395>
-rw-r--r--sys/v4l2codecs/gstv4l2decoder.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/sys/v4l2codecs/gstv4l2decoder.c b/sys/v4l2codecs/gstv4l2decoder.c
index d00706eec..fad7d7485 100644
--- a/sys/v4l2codecs/gstv4l2decoder.c
+++ b/sys/v4l2codecs/gstv4l2decoder.c
@@ -63,6 +63,7 @@ struct _GstV4l2Decoder
gint media_fd;
gint video_fd;
GstQueueArray *request_pool;
+ GstQueueArray *pending_requests;
enum v4l2_buf_type src_buf_type;
enum v4l2_buf_type sink_buf_type;
@@ -104,6 +105,7 @@ static void
gst_v4l2_decoder_init (GstV4l2Decoder * self)
{
self->request_pool = gst_queue_array_new (16);
+ self->pending_requests = gst_queue_array_new (16);
}
static void
@@ -223,8 +225,18 @@ gst_v4l2_decoder_streamon (GstV4l2Decoder * self, GstPadDirection direction)
gboolean
gst_v4l2_decoder_streamoff (GstV4l2Decoder * self, GstPadDirection direction)
{
- gint ret;
+ GstV4l2Request *pending_req;
guint32 type = direction_to_buffer_type (self, direction);
+ gint ret;
+
+ if (direction == GST_PAD_SRC) {
+ /* 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))) {
+ g_clear_pointer (&pending_req->bitstream, gst_memory_unref);
+ pending_req->pending = FALSE;
+ }
+ }
ret = ioctl (self->video_fd, VIDIOC_STREAMOFF, &type);
if (ret < 0) {
@@ -838,7 +850,14 @@ gst_v4l2_request_free (GstV4l2Request * request)
request->decoder = NULL;
if (request->pending) {
+ gint idx;
+
GST_DEBUG_OBJECT (decoder, "Freeing pending request %p.", request);
+
+ idx = gst_queue_array_find (decoder->pending_requests, NULL, NULL);
+ if (idx >= 0)
+ gst_queue_array_drop_element (decoder->pending_requests, idx);
+
gst_v4l2_request_free (request);
g_object_unref (decoder);
return;
@@ -874,6 +893,7 @@ gst_v4l2_request_queue (GstV4l2Request * request)
}
request->pending = TRUE;
+ gst_queue_array_push_tail (request->decoder->pending_requests, request);
return TRUE;
}
@@ -888,8 +908,23 @@ void
gst_v4l2_request_set_done (GstV4l2Request * request)
{
if (request->bitstream) {
- gst_v4l2_decoder_dequeue_sink (request->decoder);
- g_clear_pointer (&request->bitstream, gst_memory_unref);
+ GstV4l2Decoder *dec = request->decoder;
+ GstV4l2Request *pending_req;
+
+ 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);
+
+ if (pending_req == request)
+ break;
+ }
+
+ /* 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);
+ }
}
request->pending = FALSE;