encoder: h264 compatible with old libva by macro HAVE_OLD_H264_ENCODER
authorWind Yuan <feng.yuan@intel.com>
Tue, 25 Sep 2012 05:31:51 +0000 (13:31 +0800)
committerZhong Cong <congx.zhong@intel.com>
Tue, 5 Feb 2013 07:37:12 +0000 (15:37 +0800)
gst-libs/gst/vaapi/gstvaapiencoder_h264.c

index 47fb13f..1000963 100644 (file)
  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  *  Boston, MA 02110-1301 USA
  */
+#define HAVE_OLD_H264_ENCODER 0
 
 #include "gstvaapiencoder_h264.h"
+#include "config.h"
 
 #include <string.h>
 #include <stdlib.h>
 #include <va/va.h>
 #include <va/va_x11.h>
+#if !HAVE_OLD_H264_ENCODER
 #include <va/va_enc_h264.h>
+#endif
 #include <X11/Xlib.h>
 #include <glib.h>
 
@@ -103,7 +107,7 @@ struct _GstVaapiEncoderH264Private {
   VABufferID        packed_seq_data_id;
   VABufferID        packed_pic_param_id;
   VABufferID        packed_pic_data_id;
-#ifdef _SIMPLE_LIB_VA_
+#if HAVE_OLD_H264_ENCODER
   VAEncSliceParameterBuffer     *slice_param_buffers;
 #else
   VAEncSliceParameterBufferH264 *slice_param_buffers;
@@ -464,7 +468,7 @@ gst_vaapi_encoder_h264_alloc_slices(
   GstVaapiEncoderH264Private *priv = encoder->priv;
 
   priv->slice_param_buffers =
-#ifdef _SIMPLE_LIB_VA_
+#if HAVE_OLD_H264_ENCODER
   (VAEncSliceParameterBuffer*)
 #else
   (VAEncSliceParameterBufferH264*)
@@ -575,102 +579,82 @@ h264_swap_surface(GstVaapiSurface **s1, GstVaapiSurface **s2)
   *s2 = tmp;
 }
 
-#ifdef _SIMPLE_LIB_VA_
-
-static EncoderStatus
-gst_vaapi_encoder_h264_rendering(GstVaapiBaseEncoder *encoder, GstVaapiDisplay *display,
-                             GstVaapiContext *context, GstVaapiSurface *surface,
-                             guint frame_index, VABufferID coded_buf, gboolean *is_key)
+static inline const char *
+get_slice_type(H264_SLICE_TYPE type)
 {
-  EncoderStatus ret = ENCODER_NO_ERROR;
-  VAStatus va_status = VA_STATUS_SUCCESS;
-  GstVaapiEncoderH264 *h264_encoder = GST_VAAPI_ENCODER_H264_CAST(encoder);
-  GstVaapiEncoderH264Private *priv = h264_encoder->priv;
-  VAEncPictureParameterBufferH264 pic_param;
-  VAEncSliceParameterBuffer *slice_param = NULL;
-
-  gboolean is_locked = FALSE;
-
-  ENCODER_ASSERT(display && context);
-  VADisplay va_dpy = gst_vaapi_display_get_display(display);
-  VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
+    switch (type) {
+    case SLICE_TYPE_I:
+        return "I";
+    case SLICE_TYPE_P:
+        return "P";
+    case SLICE_TYPE_B:
+        return "B";
+    default:
+        return "Unknown";
+    }
+}
 
-  *is_key = (priv->cur_slice_type == SLICE_TYPE_I);
+#if HAVE_OLD_H264_ENCODER
 
-  /* lock display */
-  ENCODER_ACQUIRE_DISPLAY_LOCK(display);
-  /*handle first surface_index*/
-  /*only need first frame*/
-  if (VA_INVALID_ID == priv->seq_param_id) { /*first time*/
-    VAEncSequenceParameterBufferH264 seq = { 0 };
-    seq.level_idc = h264_encoder->level; /* 3.0 */
-    seq.max_num_ref_frames = 1; /*Only I, P frames*/
-    seq.picture_width_in_mbs = (ENCODER_WIDTH(h264_encoder)+15)/16;
-    seq.picture_height_in_mbs = (ENCODER_HEIGHT(h264_encoder)+15)/16;
-
-    seq.bits_per_second = h264_encoder->bitrate;
-    seq.frame_rate = ENCODER_FPS(h264_encoder);
-    seq.initial_qp = h264_encoder->init_qp; /*qp_value; 15, 24, 26?*/
-    seq.min_qp = h264_encoder->min_qp;     /*1, 6, 10*/
-    seq.basic_unit_size = 0;
-    seq.intra_period = h264_encoder->intra_period;
-    seq.intra_idr_period = h264_encoder->intra_period;
-
-    va_status = vaCreateBuffer(va_dpy, context_id,
-                               VAEncSequenceParameterBufferType,
-                               sizeof(seq), 1, &seq, &priv->seq_param_id);
-    ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                         ENCODER_ENC_RES_ERR, "alloc seq-buffer failed.");
-    va_status = vaRenderPicture(va_dpy, context_id, &priv->seq_param_id, 1);
-    ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                         ENCODER_PICTURE_ERR, "vaRenderPicture seq-parameters failed.");
-  }
+static gboolean
+set_sequence_parameters(
+    GstVaapiEncoderH264 *encoder,
+    VAEncSequenceParameterBufferH264 *seq_param
+)
+{
+  seq_param->seq_parameter_set_id = 0;
+  seq_param->level_idc = encoder->level; /* 3.0 */
+  seq_param->intra_period = encoder->intra_period;
+  seq_param->intra_idr_period = encoder->intra_period;
+  seq_param->max_num_ref_frames = 1; /*Only I, P frames*/
+  seq_param->picture_width_in_mbs = (ENCODER_WIDTH(encoder)+15)/16;
+  seq_param->picture_height_in_mbs = (ENCODER_HEIGHT(encoder)+15)/16;
+
+  seq_param->bits_per_second = encoder->bitrate;
+  seq_param->frame_rate = ENCODER_FPS(encoder);
+  seq_param->initial_qp = encoder->init_qp; /*qp_value; 15, 24, 26?*/
+  seq_param->min_qp = encoder->min_qp;     /*1, 6, 10*/
+  seq_param->basic_unit_size = 0;
+  seq_param->vui_flag = FALSE;
 
-  /* set pic_parameters*/
-  if (!priv->ref_surface1) {
-    priv->ref_surface1 = gst_vaapi_context_get_surface(context);
-    ENCODER_CHECK_STATUS(priv->ref_surface1,
-                         ENCODER_SURFACE_ERR,
-                         "reference surface, h264_pop_free_surface failed.");
-  }
-  if (!priv->recon_surface) {
-    priv->recon_surface = gst_vaapi_context_get_surface(context);
-    ENCODER_CHECK_STATUS(priv->recon_surface,
-                         ENCODER_SURFACE_ERR,
-                         "reconstructed surface, h264_pop_free_surface failed.");
-  }
+  return TRUE;
+}
 
-  pic_param.reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface1);
-  pic_param.reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface);
-  pic_param.coded_buf = coded_buf;
-  pic_param.picture_width = ENCODER_WIDTH(h264_encoder);
-  pic_param.picture_height = ENCODER_HEIGHT(h264_encoder);
-  pic_param.last_picture = 0; // last pic or not
+static gboolean
+set_picture_parameters(
+    GstVaapiEncoderH264 *encoder,
+    VAEncPictureParameterBufferH264 *pic_param,
+    VABufferID coded_buf
+)
+{
+  GstVaapiEncoderH264Private *priv = encoder->priv;
 
-  if (VA_INVALID_ID != priv->pic_param_id) { /* share the same pic_param_id*/
-    vaDestroyBuffer(va_dpy, priv->pic_param_id);
-    priv->pic_param_id = VA_INVALID_ID;
-  }
-  va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
-                               sizeof(pic_param), 1, &pic_param, &priv->pic_param_id);
+  pic_param->reference_picture = GST_VAAPI_OBJECT_ID(priv->ref_surface1);
+  pic_param->reconstructed_picture = GST_VAAPI_OBJECT_ID(priv->recon_surface);
+  pic_param->coded_buf = coded_buf;
+  pic_param->picture_width = ENCODER_WIDTH(encoder);
+  pic_param->picture_height = ENCODER_HEIGHT(encoder);
+  pic_param->last_picture = 0; // last pic or not
 
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                       ENCODER_PICTURE_ERR,
-                       "creating pic-param buffer failed.");
+  return TRUE;
+}
 
-  va_status = vaRenderPicture(va_dpy, context_id, &priv->pic_param_id, 1);
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                       ENCODER_PICTURE_ERR,
-                       "rendering pic-param buffer failed.");
+static gboolean
+set_slices_parameters(
+    GstVaapiEncoderH264 *encoder,
+    VAEncSliceParameterBuffer *slices,
+    guint slice_num
+)
+{
+  GstVaapiEncoderH264Private *priv = encoder->priv;
+  VAEncSliceParameterBuffer *slice_param;
 
-  /* set slice parameters, support multiple slices */
   int i = 0;
   guint32 last_row_num = 0;
   guint32 slice_mod_num = priv->slice_mod_mb_num;
 
-  memset(priv->slice_param_buffers, 0, h264_encoder->slice_num*sizeof(priv->slice_param_buffers[0]));
-  for (i = 0; i < h264_encoder->slice_num; ++i) {
-    slice_param = &priv->slice_param_buffers[i];
+  for (i = 0; i < slice_num; ++i) {
+    slice_param = &slices[i];
     slice_param->start_row_number = last_row_num;               /* unit MB*/
     slice_param->slice_height = priv->default_slice_height; /* unit MB */
     if (slice_mod_num) {
@@ -678,40 +662,15 @@ gst_vaapi_encoder_h264_rendering(GstVaapiBaseEncoder *encoder, GstVaapiDisplay *
       --slice_mod_num;
     }
     last_row_num += slice_param->slice_height;
-    slice_param->slice_flags.bits.is_intra = *is_key;
-    slice_param->slice_flags.bits.disable_deblocking_filter_idc = 0;
-
+    slice_param->slice_flags.bits.is_intra =
+        (priv->cur_slice_type == SLICE_TYPE_I);
+    slice_param->slice_flags.bits.disable_deblocking_filter_idc = FALSE;
+    slice_param->slice_flags.bits.uses_long_term_ref = FALSE;
+    slice_param->slice_flags.bits.is_long_term_ref = FALSE;
   }
-  ENCODER_ASSERT(last_row_num == (ENCODER_HEIGHT(h264_encoder)+15)/16);
-
-  if (VA_INVALID_ID != priv->slice_param_id) {
-    vaDestroyBuffer(va_dpy, priv->slice_param_id);
-    priv->slice_param_id = VA_INVALID_ID;
-  }
-  va_status = vaCreateBuffer(va_dpy,
-                             context_id,
-                             VAEncSliceParameterBufferType,
-                             sizeof(priv->slice_param_buffers[0]),
-                             h264_encoder->slice_num,
-                             priv->slice_param_buffers,
-                             &priv->slice_param_id);
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
-                       ENCODER_PICTURE_ERR,
-                       "creating slice-parameters buffer failed.");
-
-  va_status = vaRenderPicture(va_dpy, context_id, &priv->slice_param_id, 1);
-  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                       ENCODER_PICTURE_ERR,
-                       "rendering slice-parameters buffer failed.");
-
-  /*after finished, set ref_surface1_index, recon_surface_index */
-  GstVaapiSurface *swap = priv->ref_surface1;
-  priv->ref_surface1 = priv->recon_surface;
-  priv->recon_surface = swap;
 
-  end:
-  ENCODER_RELEASE_DISPLAY_LOCK(display);
-  return ret;
+  ENCODER_ASSERT(last_row_num == (ENCODER_HEIGHT(encoder)+15)/16);
+  return TRUE;
 }
 
 #else  /* extended libva, new parameter structures*/
@@ -799,81 +758,71 @@ set_sequence_parameters(
 }
 
 static gboolean
-h264_fill_sequence_buffer(GstVaapiEncoderH264 *encoder)
+ensure_packed_sps_data(
+    GstVaapiEncoderH264 *encoder,
+    VAEncSequenceParameterBufferH264 *seq_param
+)
 {
   GstVaapiEncoderH264Private *priv = encoder->priv;
-  VAEncSequenceParameterBufferH264 seq_param = { 0 };
-  VADisplay va_dpy       = ENCODER_VA_DISPLAY(encoder);
+  VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+  VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder);
   VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
+  guint32 length_in_bits;
+  guint8 *packed_seq_buffer = NULL;
+  H264Bitstream bitstream;
   gboolean ret = TRUE;
   VAStatus va_status = VA_STATUS_SUCCESS;
 
-  /* only once */
-  if (VA_INVALID_ID != priv->seq_param_id)
+  if (priv->sps_data) 
     return TRUE;
 
-  set_sequence_parameters(encoder, &seq_param);
-  va_status = vaCreateBuffer(va_dpy, context_id,
-                             VAEncSequenceParameterBufferType,
-                             sizeof(seq_param), 1,
-                             &seq_param, &priv->seq_param_id);
+  h264_bitstream_init(&bitstream, 128*8);
+  h264_bitstream_write_uint(&bitstream, 0x00000001, 32); /* start code*/
+  h264_bitstream_write_nal_header(&bitstream, NAL_REF_IDC_HIGH, NAL_SPS);
+  h264_bitstream_write_sps(&bitstream, seq_param, encoder->profile);
+  ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0);
+  length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream);
+  packed_seq_buffer = BIT_STREAM_BUFFER(&bitstream);
+
+  /* set codec data sps */
+  priv->sps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8);
+  GST_BUFFER_SIZE(priv->sps_data) = (length_in_bits+7)/8-4; /* start code size == 4*/
+  memcpy(GST_BUFFER_DATA(priv->sps_data),
+         packed_seq_buffer+4,
+         GST_BUFFER_SIZE(priv->sps_data));
+
+  packed_header_param_buffer.type = VAEncPackedHeaderSequence;
+  packed_header_param_buffer.bit_length = length_in_bits;
+  packed_header_param_buffer.has_emulation_bytes = 0;
+  va_status = vaCreateBuffer(va_dpy,
+                             context_id,
+                             VAEncPackedHeaderParameterBufferType,
+                             sizeof(packed_header_param_buffer), 1,
+                             &packed_header_param_buffer,
+                             &priv->packed_seq_param_id);
   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
                        FALSE,
-                       "alloc seq-buffer failed.");
-
-  /*pack sps header buffer/data */
-  if (NULL == priv->sps_data) {
-    VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
-    guint32 length_in_bits;
-    guint8 *packed_seq_buffer = NULL;
-    H264Bitstream bitstream;
-    h264_bitstream_init(&bitstream, 128*8);
-    h264_bitstream_write_uint(&bitstream, 0x00000001, 32); /* start code*/
-    h264_bitstream_write_nal_header(&bitstream, NAL_REF_IDC_HIGH, NAL_SPS);
-    h264_bitstream_write_sps(&bitstream, &seq_param, encoder->profile);
-    ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0);
-    length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream);
-    packed_seq_buffer = BIT_STREAM_BUFFER(&bitstream);
-
-    /* set codec data sps */
-    priv->sps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8);
-    GST_BUFFER_SIZE(priv->sps_data) = (length_in_bits+7)/8-4; /* start code size == 4*/
-    memcpy(GST_BUFFER_DATA(priv->sps_data),
-           packed_seq_buffer+4,
-           GST_BUFFER_SIZE(priv->sps_data));
-
-    packed_header_param_buffer.type = VAEncPackedHeaderSequence;
-    packed_header_param_buffer.bit_length = length_in_bits;
-    packed_header_param_buffer.has_emulation_bytes = 0;
-    va_status = vaCreateBuffer(va_dpy,
-                               context_id,
-                               VAEncPackedHeaderParameterBufferType,
-                               sizeof(packed_header_param_buffer), 1,
-                               &packed_header_param_buffer,
-                               &priv->packed_seq_param_id);
-    ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                         FALSE,
-                         "EncPackedSeqHeaderParameterBuffer failed");
-    va_status = vaCreateBuffer(va_dpy,
-                               context_id,
-                               VAEncPackedHeaderDataBufferType,
-                               (length_in_bits + 7) / 8, 1,
-                               packed_seq_buffer,
-                               &priv->packed_seq_data_id);
-    h264_bitstream_destroy(&bitstream, TRUE);
-    ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                         FALSE,
-                         "EncPackedSeqHeaderDataBuffer failed");
-  }
+                       "EncPackedSeqHeaderParameterBuffer failed");
+  va_status = vaCreateBuffer(va_dpy,
+                             context_id,
+                             VAEncPackedHeaderDataBufferType,
+                             (length_in_bits + 7) / 8, 1,
+                             packed_seq_buffer,
+                             &priv->packed_seq_data_id);
+  h264_bitstream_destroy(&bitstream, TRUE);
+  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+                       FALSE,
+                       "EncPackedSeqHeaderDataBuffer failed");
 end:
+    return ret;
 
-  return ret;
 }
 
 static gboolean
 set_picture_parameters(
     GstVaapiEncoderH264 *encoder,
-    VAEncPictureParameterBufferH264 *pic_param
+    VAEncPictureParameterBufferH264 *pic_param,
+    VABufferID coded_buf
 )
 {
   GstVaapiEncoderH264Private *priv = encoder->priv;
@@ -905,140 +854,101 @@ set_picture_parameters(
   pic_param->pic_fields.bits.pic_order_present_flag = FALSE;
   pic_param->pic_fields.bits.pic_scaling_matrix_present_flag = FALSE;
 
-  return TRUE;
-}
+  /* reference list,  */
+  pic_param->CurrPic.picture_id = GST_VAAPI_OBJECT_ID(priv->recon_surface);
+  pic_param->CurrPic.TopFieldOrderCnt = priv->cur_display_num * 2;   // ??? /**/
+  pic_param->ReferenceFrames[0].picture_id = GST_VAAPI_OBJECT_ID(priv->ref_surface1);
+  pic_param->ReferenceFrames[1].picture_id = GST_VAAPI_OBJECT_ID(priv->ref_surface2);
+  pic_param->ReferenceFrames[2].picture_id = VA_INVALID_ID;
+  pic_param->coded_buf = coded_buf;
 
-static inline const char *
-get_slice_type(H264_SLICE_TYPE type)
-{
-    switch (type) {
-    case SLICE_TYPE_I:
-        return "I";
-    case SLICE_TYPE_P:
-        return "P";
-    case SLICE_TYPE_B:
-        return "B";
-    default:
-        return "Unknown";
-    }
+  ENCODER_LOG_INFO("type:%s, frame_num:%d, display_num:%d",
+    get_slice_type(priv->cur_slice_type),
+    pic_param->frame_num,
+    pic_param->CurrPic.TopFieldOrderCnt);
+  return TRUE;
 }
 
 static gboolean
-h264_fill_picture_buffer(
+ensure_packed_pps_data(
     GstVaapiEncoderH264 *encoder,
-    VABufferID coded_buf
+    VAEncPictureParameterBufferH264 *pic_param
 )
 {
   GstVaapiEncoderH264Private *priv = encoder->priv;
-  VAEncPictureParameterBufferH264 pic_param;
-  VADisplay va_dpy       = ENCODER_VA_DISPLAY(encoder);
+  VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+  H264Bitstream bitstream;
+  VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder);
   VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
+  guint32 length_in_bits;
+  guint8 *packed_pic_buffer = NULL;
   gboolean ret = TRUE;
   VAStatus va_status = VA_STATUS_SUCCESS;
 
-  VAAPI_UNUSED_ARG(va_status);
-  memset(&pic_param, 0, sizeof(pic_param));
-  set_picture_parameters(encoder, &pic_param);
-  pic_param.CurrPic.picture_id = GST_VAAPI_OBJECT_ID(priv->recon_surface);
-  pic_param.CurrPic.TopFieldOrderCnt = priv->cur_display_num * 2;   // ??? /**/
-  pic_param.ReferenceFrames[0].picture_id = GST_VAAPI_OBJECT_ID(priv->ref_surface1);
-  pic_param.ReferenceFrames[1].picture_id = GST_VAAPI_OBJECT_ID(priv->ref_surface2);
-  pic_param.ReferenceFrames[2].picture_id = VA_INVALID_ID;
-  pic_param.coded_buf = coded_buf;
+  if (VA_INVALID_ID != priv->packed_pic_data_id)
+      return TRUE;
 
-  ENCODER_LOG_INFO("type:%s, frame_num:%d, display_num:%d",
-    get_slice_type(priv->cur_slice_type),
-    pic_param.frame_num,
-    pic_param.CurrPic.TopFieldOrderCnt);
+  h264_bitstream_init(&bitstream, 128*8);
+  h264_bitstream_write_uint(&bitstream, 0x00000001, 32); /* start code*/
+  h264_bitstream_write_nal_header(&bitstream, NAL_REF_IDC_HIGH, NAL_PPS);
+  h264_bitstream_write_pps(&bitstream, pic_param);
+  ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0);
+  length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream);
+  packed_pic_buffer = BIT_STREAM_BUFFER(&bitstream);
+
+  /*set codec data pps*/
+  priv->pps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8);
+  GST_BUFFER_SIZE(priv->pps_data) = (length_in_bits+7)/8-4;
+  memcpy(GST_BUFFER_DATA(priv->pps_data),
+         packed_pic_buffer+4,
+         GST_BUFFER_SIZE(priv->pps_data));
+
+  packed_header_param_buffer.type = VAEncPackedHeaderPicture;
+  packed_header_param_buffer.bit_length = length_in_bits;
+  packed_header_param_buffer.has_emulation_bytes = 0;
 
-  if (VA_INVALID_ID != priv->pic_param_id) { /* share the same pic_param_id*/
-    vaDestroyBuffer(va_dpy, priv->pic_param_id);
-    priv->pic_param_id = VA_INVALID_ID;
-  }
   va_status = vaCreateBuffer(va_dpy,
                              context_id,
-                             VAEncPictureParameterBufferType,
-                             sizeof(pic_param), 1,
-                             &pic_param,
-                             &priv->pic_param_id);
-
+                             VAEncPackedHeaderParameterBufferType,
+                             sizeof(packed_header_param_buffer), 1,
+                             &packed_header_param_buffer,
+                             &priv->packed_pic_param_id);
   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
                        FALSE,
-                       "creating pic-param buffer failed.");
+                       "EncPackedPicHeaderParameterBuffer failed");
 
-  if (VA_INVALID_ID == priv->packed_pic_data_id) {
-    VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
-    guint32 length_in_bits;
-    guint8 *packed_pic_buffer = NULL;
-    H264Bitstream bitstream;
-    h264_bitstream_init(&bitstream, 128*8);
-    h264_bitstream_write_uint(&bitstream, 0x00000001, 32); /* start code*/
-    h264_bitstream_write_nal_header(&bitstream, NAL_REF_IDC_HIGH, NAL_PPS);
-    h264_bitstream_write_pps(&bitstream, &pic_param);
-    ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0);
-    length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream);
-    packed_pic_buffer = BIT_STREAM_BUFFER(&bitstream);
-
-    /*set codec data pps*/
-    priv->pps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8);
-    GST_BUFFER_SIZE(priv->pps_data) = (length_in_bits+7)/8-4;
-    memcpy(GST_BUFFER_DATA(priv->pps_data), packed_pic_buffer+4, GST_BUFFER_SIZE(priv->pps_data));
-
-    packed_header_param_buffer.type = VAEncPackedHeaderPicture;
-    packed_header_param_buffer.bit_length = length_in_bits;
-    packed_header_param_buffer.has_emulation_bytes = 0;
-
-    va_status = vaCreateBuffer(va_dpy,
-                               context_id,
-                               VAEncPackedHeaderParameterBufferType,
-                               sizeof(packed_header_param_buffer), 1,
-                               &packed_header_param_buffer,
-                               &priv->packed_pic_param_id);
-    ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                         FALSE,
-                         "EncPackedPicHeaderParameterBuffer failed");
-
-    va_status = vaCreateBuffer(va_dpy,
-                               context_id,
-                               VAEncPackedHeaderDataBufferType,
-                               (length_in_bits + 7) / 8, 1,
-                               packed_pic_buffer,
-                               &priv->packed_pic_data_id);
-    h264_bitstream_destroy(&bitstream, TRUE);
-    ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
-                         FALSE,
-                         "EncPackedPicHeaderDataBuffer failed");
-  }
+  va_status = vaCreateBuffer(va_dpy,
+                             context_id,
+                             VAEncPackedHeaderDataBufferType,
+                             (length_in_bits + 7) / 8, 1,
+                             packed_pic_buffer,
+                             &priv->packed_pic_data_id);
+  h264_bitstream_destroy(&bitstream, TRUE);
+  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+                       FALSE,
+                       "EncPackedPicHeaderDataBuffer failed");
 end:
   return ret;
 }
 
-
 static gboolean
-h264_fill_slice_buffers(
-    GstVaapiEncoderH264 *encoder
+set_slices_parameters(
+    GstVaapiEncoderH264 *encoder,
+    VAEncSliceParameterBufferH264 *slices,
+    guint slice_num
 )
 {
   GstVaapiEncoderH264Private *priv = encoder->priv;
-  VAEncSliceParameterBufferH264 *slice_param = NULL;
-  VADisplay va_dpy       = ENCODER_VA_DISPLAY(encoder);
-  VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
-  guint width_in_mbs;
-  gboolean ret = TRUE;
-  VAStatus va_status = VA_STATUS_SUCCESS;
-
-  width_in_mbs = (ENCODER_WIDTH(encoder)+15)/16;
+  VAEncSliceParameterBufferH264 *slice_param;
 
+  guint width_in_mbs = (ENCODER_WIDTH(encoder)+15)/16;
   int i = 0;
   guint32 last_row_num = 0;
   guint32 slice_mod_num = priv->slice_mod_mb_num;
 
-  memset(priv->slice_param_buffers,
-         0,
-         encoder->slice_num*sizeof(priv->slice_param_buffers[0]));
-  for (i = 0; i < encoder->slice_num; ++i) {
+  for (i = 0; i < slice_num; ++i) {
     int i_pic = 0;
-    slice_param = &priv->slice_param_buffers[i];
+    slice_param = slices + i;
 
     slice_param->macroblock_address = last_row_num*width_in_mbs;
     slice_param->num_macroblocks = width_in_mbs*priv->default_slice_height;
@@ -1111,6 +1021,98 @@ h264_fill_slice_buffers(
 
   }
   ENCODER_ASSERT(last_row_num == (ENCODER_HEIGHT(encoder)+15)/16);
+  return TRUE;
+}
+
+#endif
+
+static gboolean
+h264_fill_sequence_buffer(GstVaapiEncoderH264 *encoder)
+{
+  GstVaapiEncoderH264Private *priv = encoder->priv;
+  VAEncSequenceParameterBufferH264 seq_param = { 0 };
+  VADisplay va_dpy       = ENCODER_VA_DISPLAY(encoder);
+  VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
+  gboolean ret = TRUE;
+  VAStatus va_status = VA_STATUS_SUCCESS;
+
+  /* only once */
+  if (VA_INVALID_ID != priv->seq_param_id)
+    return TRUE;
+
+  set_sequence_parameters(encoder, &seq_param);
+  va_status = vaCreateBuffer(va_dpy, context_id,
+                             VAEncSequenceParameterBufferType,
+                             sizeof(seq_param), 1,
+                             &seq_param, &priv->seq_param_id);
+  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+                       FALSE,
+                       "alloc seq-buffer failed.");
+
+#if !HAVE_OLD_H264_ENCODER
+  ensure_packed_sps_data(encoder, &seq_param);
+#endif
+
+end:
+  return ret;
+}
+
+static gboolean
+h264_fill_picture_buffer(
+    GstVaapiEncoderH264 *encoder,
+    VABufferID coded_buf
+)
+{
+  GstVaapiEncoderH264Private *priv = encoder->priv;
+  VAEncPictureParameterBufferH264 pic_param;
+  VADisplay va_dpy = ENCODER_VA_DISPLAY(encoder);
+  VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
+  gboolean ret = TRUE;
+  VAStatus va_status = VA_STATUS_SUCCESS;
+
+  VAAPI_UNUSED_ARG(va_status);
+  memset(&pic_param, 0, sizeof(pic_param));
+  set_picture_parameters(encoder, &pic_param, coded_buf);
+
+  if (VA_INVALID_ID != priv->pic_param_id) { /* share the same pic_param_id*/
+    vaDestroyBuffer(va_dpy, priv->pic_param_id);
+    priv->pic_param_id = VA_INVALID_ID;
+  }
+  va_status = vaCreateBuffer(va_dpy,
+                             context_id,
+                             VAEncPictureParameterBufferType,
+                             sizeof(pic_param), 1,
+                             &pic_param,
+                             &priv->pic_param_id);
+
+  ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+                       FALSE,
+                       "creating pic-param buffer failed.");
+#if !HAVE_OLD_H264_ENCODER
+  ensure_packed_pps_data(encoder, &pic_param);
+#endif
+
+end:
+  return ret;
+}
+
+static gboolean
+h264_fill_slice_buffers(
+    GstVaapiEncoderH264 *encoder
+)
+{
+  GstVaapiEncoderH264Private *priv = encoder->priv;
+  VADisplay va_dpy       = ENCODER_VA_DISPLAY(encoder);
+  VAContextID context_id = ENCODER_VA_CONTEXT(encoder);
+  gboolean ret = TRUE;
+  VAStatus va_status = VA_STATUS_SUCCESS;
+
+  memset(priv->slice_param_buffers,
+         0,
+         encoder->slice_num * sizeof(priv->slice_param_buffers[0]));
+  set_slices_parameters(encoder,
+                        priv->slice_param_buffers,
+                        encoder->slice_num);
 
   if (VA_INVALID_ID != priv->slice_param_id) {
     vaDestroyBuffer(va_dpy, priv->slice_param_id);
@@ -1246,8 +1248,6 @@ gst_vaapi_encoder_h264_rendering(
   return ret;
 }
 
-#endif
-
 static const guint8 *
 h264_next_nal(const guint8 *buffer, guint32 len, guint32 *nal_size)
 {
@@ -1837,6 +1837,8 @@ h264_bitstream_write_nal_header(
   return TRUE;
 }
 
+#if !HAVE_OLD_H264_ENCODER
+
 static gboolean
 h264_bitstream_write_sps(
     H264Bitstream *bitstream,
@@ -2060,3 +2062,4 @@ h264_bitstream_write_pps(
   h264_bitstream_write_trailing_bits(bitstream);
   return TRUE;
 }
+#endif