From 0aa4c9db4e3263c1cc70eb871a9d30b330c98e61 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 28 Mar 2017 16:27:10 +0200 Subject: [PATCH] h264dec: add hack to pass profile and level to OMX This information can be useful to zynqultrascaleplus decoders. They may use this information to reduce startup latency by configuring itself before receiving the first frames. We also have a custom OMX extension allowing the decoder to report the latency. The profile/level information helps it reporting a more accurate latency earlier. https://bugzilla.gnome.org/show_bug.cgi?id=783114 --- config/zynqultrascaleplus/gstomx.conf | 2 +- omx/gstomx.c | 2 + omx/gstomx.h | 7 +++ omx/gstomxh264dec.c | 73 +++++++++++++++++++++++++-- 4 files changed, 80 insertions(+), 4 deletions(-) diff --git a/config/zynqultrascaleplus/gstomx.conf b/config/zynqultrascaleplus/gstomx.conf index 5231e46fbb..6850e1da8f 100644 --- a/config/zynqultrascaleplus/gstomx.conf +++ b/config/zynqultrascaleplus/gstomx.conf @@ -14,4 +14,4 @@ component-name=OMX.allegro.h264.decoder in-port-index=0 out-port-index=1 rank=257 -hacks=no-disable-outport +hacks=no-disable-outport;pass-profile-to-decoder diff --git a/omx/gstomx.c b/omx/gstomx.c index 17c76c308b..507aa9b436 100644 --- a/omx/gstomx.c +++ b/omx/gstomx.c @@ -2508,6 +2508,8 @@ gst_omx_parse_hacks (gchar ** hacks) hacks_flags |= GST_OMX_HACK_SIGNALS_PREMATURE_EOS; else if (g_str_equal (*hacks, "height-multiple-16")) hacks_flags |= GST_OMX_HACK_HEIGHT_MULTIPLE_16; + else if (g_str_equal (*hacks, "pass-profile-to-decoder")) + hacks_flags |= GST_OMX_HACK_PASS_PROFILE_TO_DECODER; else GST_WARNING ("Unknown hack: %s", *hacks); hacks++; diff --git a/omx/gstomx.h b/omx/gstomx.h index 74357f8011..07417a9682 100644 --- a/omx/gstomx.h +++ b/omx/gstomx.h @@ -150,6 +150,13 @@ G_BEGIN_DECLS */ #define GST_OMX_HACK_HEIGHT_MULTIPLE_16 G_GUINT64_CONSTANT (0x0000000000000200) +/* If we should pass the profile/level information from upstream to the + * OMX decoder. This is a violation of the OMX spec as + * OMX_IndexParamVideoProfileLevelCurrent is supposed to be r-o so + * do it as a platform specific hack. + */ +#define GST_OMX_HACK_PASS_PROFILE_TO_DECODER G_GUINT64_CONSTANT (0x0000000000000800) + typedef struct _GstOMXCore GstOMXCore; typedef struct _GstOMXPort GstOMXPort; typedef enum _GstOMXPortDirection GstOMXPortDirection; diff --git a/omx/gstomxh264dec.c b/omx/gstomxh264dec.c index 800c744df0..c9e5c9ecf7 100644 --- a/omx/gstomxh264dec.c +++ b/omx/gstomxh264dec.c @@ -25,6 +25,7 @@ #include #include "gstomxh264dec.h" +#include "gstomxh264utils.h" GST_DEBUG_CATEGORY_STATIC (gst_omx_h264_dec_debug_category); #define GST_CAT_DEFAULT gst_omx_h264_dec_debug_category @@ -110,16 +111,82 @@ gst_omx_h264_dec_is_format_change (GstOMXVideoDec * dec, return FALSE; } +static gboolean +set_profile_and_level (GstOMXH264Dec * self, GstVideoCodecState * state) +{ + OMX_ERRORTYPE err; + OMX_VIDEO_PARAM_PROFILELEVELTYPE param; + const gchar *profile_string, *level_string; + GstStructure *s; + + GST_OMX_INIT_STRUCT (¶m); + param.nPortIndex = GST_OMX_VIDEO_DEC (self)->dec_in_port->index; + + /* Pass profile and level to the decoder if we have both info from the + * caps. */ + s = gst_caps_get_structure (state->caps, 0); + profile_string = gst_structure_get_string (s, "profile"); + if (!profile_string) + return TRUE; + + param.eProfile = gst_omx_h264_utils_get_profile_from_str (profile_string); + if (param.eProfile == OMX_VIDEO_AVCProfileMax) + goto unsupported_profile; + + level_string = gst_structure_get_string (s, "level"); + if (!level_string) + return TRUE; + + param.eLevel = gst_omx_h264_utils_get_level_from_str (level_string); + if (param.eLevel == OMX_VIDEO_AVCLevelMax) + goto unsupported_level; + + GST_DEBUG_OBJECT (self, "Set profile (%s) and level (%s) on decoder", + profile_string, level_string); + + err = + gst_omx_component_set_parameter (GST_OMX_VIDEO_DEC (self)->dec, + OMX_IndexParamVideoProfileLevelCurrent, ¶m); + if (err == OMX_ErrorUnsupportedIndex) { + GST_WARNING_OBJECT (self, + "Setting profile/level not supported by component"); + } else if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "Error setting profile %u and level %u: %s (0x%08x)", + (guint) param.eProfile, (guint) param.eLevel, + gst_omx_error_to_string (err), err); + return FALSE; + } + + return TRUE; + +unsupported_profile: + GST_ERROR_OBJECT (self, "Unsupported profile %s", profile_string); + return FALSE; + +unsupported_level: + GST_ERROR_OBJECT (self, "Unsupported level %s", level_string); + return FALSE; +} + static gboolean gst_omx_h264_dec_set_format (GstOMXVideoDec * dec, GstOMXPort * port, GstVideoCodecState * state) { - gboolean ret; + GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (dec); OMX_PARAM_PORTDEFINITIONTYPE port_def; + OMX_ERRORTYPE err; gst_omx_port_get_port_definition (port, &port_def); port_def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; - ret = gst_omx_port_update_port_definition (port, &port_def) == OMX_ErrorNone; + err = gst_omx_port_update_port_definition (port, &port_def); + if (err != OMX_ErrorNone) + return FALSE; - return ret; + if (klass->cdata.hacks & GST_OMX_HACK_PASS_PROFILE_TO_DECODER) { + if (!set_profile_and_level (GST_OMX_H264_DEC (dec), state)) + return FALSE; + } + + return TRUE; }