+#else /* extended libva, new parameter structures*/
+
+static void h264_swap_surface(GstVaapiSurface **s1, GstVaapiSurface **s2)
+{
+ GstVaapiSurface *tmp;
+
+ g_return_if_fail(s1 && s2);
+ tmp = *s1;
+ *s1 = *s2;
+ *s2 = tmp;
+}
+
+static gboolean
+h264_recreate_seq_param(GstH264Encoder *h264_encoder,
+ VADisplay va_dpy, VAContextID context_id)
+{
+ GstH264EncoderPrivate *h264_prv = GST_H264_ENCODER_GET_PRIVATE(h264_encoder);
+ VAEncSequenceParameterBufferH264 seq_h264 = { 0 };
+ guint width_in_mbs, height_in_mbs;
+ gboolean ret = TRUE;
+ VAStatus va_status = VA_STATUS_SUCCESS;
+
+ /* only once */
+ if (VA_INVALID_ID != h264_prv->seq_parameter)
+ return TRUE;
+
+ width_in_mbs = (ENCODER_WIDTH(h264_encoder)+15)/16;
+ height_in_mbs = (ENCODER_HEIGHT(h264_encoder)+15)/16;
+
+ seq_h264.seq_parameter_set_id = 0;
+ seq_h264.profile_idc = h264_encoder->profile;
+ seq_h264.level_idc = h264_encoder->level; /* 3.0 */
+ seq_h264.intra_period = h264_encoder->intra_period;
+ seq_h264.ip_period = 0; // ?
+ seq_h264.max_num_ref_frames = (h264_encoder->b_frame_num < 2 ? 3 : h264_encoder->b_frame_num+1); // ?, why 4
+ seq_h264.picture_width_in_mbs = width_in_mbs;
+ seq_h264.picture_height_in_mbs = height_in_mbs;
+ seq_h264.frame_mbs_only_flag = 1;
+ seq_h264.target_usage = 1; // ?
+
+ if (h264_encoder->init_qp == -1)
+ seq_h264.rate_control_method = BR_CBR;
+ else if (h264_encoder->init_qp == -2)
+ seq_h264.rate_control_method = BR_VBR;
+ else {
+ ENCODER_ASSERT(h264_encoder->init_qp >= 0 && h264_encoder->init_qp <= 51);
+ seq_h264.rate_control_method = BR_CQP;
+ }
+
+ if (h264_encoder->bitrate> 0)
+ seq_h264.bits_per_second = h264_encoder->bitrate; /* use kbps as input */
+ else
+ seq_h264.bits_per_second = 0;
+
+ if (seq_h264.rate_control_method == BR_VBR) {
+ seq_h264.max_bits_per_second = seq_h264.bits_per_second*1.5;
+ seq_h264.min_bits_per_second = seq_h264.bits_per_second*0.3;
+ }
+ seq_h264.initial_hrd_buffer_fullness = 0; // ??
+ seq_h264.hrd_buffer_size = 0;
+ seq_h264.num_units_in_tick = 100;
+ seq_h264.time_scale = ENCODER_FPS(h264_encoder)*2*seq_h264.num_units_in_tick;
+
+ if (height_in_mbs*16 - ENCODER_HEIGHT(h264_encoder)) {
+ seq_h264.frame_cropping_flag = 1;
+ seq_h264.frame_crop_left_offset = 0;
+ seq_h264.frame_crop_right_offset = 0;
+ seq_h264.frame_crop_top_offset = 0;
+ seq_h264.frame_crop_bottom_offset =
+ (height_in_mbs * 16 - ENCODER_HEIGHT(h264_encoder))/(2 * (!seq_h264.frame_mbs_only_flag + 1));
+ }
+ seq_h264.pic_order_cnt_type = 0; // pic order cnt
+ seq_h264.direct_8x8_inference_flag = 0;
+ seq_h264.log2_max_frame_num_minus4 = 4; // log2(seq_h264.intra_period)-3 : 0
+ seq_h264.log2_max_pic_order_cnt_lsb_minus4 = seq_h264.log2_max_frame_num_minus4+2;
+ seq_h264.vui_flag = 0; // 0? or 1?
+
+ va_status = vaCreateBuffer(va_dpy, context_id,
+ VAEncSequenceParameterBufferType,
+ sizeof(seq_h264), 1,
+ &seq_h264, &h264_prv->seq_parameter);
+ ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+ FALSE, "alloc seq-buffer failed.");
+
+ /*pack sps header buffer/data */
+ if (NULL == h264_prv->sps_data) {
+ VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+ guint32 length_in_bits, offset_in_bytes;
+ 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_h264);
+ ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0);
+ length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream);
+ packed_seq_buffer = BIT_STREAM_BUFFER(&bitstream);
+ //h264_prv->sps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8);
+ //GST_BUFFER_SIZE(h264_prv->sps_data) = (length_in_bits+7)/8-4;
+ //memcpy(GST_BUFFER_DATA(h264_prv->sps_data), packed_seq_buffer+4, (length_in_bits+7)/8-4);
+
+ offset_in_bytes = 0;
+ packed_header_param_buffer.type = VAEncPackedHeaderSPS;
+ packed_header_param_buffer.insert_emulation_bytes = 1;
+ packed_header_param_buffer.skip_emulation_check_count = 5;
+ packed_header_param_buffer.num_headers = 1;
+ packed_header_param_buffer.length_in_bits = &length_in_bits;
+ packed_header_param_buffer.offset_in_bytes = &offset_in_bytes;
+ va_status = vaCreateBuffer(va_dpy,
+ context_id,
+ VAEncPackedHeaderParameterBufferType,
+ sizeof(packed_header_param_buffer), 1,
+ &packed_header_param_buffer,
+ &h264_prv->packed_sps_par_buf);
+ 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,
+ &h264_prv->packed_sps_data_buf);
+ h264_bitstream_destroy(&bitstream, TRUE);
+ ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+ FALSE,
+ "EncPackedSeqHeaderDataBuffer failed");
+ }
+end:
+
+ return ret;
+}
+
+static gboolean
+h264_recreate_pic_param(GstH264Encoder *h264_encoder,
+ VADisplay va_dpy, VAContextID context_id,
+ VABufferID coded_buf)
+{
+ GstH264EncoderPrivate *h264_prv = GST_H264_ENCODER_GET_PRIVATE(h264_encoder);
+ VAEncPictureParameterBufferH264 pic_h264;
+ gboolean ret = TRUE;
+ VAStatus va_status = VA_STATUS_SUCCESS;
+
+ VAAPI_UNUSED_ARG(va_status);
+ memset(&pic_h264, 0, sizeof(pic_h264));
+ pic_h264.CurrPic.picture_id = GST_VAAPI_OBJECT_ID(h264_prv->recon_surface);
+ pic_h264.CurrPic.TopFieldOrderCnt = h264_prv->cur_display_num * 2; // ??? /**/
+ pic_h264.ReferenceFrames[0].picture_id = GST_VAAPI_OBJECT_ID(h264_prv->ref_surface1);
+ pic_h264.ReferenceFrames[1].picture_id = GST_VAAPI_OBJECT_ID(h264_prv->ref_surface2);
+ pic_h264.ReferenceFrames[2].picture_id = VA_INVALID_ID;
+ pic_h264.CodedBuf = coded_buf;
+
+ pic_h264.seq_parameter_set_id = 0;
+ pic_h264.pic_parameter_set_id = 0;
+ pic_h264.last_picture = 0;
+ pic_h264.frame_num = (h264_prv->cur_slice_type == SLICE_TYPE_B ?
+ (h264_prv->cur_decode_num + 1) : h264_prv->cur_decode_num);
+ pic_h264.coding_type = 0;
+ pic_h264.pic_init_qp = (h264_encoder->init_qp >= 0 ? h264_encoder->init_qp : 26);
+ pic_h264.num_ref_idx_l0_active_minus1 = 0;
+ pic_h264.num_ref_idx_l1_active_minus1 = 0;
+ pic_h264.pic_fields.bits.idr_pic_flag = (h264_prv->cur_slice_type == SLICE_TYPE_I);
+ pic_h264.pic_fields.bits.reference_pic_flag = (h264_prv->cur_slice_type != SLICE_TYPE_B);
+ pic_h264.pic_fields.bits.entropy_coding_mode_flag = ENTROPY_MODE_CABAC;
+ pic_h264.pic_fields.bits.weighted_pred_flag = 0;
+ pic_h264.pic_fields.bits.weighted_bipred_idc = 0;
+ pic_h264.pic_fields.bits.transform_8x8_mode_flag = 1;
+ pic_h264.pic_fields.bits.deblocking_filter_control_present_flag = 1;
+
+ char *frame_type = "I";
+ if (h264_prv->cur_slice_type == SLICE_TYPE_P)
+ frame_type = "P";
+ if (h264_prv->cur_slice_type == SLICE_TYPE_B)
+ frame_type = "B";
+ ENCODER_LOG_INFO("type:%s, frame_num:%d, display_num:%d",
+ frame_type, pic_h264.frame_num, pic_h264.CurrPic.TopFieldOrderCnt);
+
+ if (VA_INVALID_ID != h264_prv->pic_parameter) { /* share the same pic_parameter*/
+ vaDestroyBuffer(va_dpy, h264_prv->pic_parameter);
+ h264_prv->pic_parameter = VA_INVALID_ID;
+ }
+ va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
+ sizeof(pic_h264), 1, &pic_h264, &h264_prv->pic_parameter);
+
+ ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
+ FALSE, "creating pic-param buffer failed.");
+
+ //if (NULL == h264_prv->pps_data) {
+ if (VA_INVALID_ID == h264_prv->packed_pps_data_buf) {
+ VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+ guint32 length_in_bits, offset_in_bytes;
+ 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_h264);
+ ENCODER_ASSERT(BIT_STREAM_BIT_SIZE(&bitstream)%8 == 0);
+ length_in_bits = BIT_STREAM_BIT_SIZE(&bitstream);
+ packed_pic_buffer = BIT_STREAM_BUFFER(&bitstream);
+ //h264_prv->pps_data = gst_buffer_new_and_alloc((length_in_bits+7)/8);
+ //GST_BUFFER_SIZE(h264_prv->pps_data) = (length_in_bits+7)/8-4;
+ //memcpy(GST_BUFFER_DATA(h264_prv->pps_data), packed_pic_buffer+4, (length_in_bits+7)/8-4);
+
+ offset_in_bytes = 0;
+ packed_header_param_buffer.type = VAEncPackedHeaderPPS;
+ packed_header_param_buffer.insert_emulation_bytes = 1;
+ packed_header_param_buffer.skip_emulation_check_count = 5;
+ packed_header_param_buffer.num_headers = 1;
+ packed_header_param_buffer.length_in_bits = &length_in_bits;
+ packed_header_param_buffer.offset_in_bytes = &offset_in_bytes;
+
+ va_status = vaCreateBuffer(va_dpy,
+ context_id,
+ VAEncPackedHeaderParameterBufferType,
+ sizeof(packed_header_param_buffer), 1,
+ &packed_header_param_buffer,
+ &h264_prv->packed_pps_par_buf);
+ 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,
+ &h264_prv->packed_pps_data_buf);
+ h264_bitstream_destroy(&bitstream, TRUE);
+ ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
+ FALSE,
+ "EncPackedPicHeaderDataBuffer failed");
+ }
+
+end:
+ return ret;
+}
+
+
+static gboolean
+h264_recreate_slice_param(GstH264Encoder *h264_encoder,
+ VADisplay va_dpy, VAContextID context_id)
+{
+ GstH264EncoderPrivate *h264_prv = GST_H264_ENCODER_GET_PRIVATE(h264_encoder);
+ VAEncSliceParameterBufferH264 *slice_h264 = NULL;
+ guint width_in_mbs;
+ gboolean ret = TRUE;
+ VAStatus va_status = VA_STATUS_SUCCESS;
+
+ width_in_mbs = (ENCODER_WIDTH(h264_encoder)+15)/16;
+
+ int i = 0;
+ guint32 last_row_num = 0;
+ guint32 slice_mod_num = h264_prv->slice_mod_mb_num;
+
+ memset(h264_prv->slice_param_buffers, 0, h264_encoder->slice_num*sizeof(h264_prv->slice_param_buffers[0]));
+ for (i = 0; i < h264_encoder->slice_num; ++i) {
+ slice_h264 = &h264_prv->slice_param_buffers[i];
+
+ slice_h264->starting_macroblock_address = last_row_num*width_in_mbs;
+ slice_h264->number_of_mbs = width_in_mbs*h264_prv->default_slice_height;
+ last_row_num += h264_prv->default_slice_height;
+ if (slice_mod_num) {
+ slice_h264->number_of_mbs += width_in_mbs;
+ ++last_row_num;
+ --slice_mod_num;
+ }
+ slice_h264->pic_parameter_set_id = 0;
+ slice_h264->slice_type = h264_prv->cur_slice_type;
+ slice_h264->direct_spatial_mv_pred_flag = 0;
+ slice_h264->num_ref_idx_l0_active_minus1 = 0;
+ slice_h264->num_ref_idx_l1_active_minus1 = 0;
+ slice_h264->cabac_init_idc = 0;
+ slice_h264->slice_qp_delta = 0;
+ slice_h264->disable_deblocking_filter_idc = 0;
+ slice_h264->slice_alpha_c0_offset_div2 = 2;
+ slice_h264->slice_beta_offset_div2 = 2;
+ slice_h264->idr_pic_id = 0;
+
+ slice_h264->ref_pic_list_modification_flag_l0 = 0;
+ slice_h264->ref_pic_list_modification_flag_l1 = 0;
+
+ }
+ ENCODER_ASSERT(last_row_num == (ENCODER_HEIGHT(h264_encoder)+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(h264_prv->slice_param_buffers[0]),
+ h264_encoder->slice_num,
+ h264_prv->slice_param_buffers,
+ &h264_prv->slice_parameter);
+ ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
+ FALSE, "creating slice-parameters buffer failed.");
+
+end:
+ return ret;
+}
+
+static EncoderStatus
+gst_h264_encoder_rendering(GstVaapiBaseEncoder *encoder, GstVaapiDisplay *display,
+ GstVaapiContext *context, GstVaapiSurface *surface,
+ guint frame_index, VABufferID coded_buf, gboolean *is_key)
+{
+ EncoderStatus ret = ENCODER_NO_ERROR;
+ VAStatus va_status = VA_STATUS_SUCCESS;
+ GstH264Encoder *h264_encoder = GST_H264_ENCODER(encoder);
+ GstH264EncoderPrivate *h264_prv = GST_H264_ENCODER_GET_PRIVATE(h264_encoder);
+ VABufferID va_buffers[64];
+ guint32 va_buffers_count = 0;
+ gboolean is_params_ok = TRUE;
+
+ 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);
+
+ *is_key = (h264_prv->cur_slice_type == SLICE_TYPE_I);
+
+ if (!h264_prv->ref_surface1) {
+ h264_prv->ref_surface1 = gst_vaapi_context_get_surface(context);
+ ENCODER_CHECK_STATUS(h264_prv->ref_surface1,
+ ENCODER_SURFACE_ERR,
+ "reference surface, h264_pop_free_surface failed.");
+ }
+ if (!h264_prv->ref_surface2) {
+ h264_prv->ref_surface2 = gst_vaapi_context_get_surface(context);
+ ENCODER_CHECK_STATUS(h264_prv->ref_surface2,
+ ENCODER_SURFACE_ERR,
+ "reference surface, h264_pop_free_surface failed.");
+ }
+ if (!h264_prv->recon_surface) {
+ h264_prv->recon_surface = gst_vaapi_context_get_surface(context);
+ ENCODER_CHECK_STATUS(h264_prv->recon_surface,
+ ENCODER_SURFACE_ERR,
+ "reconstructed surface, h264_pop_free_surface failed.");
+ }
+
+ if (SLICE_TYPE_P == h264_prv->cur_slice_type) {
+ h264_swap_surface(&h264_prv->ref_surface1, &h264_prv->ref_surface2);
+ }
+
+ /* set sequence parameters, need set every time */
+ is_params_ok = h264_recreate_seq_param(h264_encoder, va_dpy, context_id);
+ ENCODER_CHECK_STATUS(is_params_ok, ENCODER_PARAMETER_ERR,
+ "h264_recreate_seq_param failed");
+ /* set pic_parameters*/
+ is_params_ok = h264_recreate_pic_param(h264_encoder, va_dpy, context_id, coded_buf);
+ ENCODER_CHECK_STATUS(is_params_ok, ENCODER_PARAMETER_ERR,
+ "h264_recreate_pic_param failed");
+ /* set slice parameters, support multiple slices */
+ is_params_ok = h264_recreate_slice_param(h264_encoder, va_dpy, context_id);
+ ENCODER_CHECK_STATUS(is_params_ok, ENCODER_PARAMETER_ERR,
+ "h264_recreate_slice_param failed");
+
+ /* lock display */
+ ENCODER_ACQUIRE_DISPLAY_LOCK(display);
+
+ /*render all buffers*/
+ if (VA_INVALID_ID != h264_prv->seq_parameter) {
+ va_buffers[va_buffers_count++] = h264_prv->seq_parameter;
+ }
+ if (VA_INVALID_ID != h264_prv->pic_parameter) {
+ va_buffers[va_buffers_count++] = h264_prv->pic_parameter;
+ }
+ if (VA_INVALID_ID != h264_prv->slice_parameter) {
+ va_buffers[va_buffers_count++] = h264_prv->slice_parameter;
+ }
+ if (SLICE_TYPE_I == h264_prv->cur_slice_type) {
+ if (VA_INVALID_ID != h264_prv->packed_sps_par_buf) {
+ va_buffers[va_buffers_count++] = h264_prv->packed_sps_par_buf;
+ }
+ if (VA_INVALID_ID != h264_prv->packed_sps_data_buf) {
+ va_buffers[va_buffers_count++] = h264_prv->packed_sps_data_buf;
+ }
+ if (VA_INVALID_ID != h264_prv->packed_pps_par_buf) {
+ va_buffers[va_buffers_count++] = h264_prv->packed_pps_par_buf;
+ }
+ if (VA_INVALID_ID != h264_prv->packed_pps_data_buf) {
+ va_buffers[va_buffers_count++] = h264_prv->packed_pps_data_buf;
+ }
+ }
+
+ va_status = vaRenderPicture(va_dpy, context_id, va_buffers, va_buffers_count);
+ ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status, ENCODER_PICTURE_ERR,
+ "vaRenderH264Picture failed.");
+
+ /*after finished, swap recon and surface2*/
+ if (SLICE_TYPE_P == h264_prv->cur_slice_type ||
+ SLICE_TYPE_I == h264_prv->cur_slice_type) {
+ h264_swap_surface(&h264_prv->recon_surface, &h264_prv->ref_surface2);
+ }
+
+ end:
+ ENCODER_RELEASE_DISPLAY_LOCK(display);
+ return ret;
+}
+
+#endif