#include <string.h>
#include <stdlib.h>
#include <va/va.h>
-#include "va/va_x11.h"
+#include <va/va_x11.h>
+#include <va/va_enc_h264.h>
#include <X11/Xlib.h>
#include <glib.h>
guint32 cur_decode_num;
H264_SLICE_TYPE cur_slice_type;
guint64 last_decode_time;
+ guint32 max_frame_num;
+ guint32 max_pic_order_cnt;
+ guint16 idr_num;
};
G_DEFINE_TYPE(GstVaapiEncoderH264, gst_vaapi_encoder_h264, GST_TYPE_VAAPI_BASE_ENCODER);
static gboolean h264_bitstream_write_byte_array(H264Bitstream *bitstream, const guint8 *buf, guint32 byte_size);
static void h264_bitstream_destroy(H264Bitstream *bitstream, gboolean free_flag);
static gboolean h264_bitstream_auto_grow(H264Bitstream *bitstream, guint32 extra_bit_size);
-static gboolean h264_bitstream_write_sps(H264Bitstream *bitstream, VAEncSequenceParameterBufferH264 *seq);
+static gboolean h264_bitstream_write_sps(H264Bitstream *bitstream,
+ VAEncSequenceParameterBufferH264 *seq, H264_Profile profile);
static gboolean h264_bitstream_write_pps(H264Bitstream *bitstream, VAEncPictureParameterBufferH264 *pic);
static gboolean h264_bitstream_write_nal_header(H264Bitstream *bitstream,
guint nal_ref_idc, guint nal_unit_type);
h264_prv->cur_slice_type = SLICE_TYPE_I;
h264_prv->last_decode_time = 0LL;
h264_prv->default_cts_offset = 0;
+
+ h264_prv->max_frame_num = 0;
+ h264_prv->max_pic_order_cnt = 0;
+ h264_prv->idr_num = 0;
}
static void
h264_prv->cur_display_num = 0;
h264_prv->cur_decode_num = 0;
h264_prv->cur_slice_type = SLICE_TYPE_I;
+ ++h264_prv->idr_num;
return_buf = display_buf;
goto end;
}
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;
+ 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;
+
+ /*sequence field values*/
+ seq_h264.seq_fields.value = 0;
+ seq_h264.seq_fields.bits.chroma_format_idc = 1;
+ seq_h264.seq_fields.bits.frame_mbs_only_flag = 1;
+ seq_h264.seq_fields.bits.mb_adaptive_frame_field_flag = FALSE;
+ seq_h264.seq_fields.bits.seq_scaling_matrix_present_flag = FALSE;
+ /* direct_8x8_inference_flag default false */
+ seq_h264.seq_fields.bits.direct_8x8_inference_flag = FALSE;
+ seq_h264.seq_fields.bits.log2_max_frame_num_minus4 = 4; // log2(seq_h264.intra_period)-3 : 0
+ /* picture order count */
+ seq_h264.seq_fields.bits.pic_order_cnt_type = 0;
+ seq_h264.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 =
+ seq_h264.seq_fields.bits.log2_max_frame_num_minus4 + 2;
+ seq_h264.seq_fields.bits.delta_pic_order_always_zero_flag = TRUE;
+
+ h264_prv->max_frame_num = 1<<(seq_h264.seq_fields.bits.log2_max_frame_num_minus4 + 4);
+ h264_prv->max_pic_order_cnt = 1 <<(seq_h264.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 + 4);
+
+ seq_h264.bit_depth_luma_minus8 = 0;
+ seq_h264.bit_depth_chroma_minus8 = 0;
+
+ /* not used if pic_order_cnt_type == 0 */
+ seq_h264.num_ref_frames_in_pic_order_cnt_cycle = 0;
+ seq_h264.offset_for_non_ref_pic = 0;
+ seq_h264.offset_for_top_to_bottom_field = 0;
+ memset(seq_h264.offset_for_ref_frame, 0, sizeof(seq_h264.offset_for_ref_frame));
if (height_in_mbs*16 - ENCODER_HEIGHT(h264_encoder)) {
seq_h264.frame_cropping_flag = 1;
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));
+ (height_in_mbs * 16 - ENCODER_HEIGHT(h264_encoder))/(2 * (!seq_h264.seq_fields.bits.frame_mbs_only_flag + 1));
+ }
+#if 0
+ 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;
}
- 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?
+#endif
+
+ /*vui not set*/
+ seq_h264.vui_parameters_present_flag = 0;
va_status = vaCreateBuffer(va_dpy, context_id,
VAEncSequenceParameterBufferType,
ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
FALSE, "alloc seq-buffer failed.");
+#if 0
/*pack sps header buffer/data */
if (NULL == h264_prv->sps_data) {
VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
FALSE,
"EncPackedSeqHeaderDataBuffer failed");
}
+#endif
end:
return ret;
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.coded_buf = coded_buf;
pic_h264.pic_parameter_set_id = 0;
- pic_h264.last_picture = 0;
+ pic_h264.seq_parameter_set_id = 0;
+ pic_h264.last_picture = 0; /* means last encoding picture */
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.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.num_ref_idx_l0_active_minus1 = 0; /* only 1 reference */
+ pic_h264.num_ref_idx_l1_active_minus1 = 0; /* B frames only have 1 backward and 1 forward reference*/
+ pic_h264.chroma_qp_index_offset = 0;
+ pic_h264.second_chroma_qp_index_offset = 0;
+
+ /* set picture fields */
+ pic_h264.pic_fields.value = 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_pred_flag = FALSE;
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;
+ pic_h264.pic_fields.bits.constrained_intra_pred_flag = 0;
+ pic_h264.pic_fields.bits.transform_8x8_mode_flag = TRUE; /* enable 8x8 */
+ pic_h264.pic_fields.bits.deblocking_filter_control_present_flag = TRUE; /* enable debloking */
+ pic_h264.pic_fields.bits.redundant_pic_cnt_present_flag = FALSE;
+ /* bottom_field_pic_order_in_frame_present_flag */
+ pic_h264.pic_fields.bits.pic_order_present_flag = FALSE;
+ pic_h264.pic_fields.bits.pic_scaling_matrix_present_flag = FALSE;
char *frame_type = "I";
if (h264_prv->cur_slice_type == SLICE_TYPE_P)
ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
FALSE, "creating pic-param buffer failed.");
-
+#if 0
//if (NULL == h264_prv->pps_data) {
if (VA_INVALID_ID == h264_prv->packed_pps_data_buf) {
VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
FALSE,
"EncPackedPicHeaderDataBuffer failed");
}
-
+#endif
end:
return ret;
}
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) {
+ int i_pic = 0;
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;
+ slice_h264->macroblock_address = last_row_num*width_in_mbs;
+ slice_h264->num_macroblocks = 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;
+ slice_h264->num_macroblocks += width_in_mbs;
++last_row_num;
--slice_mod_num;
}
- slice_h264->pic_parameter_set_id = 0;
+ slice_h264->macroblock_info = VA_INVALID_ID;
slice_h264->slice_type = h264_prv->cur_slice_type;
- slice_h264->direct_spatial_mv_pred_flag = 0;
+ slice_h264->pic_parameter_set_id = 0;
+ slice_h264->idr_pic_id = h264_prv->idr_num;
+ slice_h264->pic_order_cnt_lsb = (h264_prv->cur_display_num*2) % h264_prv->max_pic_order_cnt;
+
+ /* not used if pic_order_cnt_type = 0 */
+ slice_h264->delta_pic_order_cnt_bottom = 0;
+ memset(slice_h264->delta_pic_order_cnt, 0, sizeof(slice_h264->delta_pic_order_cnt));
+
+ /*only works for B frames*/
+ slice_h264->direct_spatial_mv_pred_flag = FALSE;
+ /* default equal to picture parameters */
+ slice_h264->num_ref_idx_active_override_flag = FALSE;
slice_h264->num_ref_idx_l0_active_minus1 = 0;
slice_h264->num_ref_idx_l1_active_minus1 = 0;
+
+ slice_h264->RefPicList0[0].picture_id = GST_VAAPI_OBJECT_ID(h264_prv->ref_surface1);
+ for (i_pic = 1;
+ i_pic < sizeof(slice_h264->RefPicList0)/sizeof(slice_h264->RefPicList0[0]);
+ i_pic++) {
+ slice_h264->RefPicList0[i_pic].picture_id = VA_INVALID_ID;
+ }
+
+ if (SLICE_TYPE_B == h264_prv->cur_slice_type) {
+ slice_h264->RefPicList1[0].picture_id = GST_VAAPI_OBJECT_ID(h264_prv->ref_surface2);
+ i_pic = 1;
+ } else
+ i_pic = 0;
+ for (; i_pic < sizeof(slice_h264->RefPicList1)/sizeof(slice_h264->RefPicList1[0]); i_pic++)
+ slice_h264->RefPicList1[i_pic].picture_id = VA_INVALID_ID;
+
+ /* not used if pic_h264.pic_fields.bits.weighted_pred_flag == FALSE */
+ slice_h264->luma_log2_weight_denom = 0;
+ slice_h264->chroma_log2_weight_denom = 0;
+ slice_h264->luma_weight_l0_flag = FALSE;
+ memset(slice_h264->luma_weight_l0, 0, sizeof(slice_h264->luma_weight_l0));
+ memset(slice_h264->luma_offset_l0, 0, sizeof(slice_h264->luma_offset_l0));
+ slice_h264->chroma_weight_l0_flag = FALSE;
+ memset(slice_h264->chroma_weight_l0, 0, sizeof(slice_h264->chroma_weight_l0));
+ memset(slice_h264->chroma_offset_l0, 0, sizeof(slice_h264->chroma_offset_l0));
+ slice_h264->luma_weight_l1_flag = FALSE;
+ memset(slice_h264->luma_weight_l1, 0, sizeof(slice_h264->luma_weight_l1));
+ memset(slice_h264->luma_offset_l1, 0, sizeof(slice_h264->luma_offset_l1));
+ slice_h264->chroma_weight_l1_flag = FALSE;
+ memset(slice_h264->chroma_weight_l1, 0, sizeof(slice_h264->chroma_weight_l1));
+ memset(slice_h264->chroma_offset_l1, 0, sizeof(slice_h264->chroma_offset_l1));
+
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);
return ret;
}
-static gboolean h264_bitstream_align(H264Bitstream *bitstream, guint32 value)
+static gboolean
+h264_bitstream_align(H264Bitstream *bitstream, guint32 value)
{
guint32 bit_offset, bit_left;
static gboolean
h264_bitstream_write_sps(H264Bitstream *bitstream,
- VAEncSequenceParameterBufferH264 *seq)
+ VAEncSequenceParameterBufferH264 *seq, H264_Profile profile)
{
guint32 constraint_set0_flag, constraint_set1_flag, constraint_set2_flag, constraint_set3_flag;
guint32 gaps_in_frame_num_value_allowed_flag = 0; // ??
- guint32 b_qpprime_y_zero_transform_bypass = (seq->rate_control_method == BR_CQP);
+ guint32 b_qpprime_y_zero_transform_bypass = 0;
guint32 residual_color_transform_flag = 0;
- guint32 pic_height_in_map_units = (seq->frame_mbs_only_flag ?
+ guint32 pic_height_in_map_units = (seq->seq_fields.bits.frame_mbs_only_flag ?
seq->picture_height_in_mbs :
seq->picture_height_in_mbs/2);
- guint32 mb_adaptive_frame_field = !seq->frame_mbs_only_flag;
+ guint32 mb_adaptive_frame_field = !seq->seq_fields.bits.frame_mbs_only_flag;
guint32 i = 0;
- constraint_set0_flag = seq->profile_idc == H264_PROFILE_BASELINE;
- constraint_set1_flag = seq->profile_idc <= H264_PROFILE_MAIN;
+ constraint_set0_flag = profile == H264_PROFILE_BASELINE;
+ constraint_set1_flag = profile <= H264_PROFILE_MAIN;
constraint_set2_flag = 0;
constraint_set3_flag = 0;
- h264_bitstream_write_uint(bitstream, seq->profile_idc, 8); /* profile_idc */
+ h264_bitstream_write_uint(bitstream, profile, 8); /* profile_idc */
h264_bitstream_write_uint(bitstream, constraint_set0_flag, 1); /* constraint_set0_flag */
h264_bitstream_write_uint(bitstream, constraint_set1_flag, 1); /* constraint_set1_flag */
h264_bitstream_write_uint(bitstream, constraint_set2_flag, 1); /* constraint_set2_flag */
h264_bitstream_write_uint(bitstream, seq->level_idc, 8); /* level_idc */
h264_bitstream_write_ue(bitstream, seq->seq_parameter_set_id); /* seq_parameter_set_id */
- if (seq->profile_idc >= H264_PROFILE_HIGH) {
+ if (profile >= H264_PROFILE_HIGH) {
/* for high profile */
ENCODER_ASSERT(0);
h264_bitstream_write_ue(bitstream, seq->seq_fields.bits.chroma_format_idc); /* chroma_format_idc = 1, 4:2:0*/
ENCODER_ASSERT(seq->seq_fields.bits.seq_scaling_matrix_present_flag == 0);
h264_bitstream_write_uint(bitstream, seq->seq_fields.bits.seq_scaling_matrix_present_flag, 1); /*seq_scaling_matrix_present_flag */
+ #if 0
if (seq->seq_fields.bits.seq_scaling_matrix_present_flag) {
for (i = 0; i < (seq->seq_fields.bits.chroma_format_idc != 3 ? 8 : 12); i++) {
h264_bitstream_write_uint(bitstream, seq->seq_fields.bits.seq_scaling_list_present_flag, 1);
}
}
}
+ #endif
}
- h264_bitstream_write_ue(bitstream, seq->log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */
- h264_bitstream_write_ue(bitstream, seq->pic_order_cnt_type); /* pic_order_cnt_type */
+ h264_bitstream_write_ue(bitstream, seq->seq_fields.bits.log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */
+ h264_bitstream_write_ue(bitstream, seq->seq_fields.bits.pic_order_cnt_type); /* pic_order_cnt_type */
- if (seq->pic_order_cnt_type == 0)
- h264_bitstream_write_ue(bitstream, seq->log2_max_pic_order_cnt_lsb_minus4);/* log2_max_pic_order_cnt_lsb_minus4 */
- else if (seq->pic_order_cnt_type == 1) {
+ if (seq->seq_fields.bits.pic_order_cnt_type == 0)
+ h264_bitstream_write_ue(bitstream, seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);/* log2_max_pic_order_cnt_lsb_minus4 */
+ else if (seq->seq_fields.bits.pic_order_cnt_type == 1) {
ENCODER_ASSERT(0);
h264_bitstream_write_uint(bitstream, seq->seq_fields.bits.delta_pic_order_always_zero_flag, 1);
h264_bitstream_write_se(bitstream, seq->offset_for_non_ref_pic);
h264_bitstream_write_ue(bitstream, seq->picture_width_in_mbs - 1); /* pic_width_in_mbs_minus1 */
h264_bitstream_write_ue(bitstream, pic_height_in_map_units - 1); /* pic_height_in_map_units_minus1 */
- h264_bitstream_write_uint(bitstream, seq->frame_mbs_only_flag, 1); /* frame_mbs_only_flag */
+ h264_bitstream_write_uint(bitstream, seq->seq_fields.bits.frame_mbs_only_flag, 1); /* frame_mbs_only_flag */
- if (!seq->frame_mbs_only_flag) { //ONLY mbs
+ if (!seq->seq_fields.bits.frame_mbs_only_flag) { //ONLY mbs
ENCODER_ASSERT(0);
h264_bitstream_write_uint(bitstream, mb_adaptive_frame_field, 1);
}
h264_bitstream_write_ue(bitstream, seq->frame_crop_top_offset); /* frame_crop_top_offset */
h264_bitstream_write_ue(bitstream, seq->frame_crop_bottom_offset); /* frame_crop_bottom_offset */
}
- ENCODER_ASSERT(seq->vui_flag == 0);
- h264_bitstream_write_uint(bitstream, seq->vui_flag, 1); /* vui_parameters_present_flag */
- if (seq->vui_flag) {
+ ENCODER_ASSERT(seq->vui_parameters_present_flag == FALSE);
+ h264_bitstream_write_uint(bitstream, seq->vui_parameters_present_flag, 1); /* vui_parameters_present_flag */
+ if (seq->vui_parameters_present_flag) {
/*FIXME, to write vui parameters*/
}
h264_bitstream_write_trailing_bits(bitstream); /* rbsp_trailing_bits */
return TRUE;
}
-
static gboolean
h264_bitstream_write_pps(H264Bitstream *bitstream,
VAEncPictureParameterBufferH264 *pic)