nvdec: implement flush/drain
authorMatthew Waters <matthew@centricular.com>
Fri, 17 Nov 2017 06:09:22 +0000 (17:09 +1100)
committerMatthew Waters <matthew@centricular.com>
Wed, 22 Nov 2017 03:34:33 +0000 (14:34 +1100)
Fixes outputted frame sequence when performing a seek

i.e. when seeking backwards, the first frame after the seek was a frame
from the future.  This would result in GstVideoDecoder essentially
marking all the timestamps as essentially bogus and the base class would
attempt to compensate.  A visible indication of this was 'decreasing timestamp'
warning after a seek.

https://bugzilla.gnome.org/show_bug.cgi?id=790478

sys/nvdec/gstnvdec.c

index 618c990..841a701 100644 (file)
@@ -216,6 +216,8 @@ static gboolean gst_nvdec_decide_allocation (GstVideoDecoder * decoder,
 static void gst_nvdec_set_context (GstElement * element, GstContext * context);
 static gboolean gst_nvdec_src_query (GstVideoDecoder * decoder,
     GstQuery * query);
+static gboolean gst_nvdec_flush (GstVideoDecoder * decoder);
+static GstFlowReturn gst_nvdec_drain (GstVideoDecoder * decoder);
 
 static GstStaticPadTemplate gst_nvdec_sink_template =
     GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
@@ -260,6 +262,8 @@ gst_nvdec_class_init (GstNvDecClass * klass)
   video_decoder_class->decide_allocation =
       GST_DEBUG_FUNCPTR (gst_nvdec_decide_allocation);
   video_decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_nvdec_src_query);
+  video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_nvdec_drain);
+  video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_nvdec_flush);
 
   element_class->set_context = GST_DEBUG_FUNCPTR (gst_nvdec_set_context);
 }
@@ -857,6 +861,44 @@ gst_nvdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
 }
 
 static gboolean
+gst_nvdec_flush (GstVideoDecoder * decoder)
+{
+  GstNvDec *nvdec = GST_NVDEC (decoder);
+  CUVIDSOURCEDATAPACKET packet = { 0, };
+
+  GST_DEBUG_OBJECT (nvdec, "flush");
+
+  packet.payload_size = 0;
+  packet.payload = NULL;
+  packet.flags = CUVID_PKT_ENDOFSTREAM;
+
+  if (!cuda_OK (cuvidParseVideoData (nvdec->parser, &packet)))
+    GST_WARNING_OBJECT (nvdec, "parser failed");
+
+  handle_pending_frames (nvdec);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_nvdec_drain (GstVideoDecoder * decoder)
+{
+  GstNvDec *nvdec = GST_NVDEC (decoder);
+  CUVIDSOURCEDATAPACKET packet = { 0, };
+
+  GST_DEBUG_OBJECT (nvdec, "draining decoder");
+
+  packet.payload_size = 0;
+  packet.payload = NULL;
+  packet.flags = CUVID_PKT_ENDOFSTREAM;
+
+  if (!cuda_OK (cuvidParseVideoData (nvdec->parser, &packet)))
+    GST_WARNING_OBJECT (nvdec, "parser failed");
+
+  return handle_pending_frames (nvdec);
+}
+
+static gboolean
 gst_nvdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
 {
   GstNvDec *nvdec = GST_NVDEC (decoder);