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
This commit is contained in:
Gwenole Beauchesne 2014-01-10 18:18:25 +01:00
parent 2b482e8e4b
commit b59a5572af
3 changed files with 77 additions and 104 deletions

View file

@ -209,96 +209,52 @@ ensure_profile (GstVaapiEncoderH264 * encoder)
{ {
GstVaapiProfile profile; 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 = profile;
encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
return TRUE; return TRUE;
} }
static void static gboolean
_set_level (GstVaapiEncoderH264 * encoder) ensure_level (GstVaapiEncoderH264 * encoder)
{ {
guint pic_mb_size; const guint bitrate = GST_VAAPI_ENCODER_CAST (encoder)->bitrate;
guint MaxDpbMbs, MaxMBPS; const GstVaapiH264LevelLimits *limits_table;
guint dbp_level, mbps_level, profile_level; guint i, num_limits, PicSizeMbs, MaxDpbMbs, MaxMBPS;
if (encoder->level_idc) { PicSizeMbs = encoder->mb_width * encoder->mb_height;
if (encoder->level_idc < GST_VAAPI_ENCODER_H264_LEVEL_10) MaxDpbMbs = PicSizeMbs * ((encoder->num_bframes) ? 2 : 1);
encoder->level_idc = GST_VAAPI_ENCODER_H264_LEVEL_10; MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs,
else if (encoder->level_idc > GST_VAAPI_ENCODER_H264_LEVEL_51) GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder));
encoder->level_idc = GST_VAAPI_ENCODER_H264_LEVEL_51;
return; 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 */ encoder->level = limits_table[i].level;
pic_mb_size = ((GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16) * encoder->level_idc = limits_table[i].level_idc;
((GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16); return TRUE;
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 */ /* ERRORS */
if (MaxDpbMbs > 110400) error_unsupported_level:
dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_51; {
else if (MaxDpbMbs > 34816) GST_ERROR ("failed to find a suitable level matching codec config");
dbp_level = GST_VAAPI_ENCODER_H264_LEVEL_50; return FALSE;
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_idc = (dbp_level > mbps_level ? dbp_level : mbps_level);
if (encoder->level_idc < profile_level)
encoder->level_idc = profile_level;
} }
static inline void 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_pred_flag = FALSE;
pic_param->pic_fields.bits.weighted_bipred_idc = 0; pic_param->pic_fields.bits.weighted_bipred_idc = 0;
pic_param->pic_fields.bits.constrained_intra_pred_flag = 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 */ /* enable debloking */
pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE; pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE;
pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE; 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)) if (!ensure_profile (encoder))
return FALSE; return FALSE;
if (!ensure_level (encoder))
_set_level (encoder); return FALSE;
return TRUE; return TRUE;
} }
@ -1831,3 +1787,32 @@ gst_vaapi_encoder_h264_get_default_properties (void)
return props; 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;
}

View file

@ -23,6 +23,7 @@
#define GST_VAAPI_ENCODER_H264_H #define GST_VAAPI_ENCODER_H264_H
#include <gst/vaapi/gstvaapiencoder.h> #include <gst/vaapi/gstvaapiencoder.h>
#include <gst/vaapi/gstvaapiutils_h264.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -54,6 +55,10 @@ gst_vaapi_encoder_h264_new (GstVaapiDisplay * display);
GPtrArray * GPtrArray *
gst_vaapi_encoder_h264_get_default_properties (void); 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 G_END_DECLS
#endif /*GST_VAAPI_ENCODER_H264_H */ #endif /*GST_VAAPI_ENCODER_H264_H */

View file

@ -23,32 +23,13 @@
#define GST_VAAPI_ENCODER_H264_PRIV_H #define GST_VAAPI_ENCODER_H264_PRIV_H
#include "gstvaapiencoder_priv.h" #include "gstvaapiencoder_priv.h"
#include "gstvaapiutils_h264.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define GST_VAAPI_ENCODER_H264_CAST(encoder) \ #define GST_VAAPI_ENCODER_H264_CAST(encoder) \
((GstVaapiEncoderH264 *)(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 #define GST_VAAPI_ENCODER_H264_MAX_IDR_PERIOD 512
struct _GstVaapiEncoderH264 struct _GstVaapiEncoderH264
@ -56,7 +37,9 @@ struct _GstVaapiEncoderH264
GstVaapiEncoder parent_instance; GstVaapiEncoder parent_instance;
GstVaapiProfile profile; GstVaapiProfile profile;
guint32 level_idc; GstVaapiLevelH264 level;
guint8 profile_idc;
guint8 level_idc;
guint32 idr_period; guint32 idr_period;
guint32 init_qp; guint32 init_qp;
guint32 min_qp; guint32 min_qp;