support multiple h264 slices, auto calculate bitrate(=w*h*fps/4) add properties ...
authorWind Yuan <feng.yuan@intel.com>
Fri, 30 Sep 2011 06:33:44 +0000 (14:33 +0800)
committerZhong Cong <congx.zhong@intel.com>
Tue, 5 Feb 2013 07:37:10 +0000 (15:37 +0800)
gst/vaapiencode/gsth264encode.c
gst/vaapiencode/gsth264encode.h
gst/vaapiencode/h264encoder.c
gst/vaapiencode/h264encoder.h

index f355f92..b183605 100644 (file)
@@ -39,7 +39,6 @@ static const char gst_h264encode_sink_caps_str[] =
     GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { I420 } ")
     GST_CAPS_CODEC("video/x-raw-yuv, " "format = (fourcc) { NV12 } ")
     GST_CAPS_CODEC("video/x-vaapi-surface ")
-    GST_CAPS_CODEC("video/x-raw-va")
     ;
 
 static const char gst_h264encode_src_caps_str[] =
@@ -72,6 +71,8 @@ enum {
     PROP_BITRATE,
     PROP_INTRA_PERIOD,
     PROP_INIT_QP,
+    PROP_MIN_QP,
+    PROP_SLICE_NUM,
 };
 
 
@@ -138,18 +139,18 @@ gst_h264encode_class_init(GstH264EncodeClass *klass)
   g_object_class_install_property (object_class, PROP_LEVEL,
         g_param_spec_uint ("level",
             "H264 level idc",
-            "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51",
+            "Level idc supports: 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41",
             H264_LEVEL_10,
-            H264_LEVEL_51,
+            H264_LEVEL_41,
             H264_DEFAULT_LEVEL,
             G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_BITRATE,
         g_param_spec_uint ("bitrate",
             "H264 encoding bitrate",
-            "H264 encoding bitrate, 10k~100M",
-            10*1000,
+            "H264 encoding bitrate, 10k~100M, (0, auto-calculate)",
+            0,
             100*1000*1000,
-            H264_DEFAULT_BITRATE,
+            0,
             G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_INTRA_PERIOD,
         g_param_spec_uint ("intra-period",
@@ -167,6 +168,22 @@ gst_h264encode_class_init(GstH264EncodeClass *klass)
             51,
             H264_DEFAULT_INIT_QP,
             G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_MIN_QP,
+        g_param_spec_uint ("min-qp",
+            "H264 min-qp",
+            "H264 min-qp",
+            1,
+            51,
+            H264_DEFAULT_MIN_QP,
+            G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_SLICE_NUM,
+        g_param_spec_uint ("slice-num",
+            "H264 slice num",
+            "H264 slice num",
+            1,
+            200,
+            1,
+            G_PARAM_READWRITE));
 
   element_class->change_state = gst_h264encode_change_state;
 }
@@ -195,11 +212,6 @@ gst_h264encode_finalize(GObject *object)
       encode->encoder = NULL;
   }
 
-  if (encode->x_display) {
-    XCloseDisplay(encode->x_display);
-    encode->x_display = NULL;
-  }
-
   G_OBJECT_CLASS(parent_class)->finalize(object);
 }
 
@@ -212,7 +224,6 @@ gst_h264encode_init(GstH264Encode *encode, GstH264EncodeClass *klass)
   encode->srcpad_caps        = NULL;
   encode->first_sink_frame   = TRUE;
   encode->first_src_frame    = TRUE;
-  encode->x_display = NULL;
 
   encode->encoder = gst_h264_encoder_new();
   H264_ASSERT(encode->encoder);
@@ -286,6 +297,16 @@ gst_h264encode_set_property(GObject *object, guint prop_id,
     }
       break;
 
+    case PROP_MIN_QP: {
+      encode->encoder->min_qp = g_value_get_uint(value);
+    }
+      break;
+
+    case PROP_SLICE_NUM: {
+      encode->encoder->slice_num= g_value_get_uint(value);
+    }
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -320,6 +341,14 @@ gst_h264encode_get_property (GObject * object, guint prop_id,
       g_value_set_uint (value, encode->encoder->init_qp);
       break;
 
+    case PROP_MIN_QP:
+      g_value_set_uint (value, encode->encoder->min_qp);
+      break;
+
+    case PROP_SLICE_NUM:
+      g_value_set_uint (value, encode->encoder->slice_num);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index 67329ee..08a0fd6 100644 (file)
@@ -50,7 +50,6 @@ struct _GstH264Encode {
     GstH264Encoder     *encoder;
     gboolean            first_sink_frame;
     gboolean            first_src_frame;
-    void               *x_display;
 };
 
 struct _GstH264EncodeClass {
index b94a254..d16d632 100644 (file)
@@ -76,6 +76,9 @@ struct _GstH264EncoderPrivate {
   VABufferID        seq_parameter;
   VABufferID        pic_parameter;
   VABufferID        slice_parameter;
+  VAEncSliceParameterBuffer *slice_param_buffers;
+  uint32_t          default_slice_height;
+  uint32_t          slice_mod_mb_num;
 
   VABufferID       *coded_bufs;
   uint32_t          coded_buf_num;
@@ -114,9 +117,10 @@ static const uint8_t h264_bit_mask[9] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3
 
 static GstBufferClass *h264_encode_buffer_parent_class = NULL;
 
-static void gst_h264_encoder_finalize(GObject *object);
+static void     gst_h264_encoder_finalize(GObject *object);
+static void     gst_h264_encoder_init_public_values(GstH264Encoder* encoder);
 
-static VAProfile h264_get_va_profile(uint32_t profile);
+static VAProfile  h264_get_va_profile(uint32_t profile);
 static H264Status h264_encoder_alloc_buffers(GstH264EncoderPrivate *h264_prv);
 static H264Status h264_encoder_release_buffers(GstH264EncoderPrivate *h264_prv);
 static H264Status h264_put_raw_buffer_to_surface(GstH264EncoderPrivate *h264_prv,
@@ -346,12 +350,12 @@ gst_h264_encoder_init(GstH264Encoder *encoder)
 {
   GstH264EncoderPrivate *h264_prv = ENCPRV(encoder);
   H264_ASSERT(h264_prv);
+  h264_prv->public = encoder;
 
   /* init public attributes */
-  gst_h264_encoder_set_default_values(encoder);
+  gst_h264_encoder_init_public_values(encoder);
 
   /* init private values*/
-  h264_prv->public = encoder;
   h264_prv->format = GST_MAKE_FOURCC('N','V','1','2');
   h264_prv->es_flag = TRUE;
 
@@ -365,6 +369,9 @@ gst_h264_encoder_init(GstH264Encoder *encoder)
   h264_prv->seq_parameter = VA_INVALID_ID;
   h264_prv->pic_parameter = VA_INVALID_ID;
   h264_prv->slice_parameter = VA_INVALID_ID;
+  h264_prv->slice_param_buffers = NULL;
+  h264_prv->default_slice_height = 0;
+  h264_prv->slice_mod_mb_num = 0;
 
   h264_prv->coded_bufs = NULL;
   h264_prv->coded_buf_num = DEFAULT_CODEDBUF_NUM;
@@ -429,20 +436,26 @@ gst_h264_encoder_finalize(GObject *object)
     gst_buffer_unref(h264_prv->pps_data);
     h264_prv->pps_data = NULL;
   }
+  if (h264_prv->slice_param_buffers) {
+    g_free(h264_prv->slice_param_buffers);
+    h264_prv->slice_param_buffers = NULL;
+  }
 }
 
 
-void
-gst_h264_encoder_set_default_values(GstH264Encoder* encoder)
+static void
+gst_h264_encoder_init_public_values(GstH264Encoder* encoder)
 {
-  encoder->profile = H264_DEFAULT_PROFILE;
-  encoder->level = H264_DEFAULT_LEVEL;
+  encoder->profile = 0;
+  encoder->level = 0;
   encoder->width = 0;
   encoder->height = 0;
-  encoder->frame_rate = H264_DEFAULT_FPS;
-  encoder->bitrate = H264_DEFAULT_BITRATE;
-  encoder->intra_period = H264_DEFAULT_INTRA_PERIOD;
-  encoder->init_qp = H264_DEFAULT_INIT_QP;
+  encoder->frame_rate = 0;
+  encoder->bitrate = 0;
+  encoder->intra_period = 0;
+  encoder->init_qp = -1;
+  encoder->min_qp = -1;
+  encoder->slice_num = 0;
 }
 
 void
@@ -547,6 +560,63 @@ gst_h264_encoder_uninitialize(GstH264Encoder* encoder)
   return ret;
 }
 
+gboolean
+gst_h264_validate_parameters(GstH264Encoder *encoder)
+{
+  GstH264EncoderPrivate *h264_prv = ENCPRV(encoder);
+  if (!encoder->width || !encoder->height || !encoder->frame_rate) {
+    return FALSE;
+  }
+  if (!encoder->profile) {
+    encoder->profile = H264_DEFAULT_PROFILE;
+  }
+  if (!encoder->level) {
+    encoder->level = H264_DEFAULT_LEVEL;
+  }
+  if (!encoder->intra_period) {
+    encoder->intra_period = H264_DEFAULT_INTRA_PERIOD;
+  }
+  if (-1 == encoder->init_qp) {
+    encoder->init_qp = H264_DEFAULT_INIT_QP;
+  }
+  if (-1 == encoder->min_qp) {
+    encoder->min_qp = H264_DEFAULT_MIN_QP;
+  }
+
+  if (encoder->min_qp > encoder->init_qp) {
+    encoder->min_qp = encoder->init_qp;
+  }
+
+  /* default compress ratio 1: (4*8*1.5) */
+  if (!encoder->bitrate) {
+    encoder->bitrate = encoder->width*encoder->height*encoder->frame_rate/4;
+  }
+
+  if (!encoder->slice_num) {
+    encoder->slice_num = H264_DEFAULT_SLICE_NUM;
+  }
+
+  /* need  calculate slice-num and each slice-height
+        suppose:  ((encoder->height+15)/16) = 13, slice_num = 8
+        then: slice_1_height = 2
+                 slice_2_height = 2
+                 slice_3_height = 2
+                 slice_4_height = 2
+                 slice_5_height = 2
+                 slice_6_height = 1
+                 slice_7_height = 1
+                 slice_8_height = 1
+   */
+  h264_prv->default_slice_height = (encoder->height+15)/16/encoder->slice_num;
+  if (0 == h264_prv->default_slice_height) { /* special value */
+    h264_prv->default_slice_height = 1;
+    h264_prv->slice_mod_mb_num = 0;
+    encoder->slice_num = (encoder->height+15)/16;
+  } else {
+    h264_prv->slice_mod_mb_num = ((encoder->height+15)/16)%encoder->slice_num;
+  }
+  return TRUE;
+}
 
 H264Status
 #ifdef _MRST_
@@ -557,7 +627,7 @@ gst_h264_encoder_open(GstH264Encoder* encoder)
 {
   H264Status ret = H264_NO_ERROR;
   GstH264EncoderPrivate *h264_prv = ENCPRV(encoder);
-  VAProfile va_profile = h264_get_va_profile(encoder->profile);
+  VAProfile va_profile = -1;
   VAEntrypoint entrypoints[5];
   int num_entrypoints,slice_entrypoint;
   VAConfigAttrib attrib[5];
@@ -572,9 +642,12 @@ gst_h264_encoder_open(GstH264Encoder* encoder)
     return H264_STATE_ERR;
   }
 
+  /*check and set default values*/
+  H264_CHECK_STATUS(gst_h264_validate_parameters(encoder), H264_PARAMETER_ERR, "h264encoder paramerter error.\n");
+
+  va_profile = h264_get_va_profile(encoder->profile);
   H264_ASSERT(h264_prv->vaapi_display);
   H264_ASSERT(!h264_prv->vaapi_context);
-  H264_CHECK_STATUS(encoder->width && encoder->height, H264_PARAMETER_ERR, "width/height was not set.\n");
   H264_CHECK_STATUS(-1 != va_profile, H264_PROFILE_ERR, "profile(%d) is NOT supported.\n", encoder->profile);
 
 #ifdef _MRST_
@@ -698,7 +771,7 @@ h264_encoder_alloc_buffers(GstH264EncoderPrivate *h264_prv)
       seq_h264.bits_per_second = h264_prv->public->bitrate;
       seq_h264.frame_rate = h264_prv->public->frame_rate;
       seq_h264.initial_qp = h264_prv->public->init_qp; /*qp_value; 15, 24, 26?*/
-      seq_h264.min_qp = 1;     /*0, 3, 10*/
+      seq_h264.min_qp = h264_prv->public->min_qp;     /*1, 6, 10*/
       seq_h264.basic_unit_size = 0;
       seq_h264.intra_period = h264_prv->public->intra_period;
       seq_h264.intra_idr_period = h264_prv->public->intra_period;
@@ -727,7 +800,11 @@ h264_encoder_alloc_buffers(GstH264EncoderPrivate *h264_prv)
 
   H264_ASSERT(h264_prv->available_code_buffers);
 
-  /* 3. init queue available_code_buffers */
+  /*3. create slice_param_buffers*/
+  h264_prv->slice_param_buffers = (VAEncSliceParameterBuffer*)g_malloc0_n(h264_prv->public->slice_num,
+                                                     sizeof(h264_prv->slice_param_buffers[0]));
+
+  /* 4. init queue available_code_buffers */
   g_mutex_lock(h264_prv->code_buffer_lock);
   for (i = 0; i < h264_prv->coded_buf_num; i++) {
     g_queue_push_tail (h264_prv->available_code_buffers, &h264_prv->coded_bufs[i]);
@@ -781,6 +858,11 @@ h264_encoder_release_buffers(GstH264EncoderPrivate *h264_prv)
     h264_prv->coded_bufs = NULL;
   }
 
+  if (h264_prv->slice_param_buffers) {
+    g_free(h264_prv->slice_param_buffers);
+    h264_prv->slice_param_buffers = NULL;
+  }
+
   return H264_NO_ERROR;
 }
 
@@ -967,7 +1049,7 @@ h264_prepare_encoding(GstH264EncoderPrivate *h264_prv, GstBuffer *raw_pic, gbool
   VAStatus va_status = VA_STATUS_SUCCESS;
 
   VAEncPictureParameterBufferH264 pic_h264;
-  VAEncSliceParameterBuffer slice_h264;
+  VAEncSliceParameterBuffer *slice_h264 = NULL;
 
   H264_ASSERT(h264_prv->vaapi_display);
   H264_ASSERT(h264_prv->vaapi_context);
@@ -992,6 +1074,7 @@ h264_prepare_encoding(GstH264EncoderPrivate *h264_prv, GstBuffer *raw_pic, gbool
     h264_prv->recon_surface = h264_pop_free_surface(h264_prv);
     H264_CHECK_STATUS(h264_prv->recon_surface, H264_SURFACE_ERR, "reconstructed surface, h264_pop_free_surface failed.\n");
   }
+
   pic_h264.reference_picture = GST_VAAPI_OBJECT_ID(h264_prv->ref_surface);
   pic_h264.reconstructed_picture = GST_VAAPI_OBJECT_ID(h264_prv->recon_surface);
   pic_h264.coded_buf = coded_buf;
@@ -1011,20 +1094,40 @@ h264_prepare_encoding(GstH264EncoderPrivate *h264_prv, GstBuffer *raw_pic, gbool
   va_status = vaRenderPicture(va_dpy, context_id, &h264_prv->pic_parameter, 1);
   H264_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, H264_PICTURE_ERR, "rendering pic-param buffer failed.\n");
 
-  /*set slice parameters*/
-  /* one frame, one slice */
-  memset(&slice_h264, 0, sizeof(slice_h264));
-  slice_h264.start_row_number = 0;
-  slice_h264.slice_height = (h264_prv->public->height+15)/16; /* Measured by MB */
-  slice_h264.slice_flags.bits.is_intra = is_key;
-  slice_h264.slice_flags.bits.disable_deblocking_filter_idc = 0;
+  /* set slice parameters, support multiple slices */
+  int i = 0;
+  uint32_t last_row_num = 0;
+  uint32_t slice_mod_num = h264_prv->slice_mod_mb_num;
+
+  memset(h264_prv->slice_param_buffers, 0, h264_prv->public->slice_num*sizeof(h264_prv->slice_param_buffers[0]));
+  for (i = 0; i < h264_prv->public->slice_num; ++i) {
+    slice_h264 = &h264_prv->slice_param_buffers[i];
+    slice_h264->start_row_number = last_row_num;               /* unit MB*/
+    slice_h264->slice_height = h264_prv->default_slice_height; /* unit MB */
+    if (slice_mod_num) {
+      ++slice_h264->slice_height;
+      --slice_mod_num;
+    }
+    last_row_num += slice_h264->slice_height;
+    slice_h264->slice_flags.bits.is_intra = is_key;
+    slice_h264->slice_flags.bits.disable_deblocking_filter_idc = 0;
+
+  }
+  H264_ASSERT(last_row_num == (h264_prv->public->height+15)/16);
+
   if (VA_INVALID_ID != h264_prv->slice_parameter) {
     vaDestroyBuffer(va_dpy, h264_prv->slice_parameter);
     h264_prv->slice_parameter = VA_INVALID_ID;
   }
-  va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType,
-                             sizeof(slice_h264), 1, &slice_h264, &h264_prv->slice_parameter);
+  va_status = vaCreateBuffer(va_dpy,
+                             context_id,
+                             VAEncSliceParameterBufferType,
+                             sizeof(h264_prv->slice_param_buffers[0]),
+                             h264_prv->public->slice_num,
+                             h264_prv->slice_param_buffers,
+                             &h264_prv->slice_parameter);
   H264_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, H264_PICTURE_ERR, "creating slice-parameters buffer failed.\n");
+
   va_status = vaRenderPicture(va_dpy, context_id, &h264_prv->slice_parameter, 1);
   H264_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status, H264_PICTURE_ERR, "rendering slice-parameters buffer failed.\n");
 
index d68cb9d..fc43522 100644 (file)
@@ -94,10 +94,10 @@ typedef enum {
 #define H264_DEFAULT_PROFILE      H264_PROFILE_BASELINE
 #define H264_DEFAULT_LEVEL        H264_LEVEL_30
 #define H264_DEFAULT_INIT_QP      24
-#define H264_DEFAULT_BITRATE      800*1000   /*800k*/
+#define H264_DEFAULT_MIN_QP       1
 #define H264_DEFAULT_INTRA_PERIOD 30
 #define H264_DEFAULT_FPS          30
-
+#define H264_DEFAULT_SLICE_NUM    1
 
 struct _GstH264Encoder {
   GObject parent;   /*based on gobject*/
@@ -109,7 +109,9 @@ struct _GstH264Encoder {
   uint32_t frame_rate;
   uint32_t bitrate;
   uint32_t intra_period;
-  int32_t  init_qp;  /*default 26*/
+  int32_t  init_qp;  /*default 24*/
+  int32_t  min_qp;   /*default 1*/
+  uint32_t slice_num;
   /* private data; */
 };
 
@@ -135,11 +137,7 @@ GstVaapiDisplay *gst_h264_encoder_get_display(GstH264Encoder* encoder);
 H264Status gst_h264_encoder_initialize(GstH264Encoder* encoder);
 H264Status gst_h264_encoder_uninitialize(GstH264Encoder* encoder);
 
-/*
- set attributes here
-*/
-void       gst_h264_encoder_set_default_values(GstH264Encoder* encoder);
-
+gboolean   gst_h264_validate_parameters(GstH264Encoder *encoder);
 
 /**/
 #ifdef _MRST_