v4l2codecs: Rework handling of queues and pending requests
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 14 Dec 2020 22:07:01 +0000 (17:07 -0500)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 29 Jan 2021 19:44:48 +0000 (19:44 +0000)
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>

sys/v4l2codecs/gstv4l2codech264dec.c
sys/v4l2codecs/gstv4l2codecvp8dec.c
sys/v4l2codecs/gstv4l2decoder.c
sys/v4l2codecs/gstv4l2decoder.h

index a24739e..f554f99 100644 (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;
index 0e5024c..ca5267b 100644 (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,33 +562,25 @@ gst_v4l2_codec_vp8_dec_end_picture (GstVp8Decoder * decoder,
   frame->output_buffer = buffer;
   gst_video_codec_frame_unref (frame);
 
-  if (!gst_v4l2_decoder_set_controls (self->decoder, request, control,
-          G_N_ELEMENTS (control))) {
-    GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
-        ("Driver did not accept the bitstream parameters."), (NULL));
-    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));
+  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_queue_src_buffer (self->decoder, buffer,
-          picture->system_frame_number)) {
+  if (!gst_v4l2_decoder_set_controls (self->decoder, request, control,
+          G_N_ELEMENTS (control))) {
     GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
-        ("Driver did not accept the picture buffer."), (NULL));
+        ("Driver did not accept the bitstream parameters."), (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);
index abe81f9..533ce3d 100644 (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);
 
-    /* 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);
+    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;
+      }
     }
+
+    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;
+}
index 0d32e31..e0f9cf8 100644 (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__ */