msdkh264dec: report error to user
authorHaihao Xiang <haihao.xiang@intel.com>
Fri, 6 Dec 2019 04:48:37 +0000 (12:48 +0800)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 28 Apr 2021 08:30:38 +0000 (08:30 +0000)
Sometimes user want to know what the error is when decoding a stream,
This commit adds a property of report-error to msdkh264dec. When
report-error is TRUE, msdkh264dec may catch bitstream error and frame
corruption, then report the error to application by using GST_ELEMENT_ERROR

Refer to the code in
https://github.com/Intel-Media-SDK/MediaSDK/tree/master/samples

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/909>

sys/msdk/gstmsdkdec.c
sys/msdk/gstmsdkdec.h
sys/msdk/gstmsdkdecproputil.c
sys/msdk/gstmsdkdecproputil.h
sys/msdk/gstmsdkh264dec.c

index da91f26..3c565ff 100644 (file)
@@ -659,6 +659,37 @@ finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
   task->decode_only = FALSE;
 }
 
+static void
+gst_msdkdec_frame_corruption_report (GstMsdkDec * thiz, mfxU16 corruption)
+{
+  if (!thiz->report_error || !corruption)
+    return;
+
+  if (corruption & MFX_CORRUPTION_MINOR)
+    GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+        ("[Corruption] Minor corruption detected!"), (NULL));
+
+  if (corruption & MFX_CORRUPTION_MAJOR)
+    GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+        ("[Corruption] Major corruption detected!"), (NULL));
+
+  if (corruption & MFX_CORRUPTION_ABSENT_TOP_FIELD)
+    GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+        ("[Corruption] Absent top field!"), (NULL));
+
+  if (corruption & MFX_CORRUPTION_ABSENT_BOTTOM_FIELD)
+    GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+        ("[Corruption] Absent bottom field!"), (NULL));
+
+  if (corruption & MFX_CORRUPTION_REFERENCE_FRAME)
+    GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+        ("[Corruption] Corrupted reference frame!"), (NULL));
+
+  if (corruption & MFX_CORRUPTION_REFERENCE_LIST)
+    GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+        ("[Corruption] Corrupted reference list!"), (NULL));
+}
+
 static GstFlowReturn
 gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
 {
@@ -681,6 +712,8 @@ gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
 
   surface = task->surface;
   if (surface) {
+    gst_msdkdec_frame_corruption_report (thiz,
+        surface->surface->Data.Corrupted);
     GST_DEBUG_OBJECT (thiz, "Decoded MFX TimeStamp: %" G_GUINT64_FORMAT,
         (guint64) surface->surface->Data.TimeStamp);
     pts = surface->surface->Data.TimeStamp;
@@ -984,6 +1017,33 @@ find_msdk_surface (GstMsdkDec * thiz, MsdkDecTask * task,
   return TRUE;
 }
 
+static void
+gst_msdkdec_error_report (GstMsdkDec * thiz)
+{
+  if (!thiz->report_error)
+    return;
+
+#if (MFX_VERSION >= 1025)
+  else {
+    if (thiz->error_report.ErrorTypes & MFX_ERROR_SPS)
+      GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+          ("[Error] SPS Error detected!"), (NULL));
+
+    if (thiz->error_report.ErrorTypes & MFX_ERROR_PPS)
+      GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+          ("[Error] PPS Error detected!"), (NULL));
+
+    if (thiz->error_report.ErrorTypes & MFX_ERROR_SLICEHEADER)
+      GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+          ("[Error] SliceHeader Error detected!"), (NULL));
+
+    if (thiz->error_report.ErrorTypes & MFX_ERROR_FRAME_GAP)
+      GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
+          ("[Error] Frame Gap Error detected!"), (NULL));
+  }
+#endif
+}
+
 static GstFlowReturn
 gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
 {
@@ -1093,8 +1153,15 @@ gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
      * and this information can't be retrieved from the negotiated caps.
      * So instead of introducing a codecparser dependency to parse the headers
      * inside msdk plugin, we simply use the mfx APIs to extract header information */
+#if (MFX_VERSION >= 1025)
+    if (thiz->report_error)
+      thiz->error_report.ErrorTypes = 0;
+#endif
+
     status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
     GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
+    gst_msdkdec_error_report (thiz);
+
     if (status == MFX_ERR_MORE_DATA) {
       flow = GST_FLOW_OK;
       goto done;
@@ -1179,6 +1246,10 @@ gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
         }
       }
     }
+#if (MFX_VERSION >= 1025)
+    if (thiz->report_error)
+      thiz->error_report.ErrorTypes = 0;
+#endif
 
     status =
         MFXVideoDECODE_DecodeFrameAsync (session, &bitstream, surface->surface,
@@ -1190,6 +1261,7 @@ gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
     }
 
     GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
+    gst_msdkdec_error_report (thiz);
 
     /* media-sdk requires complete reset since the surface is inadequate
      * for further decoding */
@@ -1199,8 +1271,14 @@ gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
        * suitable for the current frame. Call MFXVideoDECODE_DecodeHeader to get
        * the current frame size, then do memory re-allocation, otherwise
        * MFXVideoDECODE_DecodeFrameAsync will still fail on next call */
+#if (MFX_VERSION >= 1025)
+      if (thiz->report_error)
+        thiz->error_report.ErrorTypes = 0;
+#endif
       status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
       GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
+      gst_msdkdec_error_report (thiz);
+
       if (status == MFX_ERR_MORE_DATA) {
         flow = GST_FLOW_OK;
         goto done;
@@ -1574,6 +1652,10 @@ gst_msdkdec_drain (GstVideoDecoder * decoder)
       if (!surface)
         return GST_FLOW_ERROR;
     }
+#if (MFX_VERSION >= 1025)
+    if (thiz->report_error)
+      thiz->error_report.ErrorTypes = 0;
+#endif
 
     status =
         MFXVideoDECODE_DecodeFrameAsync (session, NULL, surface->surface,
@@ -1584,6 +1666,8 @@ gst_msdkdec_drain (GstVideoDecoder * decoder)
     }
 
     GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
+    gst_msdkdec_error_report (thiz);
+
     if (G_LIKELY (status == MFX_ERR_NONE)) {
       thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
       surface = NULL;
@@ -1818,6 +1902,7 @@ gst_msdkdec_init (GstMsdkDec * thiz)
   thiz->do_renego = TRUE;
   thiz->do_realloc = TRUE;
   thiz->force_reset_on_res_change = TRUE;
+  thiz->report_error = FALSE;
   thiz->adapter = gst_adapter_new ();
   thiz->input_state = NULL;
   thiz->pool = NULL;
index 7bde77d..638edfb 100644 (file)
@@ -99,10 +99,15 @@ struct _GstMsdkDec
 
   /* element properties */
   gboolean hardware;
+  gboolean report_error;
   guint async_depth;
 
   mfxExtBuffer *bs_extra_params[MAX_BS_EXTRA_PARAMS];
   guint num_bs_extra_params;
+
+#if (MFX_VERSION >= 1025)
+  mfxExtDecodeErrorReport error_report;
+#endif
 };
 
 struct _GstMsdkDecClass
index 5efb0de..f77e22f 100644 (file)
@@ -42,6 +42,16 @@ gst_msdkdec_prop_install_output_oder_property (GObjectClass * gobject_class)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
+void
+gst_msdkdec_prop_install_error_report_property (GObjectClass * gobject_class)
+{
+  g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_ERROR_REPORT,
+      g_param_spec_boolean ("report-error", "report-error",
+          "Report bitstream error information",
+          PROP_ERROR_REPORT_DEFAULT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
 gboolean
 gst_msdkdec_prop_check_state (GstState state, GParamSpec * pspec)
 {
index d24abd1..5ca887e 100644 (file)
@@ -37,6 +37,7 @@
 G_BEGIN_DECLS
 
 #define PROP_OUTPUT_ORDER_DEFAULT        GST_MSDKDEC_OUTPUT_ORDER_DISPLAY
+#define PROP_ERROR_REPORT_DEFAULT        FALSE
 
 enum
 {
@@ -44,11 +45,15 @@ enum
   GST_MSDKDEC_PROP_HARDWARE,
   GST_MSDKDEC_PROP_ASYNC_DEPTH,
   GST_MSDKDEC_PROP_OUTPUT_ORDER,
+  GST_MSDKDEC_PROP_ERROR_REPORT,
 };
 
 void
 gst_msdkdec_prop_install_output_oder_property(GObjectClass * gobject_class);
 
+void
+gst_msdkdec_prop_install_error_report_property (GObjectClass * gobject_class);
+
 gboolean
 gst_msdkdec_prop_check_state(GstState state, GParamSpec * pspec);
 
index caeda8e..9b66126 100644 (file)
@@ -61,6 +61,17 @@ gst_msdkh264dec_configure (GstMsdkDec * decoder)
    * customers still using this for low-latency streaming of non-b-frame
    * encoded streams */
   decoder->param.mfx.DecodedOrder = h264dec->output_order;
+
+#if (MFX_VERSION >= 1025)
+  if (decoder->report_error) {
+    decoder->error_report.Header.BufferId = MFX_EXTBUFF_DECODE_ERROR_REPORT;
+    decoder->error_report.Header.BufferSz = sizeof (decoder->error_report);
+    decoder->error_report.ErrorTypes = 0;
+    gst_msdkdec_add_bs_extra_param (decoder,
+        (mfxExtBuffer *) & decoder->error_report);
+  }
+#endif
+
   return TRUE;
 }
 
@@ -69,6 +80,9 @@ gst_msdkdec_h264_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
   GstMsdkH264Dec *thiz = GST_MSDKH264DEC (object);
+#if (MFX_VERSION >= 1025)
+  GstMsdkDec *dec = GST_MSDKDEC (object);
+#endif
   GstState state;
 
   GST_OBJECT_LOCK (thiz);
@@ -83,6 +97,11 @@ gst_msdkdec_h264_set_property (GObject * object, guint prop_id,
     case GST_MSDKDEC_PROP_OUTPUT_ORDER:
       thiz->output_order = g_value_get_enum (value);
       break;
+#if (MFX_VERSION >= 1025)
+    case GST_MSDKDEC_PROP_ERROR_REPORT:
+      dec->report_error = g_value_get_boolean (value);
+      break;
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -96,12 +115,20 @@ gst_msdkdec_h264_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
 {
   GstMsdkH264Dec *thiz = GST_MSDKH264DEC (object);
+#if (MFX_VERSION >= 1025)
+  GstMsdkDec *dec = GST_MSDKDEC (object);
+#endif
 
   GST_OBJECT_LOCK (thiz);
   switch (prop_id) {
     case GST_MSDKDEC_PROP_OUTPUT_ORDER:
       g_value_set_enum (value, thiz->output_order);
       break;
+#if (MFX_VERSION >= 1025)
+    case GST_MSDKDEC_PROP_ERROR_REPORT:
+      g_value_set_boolean (value, dec->report_error);
+      break;
+#endif
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -133,6 +160,10 @@ gst_msdkh264dec_class_init (GstMsdkH264DecClass * klass)
 
   gst_msdkdec_prop_install_output_oder_property (gobject_class);
 
+#if (MFX_VERSION >= 1025)
+  gst_msdkdec_prop_install_error_report_property (gobject_class);
+#endif
+
   gst_element_class_add_static_pad_template (element_class, &sink_factory);
 }