From af05abdb798e6b0615179238fc04faf8e6e3fa90 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Tue, 1 Nov 2022 09:35:11 -0400 Subject: [PATCH] avviddec: Expose std-compliance option Default compliance mode (i.e., FF_COMPLIANCE_NORMAL) might not strictly follow specification. This property will allow user to specifiy expected compliance mode. Part-of: --- subprojects/gst-libav/ext/libav/gstavutils.c | 35 ++++++++++++++++ subprojects/gst-libav/ext/libav/gstavutils.h | 14 +++++++ subprojects/gst-libav/ext/libav/gstavviddec.c | 58 +++++++++++++++++++++------ subprojects/gst-libav/ext/libav/gstavviddec.h | 1 + 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/subprojects/gst-libav/ext/libav/gstavutils.c b/subprojects/gst-libav/ext/libav/gstavutils.c index f3878c3..7f4409d 100644 --- a/subprojects/gst-libav/ext/libav/gstavutils.c +++ b/subprojects/gst-libav/ext/libav/gstavutils.c @@ -493,3 +493,38 @@ gst_ffmpeg_auto_max_threads (void) return (int) (n_threads); } + + +GType +gst_av_codec_compliance_get_type (void) +{ + static gsize compliance_type = 0; + + if (g_once_init_enter (&compliance_type)) { + static const GEnumValue types[] = { + {GST_AV_CODEC_COMPLIANCE_AUTO, + "The decoder automatically decides. If the pipeline is live, it will" + "use `normal` mode, and `strict` otherwise.", "auto"}, + {GST_AV_CODEC_COMPLIANCE_VERY_STRICT, + "VeryStrict: Strictly conform to an older more strict version " + "of the spec or reference software", "very-strict"}, + {GST_AV_CODEC_COMPLIANCE_STRICT, + "Strict: Strictly conform to all the things in the spec no matter " + "what consequences", "strict"}, + {GST_AV_CODEC_COMPLIANCE_NORMAL, "Normal", "normal"}, + {GST_AV_CODEC_COMPLIANCE_UNOFFICIAL, + "Unofficial: Allow unofficial extensions " + "(decoder will not differentiate this with \"normal\")", + "unofficial"}, + {GST_AV_CODEC_COMPLIANCE_EXPERIMENTAL, + "Experimental: Allow nonstandardized experimental things " + "(decoder will not differentiate this with \"normal\")", + "experimental"}, + {0, NULL, NULL}, + }; + GType tmp = g_enum_register_static ("GstAvCodecCompliance", types); + g_once_init_leave (&compliance_type, tmp); + } + + return (GType) compliance_type; +} diff --git a/subprojects/gst-libav/ext/libav/gstavutils.h b/subprojects/gst-libav/ext/libav/gstavutils.h index 7b41b66..fab7969 100644 --- a/subprojects/gst-libav/ext/libav/gstavutils.h +++ b/subprojects/gst-libav/ext/libav/gstavutils.h @@ -114,4 +114,18 @@ av_smp_format_depth(enum AVSampleFormat smp_fmt); GstBuffer * new_aligned_buffer (gint size); +typedef enum +{ + GST_AV_CODEC_COMPLIANCE_AUTO = G_MAXINT, + GST_AV_CODEC_COMPLIANCE_VERY_STRICT = FF_COMPLIANCE_VERY_STRICT, + GST_AV_CODEC_COMPLIANCE_STRICT = FF_COMPLIANCE_STRICT, + GST_AV_CODEC_COMPLIANCE_NORMAL = FF_COMPLIANCE_NORMAL, + GST_AV_CODEC_COMPLIANCE_UNOFFICIAL = FF_COMPLIANCE_UNOFFICIAL, + GST_AV_CODEC_COMPLIANCE_EXPERIMENTAL = FF_COMPLIANCE_EXPERIMENTAL, +} GstAvCodecCompliance; + +#define GST_TYPE_AV_CODEC_COMPLIANCE (gst_av_codec_compliance_get_type()) +GType gst_av_codec_compliance_get_type (void); + + #endif /* __GST_FFMPEG_UTILS_H__ */ diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.c b/subprojects/gst-libav/ext/libav/gstavviddec.c index dd8c615..dac01f5 100644 --- a/subprojects/gst-libav/ext/libav/gstavviddec.c +++ b/subprojects/gst-libav/ext/libav/gstavviddec.c @@ -48,6 +48,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); #define DEFAULT_STRIDE_ALIGN 31 #define DEFAULT_ALLOC_PARAM { 0, DEFAULT_STRIDE_ALIGN, 0, 0, } #define DEFAULT_THREAD_TYPE 0 +#define DEFAULT_STD_COMPLIANCE GST_AV_CODEC_COMPLIANCE_AUTO enum { @@ -59,6 +60,7 @@ enum PROP_MAX_THREADS, PROP_OUTPUT_CORRUPT, PROP_THREAD_TYPE, + PROP_STD_COMPLIANCE, PROP_LAST }; @@ -293,6 +295,18 @@ gst_ffmpegviddec_class_init (GstFFMpegVidDecClass * klass) DEFAULT_THREAD_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } + /** + * GstFFMpegVidDec::std-compliance: + * + * Specifies standard compliance mode to use + * + * Since: 1.20 + */ + g_object_class_install_property (gobject_class, PROP_STD_COMPLIANCE, + g_param_spec_enum ("std-compliance", "Standard Compliance", + "Standard compliance mode to use", GST_TYPE_AV_CODEC_COMPLIANCE, + DEFAULT_STD_COMPLIANCE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + viddec_class->set_format = gst_ffmpegviddec_set_format; viddec_class->handle_frame = gst_ffmpegviddec_handle_frame; viddec_class->start = gst_ffmpegviddec_start; @@ -308,6 +322,7 @@ gst_ffmpegviddec_class_init (GstFFMpegVidDecClass * klass) gst_type_mark_as_plugin_api (GST_FFMPEGVIDDEC_TYPE_LOWRES, 0); gst_type_mark_as_plugin_api (GST_FFMPEGVIDDEC_TYPE_SKIPFRAME, 0); gst_type_mark_as_plugin_api (GST_FFMPEGVIDDEC_TYPE_THREAD_TYPE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AV_CODEC_COMPLIANCE, 0); } static void @@ -492,6 +507,8 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder, GstFFMpegVidDecClass *oclass; GstClockTime latency = GST_CLOCK_TIME_NONE; gboolean ret = FALSE; + gboolean is_live; + GstQuery *query; ffmpegdec = (GstFFMpegVidDec *) decoder; oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); @@ -568,23 +585,21 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder, ffmpegdec->context->lowres = ffmpegdec->lowres; ffmpegdec->context->skip_frame = ffmpegdec->skip_frame; + + query = gst_query_new_latency (); + is_live = FALSE; + /* Check if upstream is live. If it isn't we can enable frame based + * threading, which is adding latency */ + if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (ffmpegdec), query)) { + gst_query_parse_latency (query, &is_live, NULL, NULL); + } + gst_query_unref (query); + if (ffmpegdec->thread_type) { GST_DEBUG_OBJECT (ffmpegdec, "Use requested thread type 0x%x", ffmpegdec->thread_type); ffmpegdec->context->thread_type = ffmpegdec->thread_type; } else { - GstQuery *query; - gboolean is_live; - - query = gst_query_new_latency (); - is_live = FALSE; - /* Check if upstream is live. If it isn't we can enable frame based - * threading, which is adding latency */ - if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (ffmpegdec), query)) { - gst_query_parse_latency (query, &is_live, NULL, NULL); - } - gst_query_unref (query); - if (is_live) ffmpegdec->context->thread_type = FF_THREAD_SLICE; else @@ -603,6 +618,19 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder, } else ffmpegdec->context->thread_count = ffmpegdec->max_threads; + if (ffmpegdec->std_compliance == GST_AV_CODEC_COMPLIANCE_AUTO) { + /* Normal yields lower latency, but fails some compliance check */ + if (is_live || ffmpegdec->context->thread_type == FF_THREAD_SLICE) { + ffmpegdec->context->strict_std_compliance = + GST_AV_CODEC_COMPLIANCE_NORMAL; + } else { + ffmpegdec->context->strict_std_compliance = + GST_AV_CODEC_COMPLIANCE_STRICT; + } + } else { + ffmpegdec->context->strict_std_compliance = ffmpegdec->std_compliance; + } + if (oclass->in_plugin->id == AV_CODEC_ID_H264) { GstStructure *s = gst_caps_get_structure (state->caps, 0); const char *alignment; @@ -2417,6 +2445,9 @@ gst_ffmpegviddec_set_property (GObject * object, case PROP_THREAD_TYPE: ffmpegdec->thread_type = g_value_get_flags (value); break; + case PROP_STD_COMPLIANCE: + ffmpegdec->std_compliance = g_value_get_enum (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2453,6 +2484,9 @@ gst_ffmpegviddec_get_property (GObject * object, case PROP_THREAD_TYPE: g_value_set_flags (value, ffmpegdec->thread_type); break; + case PROP_STD_COMPLIANCE: + g_value_set_enum (value, ffmpegdec->std_compliance); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.h b/subprojects/gst-libav/ext/libav/gstavviddec.h index 92789b9..d3b55448 100644 --- a/subprojects/gst-libav/ext/libav/gstavviddec.h +++ b/subprojects/gst-libav/ext/libav/gstavviddec.h @@ -69,6 +69,7 @@ struct _GstFFMpegVidDec int max_threads; gboolean output_corrupt; guint thread_type; + GstAvCodecCompliance std_compliance; GstCaps *last_caps; -- 2.7.4