msdkh264dec: report error to user

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>
This commit is contained in:
Haihao Xiang 2019-12-06 12:48:37 +08:00 committed by GStreamer Marge Bot
parent b6eca79557
commit 5d891eb40c
5 changed files with 136 additions and 0 deletions

View 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;

View 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

View 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)
{

View 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);

View 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);
}