qsvencoder: Workaround for invalid DTS with VP9
authorSeungha Yang <seungha@centricular.com>
Mon, 25 Apr 2022 13:59:14 +0000 (22:59 +0900)
committerSeungha Yang <seungha@centricular.com>
Mon, 25 Apr 2022 19:51:54 +0000 (04:51 +0900)
SDK runtime seems to report zero DTS for all frames in case of VP9 but
we don't need to use DTS for the codec.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2291>

subprojects/gst-plugins-bad/sys/qsv/gstqsvencoder.cpp

index e16a13a30bbfd1e4be87930b6a37d0e9a07687e0..3b6e7472be9852bfc24c6b798c18c4d3cf68f872 100644 (file)
@@ -704,8 +704,8 @@ gst_qsv_encoder_finish_frame (GstQsvEncoder * self, GstQsvEncoderTask * task,
   mfxStatus status;
   mfxBitstream *bs;
   GstVideoCodecFrame *frame;
-  GstClockTime pts = GST_CLOCK_TIME_NONE;
-  GstClockTime dts = GST_CLOCK_TIME_NONE;
+  GstClockTime qsv_pts = GST_CLOCK_TIME_NONE;
+  GstClockTime qsv_dts = GST_CLOCK_TIME_NONE;
   GstBuffer *buffer;
   gboolean keyframe = FALSE;
   guint retry_count = 0;
@@ -750,8 +750,19 @@ gst_qsv_encoder_finish_frame (GstQsvEncoder * self, GstQsvEncoderTask * task,
   }
 
   bs = &task->bitstream;
-  pts = gst_qsv_timestamp_to_gst (bs->TimeStamp);
-  dts = gst_qsv_timestamp_to_gst ((mfxU64) bs->DecodeTimeStamp);
+  qsv_pts = gst_qsv_timestamp_to_gst (bs->TimeStamp);
+
+  /* SDK runtime seems to report zero DTS for all fraems in case of VP9.
+   * It sounds SDK bug, but we can workaround it safely because VP9 B-frame is
+   * not supported in this implementation.
+   *
+   * Also we perfer our nanoseconds timestamp instead of QSV's timescale.
+   * So let' ignore QSV's timescale for non-{h264,h265} cases.
+   *
+   * TODO: We may need to use DTS for MPEG2 (not implemented yet)
+   */
+  if (klass->codec_id == MFX_CODEC_AVC || klass->codec_id == MFX_CODEC_HEVC)
+    qsv_dts = gst_qsv_timestamp_to_gst ((mfxU64) bs->DecodeTimeStamp);
 
   if ((bs->FrameType & MFX_FRAMETYPE_IDR) != 0)
     keyframe = TRUE;
@@ -768,10 +779,15 @@ gst_qsv_encoder_finish_frame (GstQsvEncoder * self, GstQsvEncoderTask * task,
     return GST_FLOW_ERROR;
   }
 
-  frame = gst_qsv_encoder_find_output_frame (self, pts);
+  frame = gst_qsv_encoder_find_output_frame (self, qsv_pts);
   if (frame) {
-    frame->pts = pts;
-    frame->dts = dts;
+    if (GST_CLOCK_TIME_IS_VALID (qsv_dts)) {
+      frame->pts = qsv_pts;
+      frame->dts = qsv_dts;
+    } else {
+      frame->dts = frame->pts;
+    }
+
     frame->output_buffer = buffer;
 
     if (keyframe)
@@ -783,8 +799,11 @@ gst_qsv_encoder_finish_frame (GstQsvEncoder * self, GstQsvEncoderTask * task,
   /* Empty available frame, something went wrong but we can just push this
    * buffer */
   GST_WARNING_OBJECT (self, "Failed to find corresponding frame");
-  GST_BUFFER_PTS (buffer) = pts;
-  GST_BUFFER_DTS (buffer) = dts;
+  GST_BUFFER_PTS (buffer) = qsv_pts;
+  if (GST_CLOCK_TIME_IS_VALID (qsv_dts))
+    GST_BUFFER_DTS (buffer) = qsv_dts;
+  else
+    GST_BUFFER_DTS (buffer) = qsv_pts;
 
   if (!keyframe)
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);