add properties in gsth264encode; profile, level,bitrate, intra-period, init-qp
authorWind Yuan <feng.yuan@intel.com>
Thu, 29 Sep 2011 14:08:26 +0000 (22:08 +0800)
committerZhong Cong <congx.zhong@intel.com>
Tue, 5 Feb 2013 07:37:10 +0000 (15:37 +0800)
gst/vaapiencode/gsth264encode.c
gst/vaapiencode/h264encoder.c
gst/vaapiencode/h264encoder.h

index 696bea5..f355f92 100644 (file)
@@ -67,6 +67,11 @@ GST_BOILERPLATE(
 
 enum {
     PROP_0,
+    PROP_PROFILE,
+    PROP_LEVEL,
+    PROP_BITRATE,
+    PROP_INTRA_PERIOD,
+    PROP_INIT_QP,
 };
 
 
@@ -85,6 +90,9 @@ static GstFlowReturn gst_h264encode_buffer_alloc(GstPad * pad, guint64 offset, g
                            GstCaps * caps, GstBuffer ** buf);
 
 static char* _h264_dump_caps(GstCaps *cpas);
+static gboolean _h264_check_valid_profile(guint profile);
+static gboolean _h264_check_valid_level(guint level);
+
 
 /*gst fix functions*/
 
@@ -119,6 +127,47 @@ gst_h264encode_class_init(GstH264EncodeClass *klass)
   object_class->set_property  = gst_h264encode_set_property;
   object_class->get_property  = gst_h264encode_get_property;
 
+  g_object_class_install_property (object_class, PROP_PROFILE,
+        g_param_spec_uint ("profile",
+            "H264 Profile",
+            "Profile supports: 66(Baseline), 77(Main), 100(High)",
+            H264_PROFILE_BASELINE,
+            H264_PROFILE_HIGH10,
+            H264_DEFAULT_PROFILE,
+            G_PARAM_READWRITE));
+  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",
+            H264_LEVEL_10,
+            H264_LEVEL_51,
+            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,
+            100*1000*1000,
+            H264_DEFAULT_BITRATE,
+            G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_INTRA_PERIOD,
+        g_param_spec_uint ("intra-period",
+            "H264 encoding intra-period",
+            "H264 encoding intra-period",
+            1,
+            300,
+            H264_DEFAULT_INTRA_PERIOD,
+            G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_INIT_QP,
+        g_param_spec_uint ("init-qp",
+            "H264 init-qp",
+            "H264 init-qp",
+            1,
+            51,
+            H264_DEFAULT_INIT_QP,
+            G_PARAM_READWRITE));
+
   element_class->change_state = gst_h264encode_change_state;
 }
 
@@ -198,21 +247,110 @@ static void
 gst_h264encode_set_property(GObject *object, guint prop_id,
     const GValue *value, GParamSpec *pspec)
 {
+  GstH264Encode *encode = GST_H264ENCODE(object);
+  H264_ASSERT(encode->encoder);
+
+  switch (prop_id) {
+    case PROP_PROFILE: {
+      guint profile = g_value_get_uint(value);
+      if (_h264_check_valid_profile(profile)) {
+        encode->encoder->profile = profile;
+      } else {
+        H264_LOG_ERROR("h264encode set property <profile> failed.\n");
+      }
+    }
+      break;
+
+    case PROP_LEVEL: {
+      guint level = g_value_get_uint(value);
+      if (_h264_check_valid_level(level)) {
+        encode->encoder->level= level;
+      } else {
+        H264_LOG_ERROR("h264encode set property <level> failed.\n");
+      }
+    }
+      break;
+
+    case PROP_BITRATE: {
+      encode->encoder->bitrate = g_value_get_uint(value);
+    }
+      break;
+
+    case PROP_INTRA_PERIOD: {
+      encode->encoder->intra_period = g_value_get_uint(value);
+    }
+      break;
+
+    case PROP_INIT_QP: {
+      encode->encoder->init_qp = g_value_get_uint(value);
+    }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
 }
 
 static void
 gst_h264encode_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec)
 {
+  GstH264Encode *encode = GST_H264ENCODE(object);
+  H264_ASSERT(encode->encoder);
+
+  switch (prop_id) {
+    case PROP_PROFILE:
+      g_value_set_uint (value, encode->encoder->profile);
+      break;
+
+    case PROP_LEVEL:
+      g_value_set_uint (value, encode->encoder->level);
+      break;
+
+    case PROP_BITRATE:
+      g_value_set_uint (value, encode->encoder->bitrate);
+      break;
+
+    case PROP_INTRA_PERIOD:
+      g_value_set_uint (value, encode->encoder->intra_period);
+      break;
+
+    case PROP_INIT_QP:
+      g_value_set_uint (value, encode->encoder->init_qp);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
 }
 
 static gboolean
 gst_h264encode_set_caps(GstPad *sink_pad, GstCaps *caps)
 {
   GstH264Encode *encode = GST_H264ENCODE(GST_OBJECT_PARENT(sink_pad));
+  GstStructure *structure;
+  gint width = 0, height = 0;
+  gint fps_n = 0, fps_d = 0;
+  const GValue *fps_value = NULL;
   encode->sinkpad_caps = caps;
-  H264_LOG_INFO("gst_h264encode_set_caps,\n%s", _h264_dump_caps(caps));
   gst_caps_ref(caps);
+  H264_LOG_INFO("gst_h264encode_set_caps,\n%s", _h264_dump_caps(caps));
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (gst_structure_get_int (structure, "width", &width)) {
+    encode->encoder->width = width;
+  }
+  if (gst_structure_get_int (structure, "height", &height)) {
+    encode->encoder->height = height;
+  }
+  fps_value = gst_structure_get_value (structure, "framerate");
+  if (fps_value) {
+    fps_n = gst_value_get_fraction_numerator (fps_value);
+    fps_d = gst_value_get_fraction_denominator (fps_value);
+    encode->encoder->frame_rate = fps_n/fps_d;
+  }
   return TRUE;
 }
 
@@ -290,26 +428,28 @@ gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf)
 
     recv_struct = gst_caps_get_structure (recv_caps, 0);
     GST_H264_ENCODE_CHECK_STATUS(NULL != recv_caps, GST_FLOW_ERROR, "gst_h264encode_chain, 1st buffer didn't have detailed caps.\n");
-    gst_structure_get_int (recv_struct, "width", &width);
-    gst_structure_get_int (recv_struct, "height", &height);
+    if (gst_structure_get_int (recv_struct, "width", &width)) {
+      encode->encoder->width = width;
+    }
+    if (gst_structure_get_int (recv_struct, "height", &height)) {
+      encode->encoder->height = height;
+    }
     framerate = gst_structure_get_value (recv_struct, "framerate");
-    fps_n = gst_value_get_fraction_numerator (framerate);
-    fps_d = gst_value_get_fraction_denominator (framerate);
+    if (framerate) {
+      fps_n = gst_value_get_fraction_numerator (framerate);
+      fps_d = gst_value_get_fraction_denominator (framerate);
+      encode->encoder->frame_rate = fps_n/fps_d;
+    }
     format_value = gst_structure_get_value (recv_struct, "format");
     if (format_value) {
       GST_H264_ENCODE_CHECK_STATUS(format_value && GST_TYPE_FOURCC == G_VALUE_TYPE(format_value),
                                  GST_FLOW_ERROR, "1st buffer caps' format type is not fourcc.\n");
       format = gst_value_get_fourcc (format_value);
+      if (format) {
+        gst_h264_encoder_set_input_format(encode->encoder, format);
+      }
     }
 
-    encode->encoder->profile = 66;
-    encode->encoder->level = 30;
-    encode->encoder->width = width;
-    encode->encoder->height = height;
-    encode->encoder->frame_rate = fps_n/fps_d;
-    encode->encoder->bitrate = 3*1000*1000; // 3M
-    encode->encoder->intra_period = 30;
-
     /*set src pad caps*/
     if (encode->srcpad_caps) {
       gst_caps_unref(encode->srcpad_caps);
@@ -321,9 +461,6 @@ gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf)
                       "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
 
     /*set display and initialize encoder*/
-    if (format) {
-      gst_h264_encoder_set_input_format(encode->encoder, format);
-    }
     if (GST_VAAPI_IS_VIDEO_BUFFER(buf)) {
       GstVaapiDisplay *display = NULL;
       GstVaapiVideoBuffer *video_buffer = GST_VAAPI_VIDEO_BUFFER(buf);
@@ -332,7 +469,7 @@ gst_h264encode_chain(GstPad *sink_pad, GstBuffer *buf)
       //need to get surface_pool and set to h264encoder->vaapi_context
       //(video_buffer->priv->surface_pool);
       #ifdef _MRST_
-      surface_pool = gst_vaapi_video_buffer_get_surface_pool(video_buffer);
+      surface_pool = GST_VAAPI_SURFACE_POOL(gst_vaapi_video_buffer_get_surface_pool(video_buffer));
       #endif
       if (display) {
         GST_H264_ENCODE_CHECK_STATUS(gst_h264_encoder_set_display(encode->encoder,display)
@@ -432,7 +569,50 @@ finish:
   return ret_num;
 }
 
+static gboolean _h264_check_valid_profile(guint profile)
+{
+   static const limit_profiles[] = {
+         H264_PROFILE_BASELINE,
+         H264_PROFILE_MAIN,
+         H264_PROFILE_HIGH
+        };
+   guint n_profiles = sizeof(limit_profiles)/sizeof(limit_profiles[0]);
+   guint i;
+   for (i = 0; i < n_profiles; ++i) {
+     if (limit_profiles[i] == profile)
+       return TRUE;
+   }
+   return FALSE;
+}
+
+static gboolean _h264_check_valid_level(guint level)
+{
+  static const limit_levels[] = {
+        H264_LEVEL_10,
+        H264_LEVEL_11,
+        H264_LEVEL_12,
+        H264_LEVEL_13,
+        H264_LEVEL_20,
+        H264_LEVEL_21,
+        H264_LEVEL_22,
+        H264_LEVEL_30,
+        H264_LEVEL_31,
+        H264_LEVEL_32,
+        H264_LEVEL_40,
+        H264_LEVEL_41,
+        H264_LEVEL_42,
+        H264_LEVEL_50,
+        H264_LEVEL_51
+       };
+  guint n_levels = sizeof(limit_levels)/sizeof(limit_levels[0]);
+  guint i;
+  for (i = 0; i < n_levels; ++i) {
+    if (limit_levels[i] == level)
+      return TRUE;
+  }
+  return FALSE;
 
+}
 
 static char*
 _h264_dump_caps(GstCaps *cpas)
index 500cbfb..b94a254 100644 (file)
@@ -318,7 +318,20 @@ H264_Encode_State gst_h264_encoder_get_state(GstH264Encoder* encoder)
 static VAProfile
 h264_get_va_profile(uint32_t profile)
 {
-  return VAProfileH264Baseline;
+  switch (profile) {
+    case H264_PROFILE_BASELINE:
+      return VAProfileH264Baseline;
+
+    case H264_PROFILE_MAIN:
+      return VAProfileH264Main;
+
+    case H264_PROFILE_HIGH:
+      return VAProfileH264High;
+
+    default:
+      break;
+  }
+  return (-1);
 }
 
 GstH264Encoder *
@@ -422,14 +435,14 @@ gst_h264_encoder_finalize(GObject *object)
 void
 gst_h264_encoder_set_default_values(GstH264Encoder* encoder)
 {
-  encoder->profile = 66;
-  encoder->level = 30;
-  encoder->width = 1280;
-  encoder->height = 720;
-  encoder->frame_rate = 30;
-  encoder->bitrate = 3*1000*1000; // 3M
-  encoder->intra_period = 30;
-  encoder->init_qp = 30;
+  encoder->profile = H264_DEFAULT_PROFILE;
+  encoder->level = H264_DEFAULT_LEVEL;
+  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;
 }
 
 void
@@ -561,6 +574,9 @@ gst_h264_encoder_open(GstH264Encoder* encoder)
 
   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_
   h264_prv->vaapi_context = g_object_new(
         GST_VAAPI_TYPE_CONTEXT,
@@ -1231,7 +1247,6 @@ gst_h264_encoder_flush(GstH264Encoder* encoder, GList *coded_pics)
 {
   H264Status ret = H264_NO_ERROR;
   //GstH264EncoderPrivate *h264_prv = ENCPRV(encoder);
-  //VAProfile va_profile = h264_get_va_profile(encoder->profile);
 
   //error:
   return ret;
index f79de0e..d68cb9d 100644 (file)
@@ -32,7 +32,8 @@ extern "C" {
 #define H264_QUERY_STATUS_ERR -8
 #define H264_DATA_NOT_READY   -9
 #define H264_DATA_ERR      -10
-
+#define H264_PROFILE_ERR   -11
+#define H264_PARAMETER_ERR -12
 
 
 #define H264_LOG_ERROR(...) fprintf(stdout, ## __VA_ARGS__)
@@ -41,7 +42,6 @@ extern "C" {
 
 
 typedef int                                 H264Status;
-typedef void*                               VADisplay;
 typedef struct _GstH264Encoder              GstH264Encoder;
 typedef struct _GstH264EncoderPrivate       GstH264EncoderPrivate;
 typedef struct _GstH264EncoderClass         GstH264EncoderClass;
@@ -73,7 +73,31 @@ typedef enum {
   H264_PROFILE_HIGH444_PREDICTIVE = 244,
 } H264_Profile;
 
-#define H264_DEFAULT_INIT_QP 26
+typedef enum {
+  H264_LEVEL_10 = 10,  /* QCIF format, < 380160 samples/sec */
+  H264_LEVEL_11 = 11,  /* CIF format,   < 768000 samples/sec */
+  H264_LEVEL_12 = 12,  /* CIF format,   < 1536000  samples/sec */
+  H264_LEVEL_13 = 13,  /* CIF format,   < 3041280  samples/sec */
+  H264_LEVEL_20 = 20,  /* CIF format,   < 3041280  samples/sec */
+  H264_LEVEL_21 = 21,  /* HHR format,  < 5068800  samples/sec */
+  H264_LEVEL_22 = 22,  /* SD/4CIF format,     < 5184000      samples/sec */
+  H264_LEVEL_30 = 30,  /* SD/4CIF format,     < 10368000    samples/sec */
+  H264_LEVEL_31 = 31,  /* 720pHD format,      < 27648000    samples/sec */
+  H264_LEVEL_32 = 32,  /* SXGA  format,         < 55296000    samples/sec */
+  H264_LEVEL_40 = 40,  /* 2Kx1K format,         < 62914560    samples/sec */
+  H264_LEVEL_41 = 41,  /* 2Kx1K format,         < 62914560    samples/sec */
+  H264_LEVEL_42 = 42,  /* 2Kx1K format,         < 125829120  samples/sec */
+  H264_LEVEL_50 = 50,  /* 3672x1536 format,  < 150994944  samples/sec */
+  H264_LEVEL_51 = 51,  /* 4096x2304 format,  < 251658240  samples/sec */
+} H264_Level;
+
+#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_INTRA_PERIOD 30
+#define H264_DEFAULT_FPS          30
+
 
 struct _GstH264Encoder {
   GObject parent;   /*based on gobject*/