From b59a5572af08c1ce504232d3a9eed0cbf0cecec5 Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Fri, 10 Jan 2014 18:18:25 +0100 Subject: [PATCH] encoder: h264: derive profile and level from active coding tools. Automatically derive the minimum profile and level to be used for encoding, based on the activated coding tools. The encoder will be trying to generate a bitstream that has the best chances to be decoded on most platforms by default. Also change the default profile to "constrained-baseline" so that to ensure maximum compatibility when the stream is decoded. https://bugzilla.gnome.org/show_bug.cgi?id=719691 --- gst-libs/gst/vaapi/gstvaapiencoder_h264.c | 153 +++++++++++-------------- gst-libs/gst/vaapi/gstvaapiencoder_h264.h | 5 + gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h | 25 +--- 3 files changed, 78 insertions(+), 105 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c index 16dcb64..2f4ed92 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c @@ -209,96 +209,52 @@ ensure_profile (GstVaapiEncoderH264 * encoder) { GstVaapiProfile profile; - profile = GST_VAAPI_PROFILE_H264_BASELINE; + /* Always start from "constrained-baseline" profile for maximum + compatibility */ + profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE; + + /* Main profile coding tools */ + if (encoder->num_bframes > 0) + profile = GST_VAAPI_PROFILE_H264_MAIN; encoder->profile = profile; + encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile); return TRUE; } -static void -_set_level (GstVaapiEncoderH264 * encoder) +static gboolean +ensure_level (GstVaapiEncoderH264 * encoder) { - guint pic_mb_size; - guint MaxDpbMbs, MaxMBPS; - guint dbp_level, mbps_level, profile_level; - - if (encoder->level_idc) { - if (encoder->level_idc < GST_VAAPI_ENCODER_H264_LEVEL_10) - encoder->level_idc = GST_VAAPI_ENCODER_H264_LEVEL_10; - else if (encoder->level_idc > GST_VAAPI_ENCODER_H264_LEVEL_51) - encoder->level_idc = GST_VAAPI_ENCODER_H264_LEVEL_51; - return; + const guint bitrate = GST_VAAPI_ENCODER_CAST (encoder)->bitrate; + const GstVaapiH264LevelLimits *limits_table; + guint i, num_limits, PicSizeMbs, MaxDpbMbs, MaxMBPS; + + PicSizeMbs = encoder->mb_width * encoder->mb_height; + MaxDpbMbs = PicSizeMbs * ((encoder->num_bframes) ? 2 : 1); + MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs, + GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder)); + + limits_table = gst_vaapi_utils_h264_get_level_limits_table (&num_limits); + for (i = 0; i < num_limits; i++) { + const GstVaapiH264LevelLimits *const limits = &limits_table[i]; + if (PicSizeMbs <= limits->MaxFS && + MaxDpbMbs <= limits->MaxDpbMbs && + MaxMBPS <= limits->MaxMBPS && (!bitrate || bitrate <= limits->MaxBR)) + break; } + if (i == num_limits) + goto error_unsupported_level; - /* calculate level */ - pic_mb_size = ((GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16) * - ((GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16); - MaxDpbMbs = pic_mb_size * ((encoder->num_bframes) ? 2 : 1); - MaxMBPS = pic_mb_size * GST_VAAPI_ENCODER_FPS_N (encoder) / - GST_VAAPI_ENCODER_FPS_D (encoder); - - /* calculate from MaxDbpMbs */ - if (MaxDpbMbs > 110400) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_51; - else if (MaxDpbMbs > 34816) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_50; - else if (MaxDpbMbs > 32768) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_42; - else if (MaxDpbMbs > 20480) /* 41 or 40 */ - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_41; - else if (MaxDpbMbs > 18000) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_32; - else if (MaxDpbMbs > 8100) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_31; - else if (MaxDpbMbs > 4752) /* 30 or 22 */ - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_30; - else if (MaxDpbMbs > 2376) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_21; - else if (MaxDpbMbs > 900) /* 20, 13, 12 */ - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_20; - else if (MaxDpbMbs > 396) - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_11; - else - dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_10; - - /* calculate from Max Mb processing rate */ - if (MaxMBPS > 589824) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_51; - else if (MaxMBPS > 522240) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_50; - else if (MaxMBPS > 245760) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_42; - else if (MaxMBPS > 216000) /* 40 or 41 */ - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_41; - else if (MaxMBPS > 108000) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_32; - else if (MaxMBPS > 40500) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_31; - else if (MaxMBPS > 20250) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_30; - else if (MaxMBPS > 19800) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_22; - else if (MaxMBPS > 11800) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_21; - else if (MaxMBPS > 6000) /*13 or 20 */ - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_20; - else if (MaxMBPS > 3000) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_12; - else if (MaxMBPS > 1485) - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_11; - else - mbps_level = GST_VAAPI_ENCODER_H264_LEVEL_10; - - if (encoder->profile == GST_VAAPI_PROFILE_H264_HIGH) - profile_level = GST_VAAPI_ENCODER_H264_LEVEL_41; - else if (encoder->profile == GST_VAAPI_PROFILE_H264_MAIN) - profile_level = GST_VAAPI_ENCODER_H264_LEVEL_30; - else - profile_level = GST_VAAPI_ENCODER_H264_LEVEL_20; + encoder->level = limits_table[i].level; + encoder->level_idc = limits_table[i].level_idc; + return TRUE; - encoder->level_idc = (dbp_level > mbps_level ? dbp_level : mbps_level); - if (encoder->level_idc < profile_level) - encoder->level_idc = profile_level; + /* ERRORS */ +error_unsupported_level: + { + GST_ERROR ("failed to find a suitable level matching codec config"); + return FALSE; + } } static inline void @@ -1015,7 +971,7 @@ fill_va_picture_param (GstVaapiEncoderH264 * encoder, pic_param->pic_fields.bits.weighted_pred_flag = FALSE; pic_param->pic_fields.bits.weighted_bipred_idc = 0; pic_param->pic_fields.bits.constrained_intra_pred_flag = 0; - pic_param->pic_fields.bits.transform_8x8_mode_flag = (encoder->profile >= GST_VAAPI_PROFILE_H264_HIGH); /* enable 8x8 */ + pic_param->pic_fields.bits.transform_8x8_mode_flag = (encoder->profile_idc >= 100); /* enable 8x8 */ /* enable debloking */ pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE; pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE; @@ -1282,8 +1238,8 @@ ensure_profile_and_level (GstVaapiEncoderH264 * encoder) { if (!ensure_profile (encoder)) return FALSE; - - _set_level (encoder); + if (!ensure_level (encoder)) + return FALSE; return TRUE; } @@ -1831,3 +1787,32 @@ gst_vaapi_encoder_h264_get_default_properties (void) return props; } + +/** + * gst_vaapi_encoder_h264_get_profile_and_level: + * @encoder: a #GstVaapiEncoderH264 + * @out_profile_ptr: return location for the #GstVaapiProfile + * @out_level_ptr: return location for the #GstVaapiLevelH264 + * + * Queries the H.264 @encoder for the active profile and level. That + * information is only constructed and valid after the encoder is + * configured, i.e. after the gst_vaapi_encoder_set_codec_state() + * function is called. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_encoder_h264_get_profile_and_level (GstVaapiEncoderH264 * encoder, + GstVaapiProfile * out_profile_ptr, GstVaapiLevelH264 * out_level_ptr) +{ + g_return_val_if_fail (encoder != NULL, FALSE); + + if (!encoder->profile || !encoder->level) + return FALSE; + + if (out_profile_ptr) + *out_profile_ptr = encoder->profile; + if (out_level_ptr) + *out_level_ptr = encoder->level; + return TRUE; +} diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.h b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h index f02e40e..7d5f053 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.h @@ -23,6 +23,7 @@ #define GST_VAAPI_ENCODER_H264_H #include +#include G_BEGIN_DECLS @@ -54,6 +55,10 @@ gst_vaapi_encoder_h264_new (GstVaapiDisplay * display); GPtrArray * gst_vaapi_encoder_h264_get_default_properties (void); +gboolean +gst_vaapi_encoder_h264_get_profile_and_level (GstVaapiEncoderH264 * encoder, + GstVaapiProfile * out_profile_ptr, GstVaapiLevelH264 * out_level_ptr); + G_END_DECLS #endif /*GST_VAAPI_ENCODER_H264_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h b/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h index a2eb65b..bf9958a 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h @@ -23,32 +23,13 @@ #define GST_VAAPI_ENCODER_H264_PRIV_H #include "gstvaapiencoder_priv.h" +#include "gstvaapiutils_h264.h" G_BEGIN_DECLS #define GST_VAAPI_ENCODER_H264_CAST(encoder) \ ((GstVaapiEncoderH264 *)(encoder)) -typedef enum -{ - GST_VAAPI_ENCODER_H264_LEVEL_10 = 10, /* QCIF format, < 380160 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_11 = 11, /* CIF format, < 768000 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_12 = 12, /* CIF format, < 1536000 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_13 = 13, /* CIF format, < 3041280 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_20 = 20, /* CIF format, < 3041280 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_21 = 21, /* HHR format, < 5068800 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_22 = 22, /* SD/4CIF format, < 5184000 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_30 = 30, /* SD/4CIF format, < 10368000 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_31 = 31, /* 720pHD format, < 27648000 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_32 = 32, /* SXGA format, < 55296000 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_40 = 40, /* 2Kx1K format, < 62914560 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_41 = 41, /* 2Kx1K format, < 62914560 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_42 = 42, /* 2Kx1K format, < 125829120 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_50 = 50, /* 3672x1536 format, < 150994944 samples/sec */ - GST_VAAPI_ENCODER_H264_LEVEL_51 = 51, /* 4096x2304 format, < 251658240 samples/sec */ -} GstVaapiEncoderH264Level; - -#define GST_VAAPI_ENCODER_H264_DEFAULT_LEVEL GST_VAAPI_ENCODER_H264_LEVEL_31 #define GST_VAAPI_ENCODER_H264_MAX_IDR_PERIOD 512 struct _GstVaapiEncoderH264 @@ -56,7 +37,9 @@ struct _GstVaapiEncoderH264 GstVaapiEncoder parent_instance; GstVaapiProfile profile; - guint32 level_idc; + GstVaapiLevelH264 level; + guint8 profile_idc; + guint8 level_idc; guint32 idr_period; guint32 init_qp; guint32 min_qp; -- 2.7.4