encoder: h264: derive profile and level from active coding tools.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 10 Jan 2014 17:18:25 +0000 (18:18 +0100)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 13 Jan 2014 16:31:55 +0000 (17:31 +0100)
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
gst-libs/gst/vaapi/gstvaapiencoder_h264.h
gst-libs/gst/vaapi/gstvaapiencoder_h264_priv.h

index 16dcb64..2f4ed92 100644 (file)
@@ -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;
+}
index f02e40e..7d5f053 100644 (file)
@@ -23,6 +23,7 @@
 #define GST_VAAPI_ENCODER_H264_H
 
 #include <gst/vaapi/gstvaapiencoder.h>
+#include <gst/vaapi/gstvaapiutils_h264.h>
 
 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 */
index a2eb65b..bf9958a 100644 (file)
 #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;