avviddec: Expose std-compliance option
authorSeungha Yang <seungha@centricular.com>
Tue, 1 Nov 2022 13:35:11 +0000 (09:35 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 2 Nov 2022 19:23:14 +0000 (19:23 +0000)
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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3311>

subprojects/gst-libav/ext/libav/gstavutils.c
subprojects/gst-libav/ext/libav/gstavutils.h
subprojects/gst-libav/ext/libav/gstavviddec.c
subprojects/gst-libav/ext/libav/gstavviddec.h

index f3878c3..7f4409d 100644 (file)
@@ -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;
+}
index 7b41b66..fab7969 100644 (file)
@@ -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__ */
index dd8c615..dac01f5 100644 (file)
@@ -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;
index 92789b9..d3b5544 100644 (file)
@@ -69,6 +69,7 @@ struct _GstFFMpegVidDec
   int max_threads;
   gboolean output_corrupt;
   guint thread_type;
+  GstAvCodecCompliance std_compliance;
 
   GstCaps *last_caps;