h264encoder: calculate level_idc according pic size
authorWind Yuan <feng.yuan@intel.com>
Fri, 15 Mar 2013 07:48:38 +0000 (15:48 +0800)
committerWind Yuan <feng.yuan@intel.com>
Fri, 22 Mar 2013 01:59:17 +0000 (09:59 +0800)
gst-libs/gst/vaapi/gstvaapiencoder_h264.c

index b98ff47..6e6d92e 100644 (file)
@@ -68,6 +68,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encoder_debug);
 #define NAL_REF_IDC_MEDIUM      2
 #define NAL_REF_IDC_HIGH        3
 
+#define GST_VAAPI_H264_MAX_REFERENCE_NUM 2
 
 typedef enum {
   NAL_UNKNOWN     = 0,
@@ -258,6 +259,82 @@ gst_vaapi_encoder_h264_get_avc_flag(GstVaapiEncoderH264* encoder)
   return priv->avc_flag;
 }
 
+static void
+_ensure_level(GstVaapiEncoderH264* encoder)
+{
+  guint pic_mb_size;
+  guint MaxDpbMbs, MaxMBPS;
+  guint dbp_level, mbps_level;
+
+  if (encoder->level) {
+    if (encoder->level < H264_LEVEL_10)
+      encoder->level = H264_LEVEL_10;
+    else if (encoder->level > H264_LEVEL_51)
+      encoder->level = H264_LEVEL_51;
+    return;
+  }
+
+  /* calculate level */
+  pic_mb_size = ((ENCODER_WIDTH(encoder)+15)/16) *
+                ((ENCODER_HEIGHT(encoder)+15)/16);
+  MaxDpbMbs = pic_mb_size * GST_VAAPI_H264_MAX_REFERENCE_NUM;
+  MaxMBPS = pic_mb_size * ENCODER_FPS(encoder);
+
+  /* calculate from MaxDbpMbs */
+  if (MaxDpbMbs > 110400)
+    dbp_level = H264_LEVEL_51;
+  else if (MaxDpbMbs > 34816)
+    dbp_level = H264_LEVEL_50;
+  else if (MaxDpbMbs > 32768)
+    dbp_level = H264_LEVEL_42;
+  else if (MaxDpbMbs > 20480) /* 41 or 40 */
+    dbp_level = H264_LEVEL_41;
+  else if (MaxDpbMbs > 18000)
+    dbp_level = H264_LEVEL_32;
+  else if (MaxDpbMbs > 8100)
+    dbp_level = H264_LEVEL_31;
+  else if (MaxDpbMbs > 4752) /* 30 or 22 */
+    dbp_level = H264_LEVEL_30;
+  else if (MaxDpbMbs > 2376)
+    dbp_level = H264_LEVEL_21;
+  else if (MaxDpbMbs > 900) /* 20, 13, 12 */
+    dbp_level = H264_LEVEL_20;
+  else if (MaxDpbMbs > 396)
+    dbp_level = H264_LEVEL_11;
+  else
+    dbp_level = H264_LEVEL_10;
+
+  /* calculate from Max Mb processing rate */
+  if (MaxMBPS > 589824)
+    mbps_level = H264_LEVEL_51;
+  else if (MaxMBPS > 522240)
+    mbps_level = H264_LEVEL_50;
+  else if (MaxMBPS > 245760)
+    mbps_level = H264_LEVEL_42;
+  else if (MaxMBPS > 216000) /* 40 or 41 */
+    mbps_level = H264_LEVEL_41;
+  else if (MaxMBPS > 108000)
+    mbps_level = H264_LEVEL_32;
+  else if (MaxMBPS > 40500)
+    mbps_level = H264_LEVEL_31;
+  else if (MaxMBPS > 20250)
+    mbps_level = H264_LEVEL_30;
+  else if (MaxMBPS > 19800)
+    mbps_level = H264_LEVEL_22;
+  else if (MaxMBPS > 11800)
+    mbps_level = H264_LEVEL_21;
+  else if (MaxMBPS > 6000) /*13 or 20 */
+    mbps_level = H264_LEVEL_20;
+  else if (MaxMBPS > 3000)
+    mbps_level = H264_LEVEL_12;
+  else if (MaxMBPS > 1485)
+    mbps_level = H264_LEVEL_11;
+  else
+    mbps_level = H264_LEVEL_10;
+
+  encoder->level = (dbp_level > mbps_level ? dbp_level : mbps_level);
+}
+
 gboolean
 gst_vaapi_encoder_h264_validate_attributes(GstVaapiBaseEncoder *base)
 {
@@ -272,12 +349,9 @@ gst_vaapi_encoder_h264_validate_attributes(GstVaapiBaseEncoder *base)
     encoder->profile = H264_DEFAULT_PROFILE;
   }
   gst_vaapi_base_encoder_set_va_profile(base, h264_get_va_profile(encoder->profile));
-  if (!encoder->level) {
-    if (encoder->profile <= H264_PROFILE_BASELINE)
-      encoder->level = H264_LEVEL_31;
-    else
-      encoder->level = H264_LEVEL_41;
-  }
+
+  _ensure_level(encoder);
+
   if (!encoder->intra_period) {
     encoder->intra_period = H264_DEFAULT_INTRA_PERIOD;
   }
@@ -686,6 +760,22 @@ set_slices_parameters(
 
 #else  /* extended libva, new parameter structures*/
 
+static guint
+_get_log2_max_frame_num_minus4(guint num)
+{
+    guint ret = 0;
+
+    while (num) {
+        ++ret;
+        num >>= 1;
+    }
+    if (ret <= 4)
+        ret = 4;
+    else if (ret > 9)
+        ret = 9;
+    return (ret -4);
+}
+
 static gboolean
 set_sequence_parameters(
     GstVaapiEncoderH264 *encoder,
@@ -707,8 +797,7 @@ set_sequence_parameters(
   else
       seq_param->bits_per_second = 0;
 
-  seq_param->max_num_ref_frames =
-      (encoder->b_frame_num < 2 ? 3 : encoder->b_frame_num+1);  // ?, why 4
+  seq_param->max_num_ref_frames = GST_VAAPI_H264_MAX_REFERENCE_NUM;
   seq_param->picture_width_in_mbs = width_in_mbs;
   seq_param->picture_height_in_mbs = height_in_mbs;
 
@@ -720,11 +809,12 @@ set_sequence_parameters(
   seq_param->seq_fields.bits.seq_scaling_matrix_present_flag = FALSE;
   /* direct_8x8_inference_flag default false */
   seq_param->seq_fields.bits.direct_8x8_inference_flag = FALSE;
-  seq_param->seq_fields.bits.log2_max_frame_num_minus4 = 4; // log2(seq.intra_period)-3 : 0
+  seq_param->seq_fields.bits.log2_max_frame_num_minus4
+      = _get_log2_max_frame_num_minus4(encoder->intra_period);
   /* picture order count */
   seq_param->seq_fields.bits.pic_order_cnt_type = 0;
   seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 =
-        seq_param->seq_fields.bits.log2_max_frame_num_minus4 + 2;
+        seq_param->seq_fields.bits.log2_max_frame_num_minus4 + 1;
   seq_param->seq_fields.bits.delta_pic_order_always_zero_flag = TRUE;
 
   priv->max_frame_num =