]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blobdiff - src/gstducatih264enc.c
ducatih264enc: fix B frames being disabled
[glsdk/gst-plugin-ducati.git] / src / gstducatih264enc.c
index 3af25e8cbe165f0ad83c0f693a30dba0667cf3b6..4df4516a1ebc4e20b862bf5998318210edf00064 100644 (file)
 
 #define DEFAULT_PROFILE GST_DUCATI_H264ENC_PROFILE_HIGH
 #define DEFAULT_LEVEL GST_DUCATI_H264ENC_LEVEL_40
+#define DEFAULT_QPI 28
+#define DEFAULT_QP_MAX_I 36
+#define DEFAULT_QP_MIN_I 10
+/* 2 x targetBitRate for VBR Rate Control */
+#define DEFAULT_HRD_BUFFER_SIZE 40960000
+#define DEFAULT_INTER_INTERVAL 4
 
 #define GST_TYPE_DUCATI_H264ENC_PROFILE (gst_ducati_h264enc_profile_get_type ())
 #define GST_TYPE_DUCATI_H264ENC_LEVEL (gst_ducati_h264enc_level_get_type ())
+#define GST_TYPE_DUCATI_H264ENC_RCPP (gst_ducati_h264enc_get_rate_control_params_preset_type ())
+#define GST_TYPE_DUCATI_H264ENC_RATE_CONTROL_ALGO (gst_ducati_h264enc_get_rate_control_algo_type ())
+#define GST_TYPE_DUCATI_H264ENC_ENTROPY_CODING_MODE (gst_ducati_h264enc_get_entropy_coding_mode_type ())
+#define GST_TYPE_DUCATI_H264ENC_SLICE_MODE (gst_ducati_h264enc_get_slice_mode_type ())
 
 
 enum
@@ -50,6 +60,15 @@ enum
   PROP_0,
   PROP_PROFILE,
   PROP_LEVEL,
+  PROP_RATE_CONTROL_PARAMS_PRESET,
+  PROP_RATE_CONTROL_ALGO,
+  PROP_QPI,
+  PROP_QP_MAX_I,
+  PROP_QP_MIN_I,
+  PROP_HRD_BUFFER_SIZE,
+  PROP_ENTROPY_CODING_MODE,
+  PROP_INTER_INTERVAL,
+  PROP_SLICE_MODE,
 };
 
 static void gst_ducati_h264enc_set_property (GObject * object, guint prop_id,
@@ -61,6 +80,8 @@ static gboolean gst_ducati_h264enc_allocate_params (GstDucatiVidEnc *
     self, gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz,
     gint outargs_sz);
 static gboolean gst_ducati_h264enc_configure (GstDucatiVidEnc * self);
+static gboolean gst_ducati_h264enc_is_sync_point (GstDucatiVidEnc * enc,
+    int type);
 
 
 static GstStaticPadTemplate gst_ducati_h264enc_sink_template =
@@ -74,7 +95,8 @@ static GstStaticPadTemplate gst_ducati_h264enc_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("video/x-h264")
+    GST_STATIC_CAPS
+    ("video/x-h264, alignment=(string)au, stream-format=(string)byte-stream")
     );
 
 GST_BOILERPLATE (GstDucatiH264Enc, gst_ducati_h264enc, GstDucatiVidEnc,
@@ -135,6 +157,52 @@ gst_ducati_h264enc_profile_get_type (void)
   return type;
 }
 
+static GType
+gst_ducati_h264enc_get_rate_control_params_preset_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GEnumValue vals[] = {
+      {IH264_RATECONTROLPARAMS_DEFAULT, "Rate Control params preset default",
+          "rate-control-params-preset-default"},
+      {IH264_RATECONTROLPARAMS_USERDEFINED, "User defined rate control",
+          "rate-control-params-preset-user-defined"},
+      {IH264_RATECONTROLPARAMS_EXISTING, "Existing rate control params",
+          "rate-control-params-preset-existing"},
+      {IH264_RATECONTROLPARAMS_MAX, "Max rate control",
+          "rate-control-params-preset-control"},
+      {0, NULL, NULL},
+    };
+
+    type = g_enum_register_static ("GstDucatiH264EncRateControlParams", vals);
+  }
+
+  return type;
+}
+
+static GType
+gst_ducati_h264enc_get_rate_control_algo_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GEnumValue vals[] = {
+      {IH264_RATECONTROL_PRC, "Perceptual rate control",
+          "perceptual-rate-control"},
+      {IH264_RATECONTROL_PRC_LOW_DELAY, "Low delay rate control",
+          "low-delay-rate-control"},
+      {IH264_RATECONTROL_DEFAULT, "Default rcAlgo (PRC)",
+          "default-rate-control"},
+      {0, NULL, NULL},
+    };
+
+    type = g_enum_register_static ("GstDucatiH264EncRateControlAlgo", vals);
+  }
+
+  return type;
+}
+
 static GType
 gst_ducati_h264enc_level_get_type (void)
 {
@@ -167,6 +235,51 @@ gst_ducati_h264enc_level_get_type (void)
   return type;
 }
 
+static GType
+gst_ducati_h264enc_get_entropy_coding_mode_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GEnumValue vals[] = {
+      {IH264_ENTROPYCODING_CAVLC, "CAVLC coding type", "cavlc"},
+      {IH264_ENTROPYCODING_DEFAULT, "Default coding type (cavlc)", "default"},
+      {IH264_ENTROPYCODING_CABAC, "Cabac coding mode", "cabac"},
+      {0, NULL, NULL},
+    };
+
+    type = g_enum_register_static ("GstDucatiEntropyCodingMode", vals);
+  }
+
+  return type;
+}
+
+static GType
+gst_ducati_h264enc_get_slice_mode_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GEnumValue vals[] = {
+      {IH264_SLICEMODE_NONE, "No slice mode", "none"},
+      {IH264_SLICEMODE_DEFAULT, "Default slice coding mode is MB based",
+          "default"},
+      {IH264_SLICEMODE_MBUNIT,
+          "Slices are controlled based upon number of Macroblocks", "mbunit"},
+      {IH264_SLICEMODE_BYTES,
+          "Slices are controlled based upon number of bytes", "bytes"},
+      {IH264_SLICEMODE_OFFSET,
+            "Slices are controlled based upon user defined offset unit of Row",
+          "offset"},
+      {0, NULL, NULL},
+    };
+
+    type = g_enum_register_static ("GstDucatiSliceMode", vals);
+  }
+
+  return type;
+}
+
 static void
 gst_ducati_h264enc_base_init (gpointer g_class)
 {
@@ -200,6 +313,7 @@ gst_ducati_h264enc_class_init (GstDucatiH264EncClass * klass)
 
   videnc_class->allocate_params = gst_ducati_h264enc_allocate_params;
   videnc_class->configure = gst_ducati_h264enc_configure;
+  videnc_class->is_sync_point = gst_ducati_h264enc_is_sync_point;
 
   g_object_class_install_property (gobject_class, PROP_PROFILE,
       g_param_spec_enum ("profile", "H.264 Profile", "H.264 Profile",
@@ -208,6 +322,68 @@ gst_ducati_h264enc_class_init (GstDucatiH264EncClass * klass)
   g_object_class_install_property (gobject_class, PROP_LEVEL,
       g_param_spec_enum ("level", "H.264 Level", "H.264 Level",
           GST_TYPE_DUCATI_H264ENC_LEVEL, DEFAULT_LEVEL, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_INTER_INTERVAL,
+      g_param_spec_uint ("inter-interval", "Inter-frame interval",
+          "Max inter frame interval (B frames are allowed between them if > 1)",
+          1, 31, DEFAULT_INTER_INTERVAL, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+      PROP_RATE_CONTROL_PARAMS_PRESET,
+      g_param_spec_enum ("rate-control-params-preset",
+          "H.264 rate control params preset",
+          "This preset controls the USER_DEFINED versus "
+          "DEFAULT mode. If you are not aware about the "
+          "fields, it should be set as IH264_RATECONTROLPARAMS_DEFAULT",
+          GST_TYPE_DUCATI_H264ENC_RCPP, IH264_RATECONTROLPARAMS_DEFAULT,
+          G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_RATE_CONTROL_ALGO,
+      g_param_spec_enum ("rate-control-algo", "H.264 rate control algorithm",
+          "This defines the rate control algorithm to be used. Only useful if "
+          " 'rate-control-params-preset' is set as "
+          "'rate-control-params-preset-user-defined'",
+          GST_TYPE_DUCATI_H264ENC_RATE_CONTROL_ALGO, IH264_RATECONTROL_DEFAULT,
+          G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_QPI,
+      g_param_spec_int ("qpi", "Initial quantization parameter",
+          "Initial quantization parameter for I/IDR frames.", -1, 51,
+          DEFAULT_QPI, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_QP_MIN_I,
+      g_param_spec_int ("qp-min-i", "Minimum quantization parameter",
+          "Minimum quantization parameter for I/IDR frames.", 0, 51,
+          DEFAULT_QP_MIN_I, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_QP_MAX_I,
+      g_param_spec_int ("qp-max-i", "Maximum quantization parameter",
+          "Maximum quantization parameter for I/IDR frames.", 0, 51,
+          DEFAULT_QP_MAX_I, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_HRD_BUFFER_SIZE,
+      g_param_spec_uint ("hrd-buffer-size",
+          "Hypothetical reference decoder buffer size",
+          "Hypothetical reference decoder buffer size. This "
+          "size controls the frame skip logic of the encoder. "
+          "For low delay applications this size should be "
+          "small. This size is in bits. Maximum Value is level "
+          "dependant and min value is 4096",
+          4096, G_MAXUINT, DEFAULT_HRD_BUFFER_SIZE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_ENTROPY_CODING_MODE,
+      g_param_spec_enum ("entropy-coding-mode", "H.264 entropy coding mode",
+          "Controls the entropy coding type.",
+          GST_TYPE_DUCATI_H264ENC_ENTROPY_CODING_MODE,
+          IH264_ENTROPYCODING_DEFAULT, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_SLICE_MODE,
+      g_param_spec_enum ("slice-mode", "H.264 slice mode",
+          "This defines the control mechanism to split a picture in slices."
+          " It can be either MB based or bytes based",
+          GST_TYPE_DUCATI_H264ENC_SLICE_MODE,
+          IH264_SLICEMODE_DEFAULT, G_PARAM_READWRITE));
+
 }
 
 static void
@@ -217,6 +393,13 @@ gst_ducati_h264enc_init (GstDucatiH264Enc * self, GstDucatiH264EncClass * klass)
 
   self->profile = DEFAULT_PROFILE;
   self->level = DEFAULT_LEVEL;
+  self->rate_control_params_preset = IH264_RATECONTROLPARAMS_DEFAULT;
+  self->rate_control_algo = IH264_RATECONTROL_DEFAULT;
+  self->qpi = DEFAULT_QPI;
+  self->qp_min_i = DEFAULT_QP_MIN_I;
+  self->qp_max_i = DEFAULT_QP_MAX_I;
+  self->hrd_buffer_size = DEFAULT_HRD_BUFFER_SIZE;
+  self->inter_interval = DEFAULT_INTER_INTERVAL;
 }
 
 static void
@@ -224,8 +407,10 @@ gst_ducati_h264enc_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
   GstDucatiH264Enc *self = GST_DUCATIH264ENC (object);
+  GstDucatiVidEnc *venc = GST_DUCATIVIDENC (object);
+  IH264ENC_DynamicParams *dynParams =
+      (IH264ENC_DynamicParams *) venc->dynParams;
 
-  g_return_if_fail (GST_IS_DUCATIH264ENC (object));
   self = GST_DUCATIH264ENC (object);
 
   switch (prop_id) {
@@ -235,6 +420,53 @@ gst_ducati_h264enc_set_property (GObject * object, guint prop_id,
     case PROP_LEVEL:
       self->level = g_value_get_enum (value);
       break;
+    case PROP_RATE_CONTROL_PARAMS_PRESET:
+      self->rate_control_params_preset = g_value_get_enum (value);
+      if (dynParams)
+        dynParams->rateControlParams.rateControlParamsPreset =
+            self->rate_control_params_preset;
+      break;
+    case PROP_RATE_CONTROL_ALGO:
+      self->rate_control_algo = g_value_get_enum (value);
+
+      if (self->rate_control_params_preset !=
+          IH264_RATECONTROLPARAMS_USERDEFINED)
+        GST_INFO_OBJECT (self,
+            "Setting rcAlgo but rateControlParamsPreset not "
+            "'rate-control-params-preset-user-defined' config won't be taken "
+            "into account");
+
+      if (dynParams)
+        dynParams->rateControlParams.rcAlgo = self->rate_control_algo;
+      break;
+    case PROP_QPI:
+      self->qpi = g_value_get_int (value);
+      if (dynParams)
+        dynParams->rateControlParams.qpI = self->qpi;
+
+      break;
+    case PROP_QP_MIN_I:
+      self->qp_min_i = g_value_get_int (value);
+      if (dynParams)
+        dynParams->rateControlParams.qpMinI = self->qp_min_i;
+      break;
+    case PROP_QP_MAX_I:
+      self->qp_max_i = g_value_get_int (value);
+      if (dynParams)
+        dynParams->rateControlParams.qpMaxI = self->qp_max_i;
+      break;
+    case PROP_HRD_BUFFER_SIZE:
+      self->hrd_buffer_size = g_value_get_uint (value);
+      break;
+    case PROP_ENTROPY_CODING_MODE:
+      self->entropy_coding_mode = g_value_get_enum (value);
+      break;
+    case PROP_SLICE_MODE:
+      self->slice_mode = g_value_get_enum (value);
+      break;
+    case PROP_INTER_INTERVAL:
+      self->inter_interval = g_value_get_uint (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   }
@@ -256,17 +488,114 @@ gst_ducati_h264enc_get_property (GObject * object, guint prop_id,
     case PROP_LEVEL:
       g_value_set_enum (value, self->level);
       break;
+    case PROP_RATE_CONTROL_PARAMS_PRESET:
+      g_value_set_enum (value, self->rate_control_params_preset);
+      break;
+    case PROP_RATE_CONTROL_ALGO:
+      g_value_set_enum (value, self->rate_control_algo);
+      break;
+    case PROP_QPI:
+      g_value_set_int (value, self->qpi);
+      break;
+    case PROP_QP_MIN_I:
+      g_value_set_int (value, self->qp_min_i);
+      break;
+    case PROP_QP_MAX_I:
+      g_value_set_int (value, self->qp_max_i);
+      break;
+    case PROP_HRD_BUFFER_SIZE:
+      g_value_set_uint (value, self->hrd_buffer_size);
+      break;
+    case PROP_ENTROPY_CODING_MODE:
+      g_value_set_enum (value, self->entropy_coding_mode);
+      break;
+    case PROP_SLICE_MODE:
+      g_value_set_enum (value, self->slice_mode);
+      break;
+    case PROP_INTER_INTERVAL:
+      g_value_set_uint (value, self->inter_interval);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   }
 }
 
+static const char *
+get_profile_name (guint profile)
+{
+  switch (profile) {
+    case GST_DUCATI_H264ENC_PROFILE_BASELINE:
+      return "baseline";
+    case GST_DUCATI_H264ENC_PROFILE_MAIN:
+      return "main";
+    case GST_DUCATI_H264ENC_PROFILE_EXTENDED:
+      return "extended";
+    case GST_DUCATI_H264ENC_PROFILE_HIGH:
+      return "high";
+    case GST_DUCATI_H264ENC_PROFILE_HIGH_10:
+      return "high-10";
+    case GST_DUCATI_H264ENC_PROFILE_HIGH_422:
+      return "high-422";
+    default:
+      return NULL;
+  }
+}
+
+static const char *
+get_level_name (guint level)
+{
+  switch (level) {
+    case GST_DUCATI_H264ENC_LEVEL_10:
+      return "1";
+    case GST_DUCATI_H264ENC_LEVEL_1b:
+      return "1b";
+    case GST_DUCATI_H264ENC_LEVEL_11:
+      return "1.1";
+    case GST_DUCATI_H264ENC_LEVEL_12:
+      return "1.2";
+    case GST_DUCATI_H264ENC_LEVEL_13:
+      return "1.3";
+    case GST_DUCATI_H264ENC_LEVEL_20:
+      return "2";
+    case GST_DUCATI_H264ENC_LEVEL_21:
+      return "2.1";
+    case GST_DUCATI_H264ENC_LEVEL_22:
+      return "2.2";
+    case GST_DUCATI_H264ENC_LEVEL_30:
+      return "3";
+    case GST_DUCATI_H264ENC_LEVEL_31:
+      return "3.1";
+    case GST_DUCATI_H264ENC_LEVEL_32:
+      return "3.2";
+    case GST_DUCATI_H264ENC_LEVEL_40:
+      return "4";
+    case GST_DUCATI_H264ENC_LEVEL_41:
+      return "4.1";
+    case GST_DUCATI_H264ENC_LEVEL_42:
+      return "4.2";
+    case GST_DUCATI_H264ENC_LEVEL_50:
+      return "5";
+    case GST_DUCATI_H264ENC_LEVEL_51:
+      return "5.1";
+    default:
+      return NULL;
+  }
+}
+
 static gboolean
 gst_ducati_h264enc_configure (GstDucatiVidEnc * videnc)
 {
   GstDucatiH264Enc *self = GST_DUCATIH264ENC (videnc);
   IH264ENC_Params *params;
+  IH264ENC_DynamicParams *dynParams;
   gboolean ret;
+  const char *s;
+  const GstVideoState *state;
+  GstCaps *caps;
+
+  ret = GST_DUCATIVIDENC_CLASS (parent_class)->configure (videnc);
+  if (!ret)
+    return FALSE;
 
   videnc->params->profile = self->profile;
   videnc->params->level = self->level;
@@ -274,21 +603,38 @@ gst_ducati_h264enc_configure (GstDucatiVidEnc * videnc)
   params = (IH264ENC_Params *) videnc->params;
   /* this is the only non-base field strictly required */
   params->maxIntraFrameInterval = 0x7fffffff;
-
-  ret = GST_DUCATIVIDENC_CLASS (parent_class)->configure (videnc);
-  if (ret) {
-    const GstVideoState *state =
-        gst_base_video_encoder_get_state (GST_BASE_VIDEO_ENCODER (videnc));
-    GstCaps *caps = gst_caps_new_simple ("video/x-h264",
-        "width", G_TYPE_INT, videnc->rect.w,
-        "height", G_TYPE_INT, videnc->rect.h,
-        "framerate", GST_TYPE_FRACTION, state->fps_n, state->fps_d,
-        "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, state->par_d,
-        "stream-format", G_TYPE_STRING, "byte-stream",
-        "align", G_TYPE_STRING, "au",
-        NULL);
-    ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self), caps);
-  }
+  params->IDRFrameInterval = 1;
+  params->numTemporalLayer = 1;
+  params->entropyCodingMode = self->entropy_coding_mode;
+  videnc->params->maxInterFrameInterval = self->inter_interval;
+
+  /* Dynamic params */
+  dynParams = (IH264ENC_DynamicParams *) videnc->dynParams;
+  dynParams->rateControlParams.rateControlParamsPreset =
+      self->rate_control_params_preset;
+  dynParams->rateControlParams.rcAlgo = self->rate_control_algo;
+  dynParams->rateControlParams.qpI = self->qpi;
+  dynParams->rateControlParams.qpMaxI = self->qp_max_i;
+  dynParams->rateControlParams.qpMinI = self->qp_min_i;
+  dynParams->rateControlParams.HRDBufferSize = self->hrd_buffer_size;
+  dynParams->sliceCodingParams.sliceMode = self->slice_mode;
+  videnc->dynParams->interFrameInterval = self->inter_interval;
+
+  state = gst_base_video_encoder_get_state (GST_BASE_VIDEO_ENCODER (videnc));
+  caps = gst_caps_new_simple ("video/x-h264",
+      "width", G_TYPE_INT, videnc->rect.w,
+      "height", G_TYPE_INT, videnc->rect.h,
+      "framerate", GST_TYPE_FRACTION, state->fps_n, state->fps_d,
+      "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, state->par_d,
+      "stream-format", G_TYPE_STRING, "byte-stream",
+      "align", G_TYPE_STRING, "au", NULL);
+  s = get_profile_name (self->profile);
+  if (s)
+    gst_caps_set_simple (caps, "profile", G_TYPE_STRING, s, NULL);
+  s = get_level_name (self->level);
+  if (s)
+    gst_caps_set_simple (caps, "level", G_TYPE_STRING, s, NULL);
+  ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self), caps);
 
   return ret;
 }
@@ -298,8 +644,32 @@ gst_ducati_h264enc_allocate_params (GstDucatiVidEnc *
     videnc, gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz,
     gint outargs_sz)
 {
-  return GST_DUCATIVIDENC_CLASS (parent_class)->allocate_params (videnc,
-      sizeof (IH264ENC_Params), sizeof (IVIDENC2_DynamicParams),
+  gboolean ret = GST_DUCATIVIDENC_CLASS (parent_class)->allocate_params (videnc,
+      sizeof (IH264ENC_Params), sizeof (IH264ENC_DynamicParams),
       sizeof (IVIDENC2_Status), sizeof (IVIDENC2_InArgs),
       sizeof (IVIDENC2_OutArgs));
+
+  GstDucatiH264Enc *self = GST_DUCATIH264ENC (videnc);
+
+  if (ret == TRUE) {
+    IH264ENC_DynamicParams *dynParams =
+        (IH264ENC_DynamicParams *) videnc->dynParams;
+
+    dynParams->rateControlParams.rateControlParamsPreset =
+        self->rate_control_params_preset;
+    dynParams->rateControlParams.rcAlgo = self->rate_control_algo;
+    dynParams->rateControlParams.qpI = self->qpi;
+    dynParams->rateControlParams.qpMaxI = self->qp_max_i;
+    dynParams->rateControlParams.qpMinI = self->qp_min_i;
+    dynParams->rateControlParams.HRDBufferSize = self->hrd_buffer_size;
+    dynParams->sliceCodingParams.sliceMode = self->slice_mode;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_ducati_h264enc_is_sync_point (GstDucatiVidEnc * enc, int type)
+{
+  return type == IVIDEO_IDR_FRAME;
 }