/* * Copyright (c) 2007-2013 Intel Corporation. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #include #include #include "va_display.h" #include "va_encode.h" #define NAL_REF_IDC_NONE 0 #define NAL_REF_IDC_LOW 1 #define NAL_REF_IDC_MEDIUM 2 #define NAL_REF_IDC_HIGH 3 #define NAL_NON_IDR 1 #define NAL_IDR 5 #define NAL_SPS 7 #define NAL_PPS 8 #define NAL_SEI 6 #define SLICE_TYPE_P 0 #define SLICE_TYPE_B 1 #define SLICE_TYPE_I 2 #define ENTROPY_MODE_CAVLC 0 #define ENTROPY_MODE_CABAC 1 #define PROFILE_IDC_BASELINE 66 #define PROFILE_IDC_MAIN 77 #define PROFILE_IDC_HIGH 100 #define BITSTREAM_ALLOCATE_STEPPING 4096 static VAConfigAttrib h264_attrib[VAConfigAttribTypeMax]; static VAEncSequenceParameterBufferH264 seq_param; static VAEncPictureParameterBufferH264 pic_param; static VAPictureH264 CurrentCurrPic; static VAPictureH264 ReferenceFrames[16], RefPicList0_P[32], RefPicList0_B[32], RefPicList1_B[32]; static unsigned int MaxFrameNum = (2<<16); static unsigned int MaxPicOrderCntLsb = (2<<8); static unsigned int Log2MaxFrameNum = 16; static unsigned int Log2MaxPicOrderCntLsb = 8; static unsigned int num_ref_frames = 2; static unsigned int numShortTerm = 0; static int constraint_set_flag = 0; static int h264_packedheader = 0; /* support pack header? */ static int h264_maxref = (1<<16|1); static int h264_autoref = 0; static VAProfile h264_profile = -1; unsigned int h264_entropy_mode = 1; /* cabac */ unsigned int h264_8x8_dct = 0; struct __bitstream { unsigned int *buffer; int bit_offset; int max_size_in_dword; }; typedef struct __bitstream bitstream; static unsigned int va_swap32(unsigned int val) { unsigned char *pval = (unsigned char *)&val; return ((pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | (pval[3] << 0)); } static void bitstream_start(bitstream *bs) { bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING; bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1); bs->bit_offset = 0; } static void bitstream_end(bitstream *bs) { int pos = (bs->bit_offset >> 5); int bit_offset = (bs->bit_offset & 0x1f); int bit_left = 32 - bit_offset; if (bit_offset) { bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left)); } } static void bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits) { int pos = (bs->bit_offset >> 5); int bit_offset = (bs->bit_offset & 0x1f); int bit_left = 32 - bit_offset; if (!size_in_bits) return; bs->bit_offset += size_in_bits; if (bit_left > size_in_bits) { bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val); } else { size_in_bits -= bit_left; bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits); bs->buffer[pos] = va_swap32(bs->buffer[pos]); if (pos + 1 == bs->max_size_in_dword) { bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING; bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int)); } bs->buffer[pos + 1] = val; } } static void bitstream_put_ue(bitstream *bs, unsigned int val) { int size_in_bits = 0; int tmp_val = ++val; while (tmp_val) { tmp_val >>= 1; size_in_bits++; } bitstream_put_ui(bs, 0, size_in_bits - 1); // leading zero bitstream_put_ui(bs, val, size_in_bits); } static void bitstream_put_se(bitstream *bs, int val) { unsigned int new_val; if (val <= 0) new_val = -2 * val; else new_val = 2 * val - 1; bitstream_put_ue(bs, new_val); } static void bitstream_byte_aligning(bitstream *bs, int bit) { int bit_offset = (bs->bit_offset & 0x7); int bit_left = 8 - bit_offset; int new_val; if (!bit_offset) return; assert(bit == 0 || bit == 1); if (bit) new_val = (1 << bit_left) - 1; else new_val = 0; bitstream_put_ui(bs, new_val, bit_left); } static void rbsp_trailing_bits(bitstream *bs) { bitstream_put_ui(bs, 1, 1); bitstream_byte_aligning(bs, 0); } static void nal_start_code_prefix(bitstream *bs) { bitstream_put_ui(bs, 0x00000001, 32); } static void nal_header(bitstream *bs, int nal_ref_idc, int nal_unit_type) { bitstream_put_ui(bs, 0, 1); /* forbidden_zero_bit: 0 */ bitstream_put_ui(bs, nal_ref_idc, 2); bitstream_put_ui(bs, nal_unit_type, 5); } static void sps_rbsp(bitstream *bs) { int profile_idc = PROFILE_IDC_BASELINE; if (h264_profile == VAProfileH264High) profile_idc = PROFILE_IDC_HIGH; else if (h264_profile == VAProfileH264Main) profile_idc = PROFILE_IDC_MAIN; bitstream_put_ui(bs, profile_idc, 8); /* profile_idc */ bitstream_put_ui(bs, !!(constraint_set_flag & 1), 1); /* constraint_set0_flag */ bitstream_put_ui(bs, !!(constraint_set_flag & 2), 1); /* constraint_set1_flag */ bitstream_put_ui(bs, !!(constraint_set_flag & 4), 1); /* constraint_set2_flag */ bitstream_put_ui(bs, !!(constraint_set_flag & 8), 1); /* constraint_set3_flag */ bitstream_put_ui(bs, 0, 4); /* reserved_zero_4bits */ bitstream_put_ui(bs, seq_param.level_idc, 8); /* level_idc */ bitstream_put_ue(bs, seq_param.seq_parameter_set_id); /* seq_parameter_set_id */ if ( profile_idc == PROFILE_IDC_HIGH) { bitstream_put_ue(bs, 1); /* chroma_format_idc = 1, 4:2:0 */ bitstream_put_ue(bs, 0); /* bit_depth_luma_minus8 */ bitstream_put_ue(bs, 0); /* bit_depth_chroma_minus8 */ bitstream_put_ui(bs, 0, 1); /* qpprime_y_zero_transform_bypass_flag */ bitstream_put_ui(bs, 0, 1); /* seq_scaling_matrix_present_flag */ } bitstream_put_ue(bs, seq_param.seq_fields.bits.log2_max_frame_num_minus4); /* log2_max_frame_num_minus4 */ bitstream_put_ue(bs, seq_param.seq_fields.bits.pic_order_cnt_type); /* pic_order_cnt_type */ if (seq_param.seq_fields.bits.pic_order_cnt_type == 0) bitstream_put_ue(bs, seq_param.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4); /* log2_max_pic_order_cnt_lsb_minus4 */ else { assert(0); } bitstream_put_ue(bs, seq_param.max_num_ref_frames); /* num_ref_frames */ bitstream_put_ui(bs, 0, 1); /* gaps_in_frame_num_value_allowed_flag */ bitstream_put_ue(bs, seq_param.picture_width_in_mbs - 1); /* pic_width_in_mbs_minus1 */ bitstream_put_ue(bs, seq_param.picture_height_in_mbs - 1); /* pic_height_in_map_units_minus1 */ bitstream_put_ui(bs, seq_param.seq_fields.bits.frame_mbs_only_flag, 1); /* frame_mbs_only_flag */ if (!seq_param.seq_fields.bits.frame_mbs_only_flag) { assert(0); } bitstream_put_ui(bs, seq_param.seq_fields.bits.direct_8x8_inference_flag, 1); /* direct_8x8_inference_flag */ bitstream_put_ui(bs, seq_param.frame_cropping_flag, 1); /* frame_cropping_flag */ if (seq_param.frame_cropping_flag) { bitstream_put_ue(bs, seq_param.frame_crop_left_offset); /* frame_crop_left_offset */ bitstream_put_ue(bs, seq_param.frame_crop_right_offset); /* frame_crop_right_offset */ bitstream_put_ue(bs, seq_param.frame_crop_top_offset); /* frame_crop_top_offset */ bitstream_put_ue(bs, seq_param.frame_crop_bottom_offset); /* frame_crop_bottom_offset */ } //if ( frame_bit_rate < 0 ) { //TODO EW: the vui header isn't correct if ( 1 ) { bitstream_put_ui(bs, 0, 1); /* vui_parameters_present_flag */ } else { bitstream_put_ui(bs, 1, 1); /* vui_parameters_present_flag */ bitstream_put_ui(bs, 0, 1); /* aspect_ratio_info_present_flag */ bitstream_put_ui(bs, 0, 1); /* overscan_info_present_flag */ bitstream_put_ui(bs, 0, 1); /* video_signal_type_present_flag */ bitstream_put_ui(bs, 0, 1); /* chroma_loc_info_present_flag */ bitstream_put_ui(bs, 1, 1); /* timing_info_present_flag */ { bitstream_put_ui(bs, 15, 32); bitstream_put_ui(bs, 900, 32); bitstream_put_ui(bs, 1, 1); } bitstream_put_ui(bs, 1, 1); /* nal_hrd_parameters_present_flag */ { // hrd_parameters bitstream_put_ue(bs, 0); /* cpb_cnt_minus1 */ bitstream_put_ui(bs, 4, 4); /* bit_rate_scale */ bitstream_put_ui(bs, 6, 4); /* cpb_size_scale */ bitstream_put_ue(bs, frame_bitrate - 1); /* bit_rate_value_minus1[0] */ bitstream_put_ue(bs, frame_bitrate*8 - 1); /* cpb_size_value_minus1[0] */ bitstream_put_ui(bs, 1, 1); /* cbr_flag[0] */ bitstream_put_ui(bs, 23, 5); /* initial_cpb_removal_delay_length_minus1 */ bitstream_put_ui(bs, 23, 5); /* cpb_removal_delay_length_minus1 */ bitstream_put_ui(bs, 23, 5); /* dpb_output_delay_length_minus1 */ bitstream_put_ui(bs, 23, 5); /* time_offset_length */ } bitstream_put_ui(bs, 0, 1); /* vcl_hrd_parameters_present_flag */ bitstream_put_ui(bs, 0, 1); /* low_delay_hrd_flag */ bitstream_put_ui(bs, 0, 1); /* pic_struct_present_flag */ bitstream_put_ui(bs, 0, 1); /* bitstream_restriction_flag */ } rbsp_trailing_bits(bs); /* rbsp_trailing_bits */ } static void pps_rbsp(bitstream *bs) { bitstream_put_ue(bs, pic_param.pic_parameter_set_id); /* pic_parameter_set_id */ bitstream_put_ue(bs, pic_param.seq_parameter_set_id); /* seq_parameter_set_id */ bitstream_put_ui(bs, pic_param.pic_fields.bits.entropy_coding_mode_flag, 1); /* entropy_coding_mode_flag */ bitstream_put_ui(bs, 0, 1); /* pic_order_present_flag: 0 */ bitstream_put_ue(bs, 0); /* num_slice_groups_minus1 */ bitstream_put_ue(bs, pic_param.num_ref_idx_l0_active_minus1); /* num_ref_idx_l0_active_minus1 */ bitstream_put_ue(bs, pic_param.num_ref_idx_l1_active_minus1); /* num_ref_idx_l1_active_minus1 1 */ bitstream_put_ui(bs, pic_param.pic_fields.bits.weighted_pred_flag, 1); /* weighted_pred_flag: 0 */ bitstream_put_ui(bs, pic_param.pic_fields.bits.weighted_bipred_idc, 2); /* weighted_bipred_idc: 0 */ bitstream_put_se(bs, pic_param.pic_init_qp - 26); /* pic_init_qp_minus26 */ bitstream_put_se(bs, 0); /* pic_init_qs_minus26 */ bitstream_put_se(bs, 0); /* chroma_qp_index_offset */ bitstream_put_ui(bs, pic_param.pic_fields.bits.deblocking_filter_control_present_flag, 1); /* deblocking_filter_control_present_flag */ bitstream_put_ui(bs, 0, 1); /* constrained_intra_pred_flag */ bitstream_put_ui(bs, 0, 1); /* redundant_pic_cnt_present_flag */ /* more_rbsp_data */ bitstream_put_ui(bs, pic_param.pic_fields.bits.transform_8x8_mode_flag, 1); /*transform_8x8_mode_flag */ bitstream_put_ui(bs, 0, 1); /* pic_scaling_matrix_present_flag */ bitstream_put_se(bs, pic_param.second_chroma_qp_index_offset ); /*second_chroma_qp_index_offset */ rbsp_trailing_bits(bs); } static int build_packed_pic_buffer(unsigned char **header_buffer) { bitstream bs; bitstream_start(&bs); nal_start_code_prefix(&bs); nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS); pps_rbsp(&bs); bitstream_end(&bs); *header_buffer = (unsigned char *)bs.buffer; return bs.bit_offset; } static int build_packed_seq_buffer(unsigned char **header_buffer) { bitstream bs; bitstream_start(&bs); nal_start_code_prefix(&bs); nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS); sps_rbsp(&bs); bitstream_end(&bs); *header_buffer = (unsigned char *)bs.buffer; return bs.bit_offset; } static int build_packed_sei_buffer_timing(unsigned int init_cpb_removal_length, unsigned int init_cpb_removal_delay, unsigned int init_cpb_removal_delay_offset, unsigned int cpb_removal_length, unsigned int cpb_removal_delay, unsigned int dpb_output_length, unsigned int dpb_output_delay, unsigned char **sei_buffer) { unsigned char *byte_buf; int bp_byte_size, i, pic_byte_size; bitstream nal_bs; bitstream sei_bp_bs, sei_pic_bs; bitstream_start(&sei_bp_bs); bitstream_put_ue(&sei_bp_bs, 0); /*seq_parameter_set_id*/ bitstream_put_ui(&sei_bp_bs, init_cpb_removal_delay, cpb_removal_length); bitstream_put_ui(&sei_bp_bs, init_cpb_removal_delay_offset, cpb_removal_length); if ( sei_bp_bs.bit_offset & 0x7) { bitstream_put_ui(&sei_bp_bs, 1, 1); } bitstream_end(&sei_bp_bs); bp_byte_size = (sei_bp_bs.bit_offset + 7) / 8; bitstream_start(&sei_pic_bs); bitstream_put_ui(&sei_pic_bs, cpb_removal_delay, cpb_removal_length); bitstream_put_ui(&sei_pic_bs, dpb_output_delay, dpb_output_length); if ( sei_pic_bs.bit_offset & 0x7) { bitstream_put_ui(&sei_pic_bs, 1, 1); } bitstream_end(&sei_pic_bs); pic_byte_size = (sei_pic_bs.bit_offset + 7) / 8; bitstream_start(&nal_bs); nal_start_code_prefix(&nal_bs); nal_header(&nal_bs, NAL_REF_IDC_NONE, NAL_SEI); /* Write the SEI buffer period data */ bitstream_put_ui(&nal_bs, 0, 8); bitstream_put_ui(&nal_bs, bp_byte_size, 8); byte_buf = (unsigned char *)sei_bp_bs.buffer; for(i = 0; i < bp_byte_size; i++) { bitstream_put_ui(&nal_bs, byte_buf[i], 8); } free(byte_buf); /* write the SEI timing data */ bitstream_put_ui(&nal_bs, 0x01, 8); bitstream_put_ui(&nal_bs, pic_byte_size, 8); byte_buf = (unsigned char *)sei_pic_bs.buffer; for(i = 0; i < pic_byte_size; i++) { bitstream_put_ui(&nal_bs, byte_buf[i], 8); } free(byte_buf); rbsp_trailing_bits(&nal_bs); bitstream_end(&nal_bs); *sei_buffer = (unsigned char *)nal_bs.buffer; return nal_bs.bit_offset; } #define partition(ref, field, key, ascending) \ while (i <= j) { \ if (ascending) { \ while (ref[i].field < key) \ i++; \ while (ref[j].field > key) \ j--; \ } else { \ while (ref[i].field > key) \ i++; \ while (ref[j].field < key) \ j--; \ } \ if (i <= j) { \ tmp = ref[i]; \ ref[i] = ref[j]; \ ref[j] = tmp; \ i++; \ j--; \ } \ } \ static void sort_one(VAPictureH264 ref[], int left, int right, int ascending, int frame_idx) { int i = left, j = right; unsigned int key; VAPictureH264 tmp; if (frame_idx) { key = ref[(left + right) / 2].frame_idx; partition(ref, frame_idx, key, ascending); } else { key = ref[(left + right) / 2].TopFieldOrderCnt; partition(ref, TopFieldOrderCnt, (signed int)key, ascending); } /* recursion */ if (left < j) sort_one(ref, left, j, ascending, frame_idx); if (i < right) sort_one(ref, i, right, ascending, frame_idx); } static void sort_two(VAPictureH264 ref[], int left, int right, unsigned int key, unsigned int frame_idx, int partition_ascending, int list0_ascending, int list1_ascending) { int i = left, j = right; VAPictureH264 tmp; if (frame_idx) { partition(ref, frame_idx, key, partition_ascending); } else { partition(ref, TopFieldOrderCnt, (signed int)key, partition_ascending); } sort_one(ref, left, i-1, list0_ascending, frame_idx); sort_one(ref, j+1, right, list1_ascending, frame_idx); } static int update_ReferenceFrames(void) { int i; if (current_frame_type == FRAME_B) return 0; CurrentCurrPic.flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; numShortTerm++; if (numShortTerm > num_ref_frames) numShortTerm = num_ref_frames; for (i=numShortTerm-1; i>0; i--) ReferenceFrames[i] = ReferenceFrames[i-1]; ReferenceFrames[0] = CurrentCurrPic; if (current_frame_type != FRAME_B) current_frame_num++; if (current_frame_num > MaxFrameNum) current_frame_num = 0; return 0; } static int update_RefPicList(void) { unsigned int current_poc = CurrentCurrPic.TopFieldOrderCnt; if (current_frame_type == FRAME_P) { memcpy(RefPicList0_P, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); sort_one(RefPicList0_P, 0, numShortTerm-1, 0, 1); } if (current_frame_type == FRAME_B) { memcpy(RefPicList0_B, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); sort_two(RefPicList0_B, 0, numShortTerm-1, current_poc, 0, 1, 0, 1); memcpy(RefPicList1_B, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); sort_two(RefPicList1_B, 0, numShortTerm-1, current_poc, 0, 0, 1, 0); } return 0; } static int render_sequence(void) { VABufferID seq_param_buf, rc_param_buf, misc_param_tmpbuf, render_id[2]; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterRateControl *misc_rate_ctrl; seq_param.level_idc = 41 /*SH_LEVEL_3*/; seq_param.picture_width_in_mbs = frame_width_mbaligned / 16; seq_param.picture_height_in_mbs = frame_height_mbaligned / 16; seq_param.bits_per_second = frame_bitrate; seq_param.intra_period = intra_period; seq_param.intra_idr_period = (intra_period == 0) ? 0 : (intra_idr_period / intra_period); seq_param.ip_period = ip_period; seq_param.max_num_ref_frames = num_ref_frames; seq_param.seq_fields.bits.frame_mbs_only_flag = 1; seq_param.time_scale = 0; seq_param.num_units_in_tick = 0; /* Tc = num_units_in_tick / time_sacle */ seq_param.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = Log2MaxPicOrderCntLsb - 4; seq_param.seq_fields.bits.log2_max_frame_num_minus4 = Log2MaxFrameNum - 4;; seq_param.seq_fields.bits.frame_mbs_only_flag = 1; seq_param.seq_fields.bits.chroma_format_idc = 1; seq_param.seq_fields.bits.direct_8x8_inference_flag = 1; if (frame_width != frame_width_mbaligned || frame_height != frame_height_mbaligned) { seq_param.frame_cropping_flag = 1; seq_param.frame_crop_left_offset = 0; seq_param.frame_crop_right_offset = (frame_width_mbaligned - frame_width)/2; seq_param.frame_crop_top_offset = 0; seq_param.frame_crop_bottom_offset = (frame_height_mbaligned - frame_height)/2; } va_status = vaCreateBuffer(va_dpy, context_id, VAEncSequenceParameterBufferType, sizeof(seq_param),1,&seq_param,&seq_param_buf); CHECK_VASTATUS(va_status,"vaCreateBuffer"); va_status = vaRenderPicture(va_dpy,context_id, &seq_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; if (misc_priv_type != 0) { va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer), 1, NULL, &misc_param_tmpbuf); CHECK_VASTATUS(va_status,"vaCreateBuffer"); vaMapBuffer(va_dpy, misc_param_tmpbuf,(void **)&misc_param_tmp); misc_param_tmp->type = misc_priv_type; misc_param_tmp->data[0] = misc_priv_value; vaUnmapBuffer(va_dpy, misc_param_tmpbuf); va_status = vaRenderPicture(va_dpy,context_id, &misc_param_tmpbuf, 1); } return va_status; } static int render_framerate() { VABufferID frame_rate_param_buf; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterFrameRate *misc_frame_rate; if (frame_rate == 0) return 0; va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterFrameRate), 1,NULL,&frame_rate_param_buf); CHECK_VASTATUS(va_status,"vaCreateBuffer"); vaMapBuffer(va_dpy, frame_rate_param_buf,(void **)&misc_param); misc_param->type = VAEncMiscParameterTypeFrameRate; misc_frame_rate = (VAEncMiscParameterFrameRate *)misc_param->data; misc_frame_rate->framerate = frame_rate; if (pm_active == 1) misc_frame_rate->framerate_flags.value = 1; else misc_frame_rate->framerate_flags.value = 0; vaUnmapBuffer(va_dpy, frame_rate_param_buf); va_status = vaRenderPicture(va_dpy,context_id, &frame_rate_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; return 0; } static int render_rcparam(unsigned int mask, struct rc_param_t *rc_param) { VABufferID rc_param_buf; VAStatus va_status; VAEncMiscParameterBuffer *misc_param, *misc_param_tmp; VAEncMiscParameterRateControl *misc_rate_ctrl; va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl), 1,NULL,&rc_param_buf); CHECK_VASTATUS(va_status,"vaCreateBuffer"); vaMapBuffer(va_dpy, rc_param_buf,(void **)&misc_param); misc_param->type = VAEncMiscParameterTypeRateControl; misc_rate_ctrl = (VAEncMiscParameterRateControl *)misc_param->data; memset(misc_rate_ctrl, 0, sizeof(*misc_rate_ctrl)); if (mask & RC_MASK_bits_per_second) misc_rate_ctrl->bits_per_second = rc_param->bits_per_second; else misc_rate_ctrl->bits_per_second = frame_bitrate; if (mask & RC_MASK_target_percentage) misc_rate_ctrl->target_percentage = rc_param->target_percentage; else misc_rate_ctrl->target_percentage = 66; if (mask & RC_MASK_window_size) misc_rate_ctrl->window_size = rc_param->window_size; else misc_rate_ctrl->window_size = windows_size; if (mask & RC_MASK_initial_qp) misc_rate_ctrl->initial_qp = rc_param->initial_qp; else misc_rate_ctrl->initial_qp = initial_qp; if (mask & RC_MASK_min_qp) misc_rate_ctrl->min_qp = rc_param->min_qp; else misc_rate_ctrl->min_qp = minimal_qp; if (mask & RC_MASK_max_qp) misc_rate_ctrl->max_qp = rc_param->max_qp; else misc_rate_ctrl->max_qp = maximum_qp; misc_rate_ctrl->basic_unit_size = 0; misc_rate_ctrl->rc_flags.bits.disable_bit_stuffing = bit_stuffing_dis; misc_rate_ctrl->rc_flags.bits.mb_rate_control = carc; vaUnmapBuffer(va_dpy, rc_param_buf); va_status = vaRenderPicture(va_dpy,context_id, &rc_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; return 0; } static int calc_poc(int pic_order_cnt_lsb) { static int PicOrderCntMsb_ref = 0, pic_order_cnt_lsb_ref = 0; int prevPicOrderCntMsb, prevPicOrderCntLsb; int PicOrderCntMsb, TopFieldOrderCnt; if (current_frame_type == FRAME_IDR) prevPicOrderCntMsb = prevPicOrderCntLsb = 0; else { prevPicOrderCntMsb = PicOrderCntMsb_ref; prevPicOrderCntLsb = pic_order_cnt_lsb_ref; } if ((pic_order_cnt_lsb < prevPicOrderCntLsb) && ((prevPicOrderCntLsb - pic_order_cnt_lsb) >= (int)(MaxPicOrderCntLsb / 2))) PicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb; else if ((pic_order_cnt_lsb > prevPicOrderCntLsb) && ((pic_order_cnt_lsb - prevPicOrderCntLsb) > (int)(MaxPicOrderCntLsb / 2))) PicOrderCntMsb = prevPicOrderCntMsb - MaxPicOrderCntLsb; else PicOrderCntMsb = prevPicOrderCntMsb; TopFieldOrderCnt = PicOrderCntMsb + pic_order_cnt_lsb; if (current_frame_type != FRAME_B) { PicOrderCntMsb_ref = PicOrderCntMsb; pic_order_cnt_lsb_ref = pic_order_cnt_lsb; } return TopFieldOrderCnt; } static int render_picture(void) { VABufferID pic_param_buf; VAStatus va_status; int i = 0; pic_param.CurrPic.picture_id = ref_surface[current_slot]; pic_param.CurrPic.frame_idx = current_frame_num; pic_param.CurrPic.flags = 0; pic_param.CurrPic.TopFieldOrderCnt = calc_poc((current_frame_display - current_IDR_display) % MaxPicOrderCntLsb); pic_param.CurrPic.BottomFieldOrderCnt = pic_param.CurrPic.TopFieldOrderCnt; CurrentCurrPic = pic_param.CurrPic; if (getenv("TO_DEL")) { /* set RefPicList into ReferenceFrames */ update_RefPicList(); /* calc RefPicList */ memset(pic_param.ReferenceFrames, 0xff, 16 * sizeof(VAPictureH264)); /* invalid all */ if (current_frame_type == FRAME_P) { pic_param.ReferenceFrames[0] = RefPicList0_P[0]; } else if (current_frame_type == FRAME_B) { pic_param.ReferenceFrames[0] = RefPicList0_B[0]; pic_param.ReferenceFrames[1] = RefPicList1_B[0]; } } else { if (h264_autoref == 0) { memcpy(pic_param.ReferenceFrames, ReferenceFrames, numShortTerm*sizeof(VAPictureH264)); for (i = numShortTerm; i < surface_num; i++) { pic_param.ReferenceFrames[i].picture_id = VA_INVALID_SURFACE; pic_param.ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; } } else { for (i=0; i> 10; i_initial_cpb_removal_delay = init_cpb_size * 0.5 * 1024 / target_bit_rate * 90000; i_cpb_removal_delay = 2; i_initial_cpb_removal_delay_length = 24; i_cpb_removal_delay_length = 24; i_dpb_output_delay_length = 24; length_in_bits = build_packed_sei_buffer_timing( i_initial_cpb_removal_delay_length, i_initial_cpb_removal_delay, 0, i_cpb_removal_delay_length, i_cpb_removal_delay * current_frame_encoding, i_dpb_output_delay_length, 0, &packed_sei_buffer); //offset_in_bytes = 0; packed_header_param_buffer.type = VAEncPackedHeaderH264_SEI; 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, &packed_sei_header_param_buf_id); CHECK_VASTATUS(va_status,"vaCreateBuffer"); va_status = vaCreateBuffer(va_dpy, context_id, VAEncPackedHeaderDataBufferType, (length_in_bits + 7) / 8, 1, packed_sei_buffer, &packed_sei_buf_id); CHECK_VASTATUS(va_status,"vaCreateBuffer"); render_id[0] = packed_sei_header_param_buf_id; render_id[1] = packed_sei_buf_id; va_status = vaRenderPicture(va_dpy,context_id, render_id, 2); CHECK_VASTATUS(va_status,"vaRenderPicture"); free(packed_sei_buffer); return; } static int render_air(void) { VAStatus va_status; VABufferID misc_parameter_air_buf_id; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterAIR *misc_air_param; va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterAIR), 1, NULL, &misc_parameter_air_buf_id); CHECK_VASTATUS(va_status, "vaCreateBuffer"); vaMapBuffer(va_dpy, misc_parameter_air_buf_id, (void **)&misc_param); misc_param->type = VAEncMiscParameterTypeAIR; misc_air_param = (VAEncMiscParameterAIR *)misc_param->data; misc_air_param->air_num_mbs = num_air_mbs; misc_air_param->air_threshold = airthreshold; misc_air_param->air_auto = autotune_air; vaUnmapBuffer(va_dpy, misc_parameter_air_buf_id); va_status = vaRenderPicture(va_dpy,context_id, &misc_parameter_air_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; return 0; } static int render_cir(void) { VAStatus va_status; VABufferID misc_parameter_cir_buf_id; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterCIR *misc_cir_param; va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterCIR), 1, NULL, &misc_parameter_cir_buf_id); CHECK_VASTATUS(va_status, "vaCreateBuffer"); vaMapBuffer(va_dpy, misc_parameter_cir_buf_id, (void **)&misc_param); misc_param->type = VAEncMiscParameterTypeCIR; misc_cir_param = (VAEncMiscParameterCIR *)misc_param->data; misc_cir_param->cir_num_mbs = num_cir_mbs; vaUnmapBuffer(va_dpy, misc_parameter_cir_buf_id); va_status = vaRenderPicture(va_dpy,context_id, &misc_parameter_cir_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture"); return 0; } static int render_hrd(void) { VABufferID misc_parameter_hrd_buf_id; VAStatus va_status; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterHRD *misc_hrd_param; uint64_t bits_size = frame_bitrate; va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterHRD), 1, NULL, &misc_parameter_hrd_buf_id); CHECK_VASTATUS(va_status, "vaCreateBuffer"); vaMapBuffer(va_dpy, misc_parameter_hrd_buf_id, (void **)&misc_param); misc_param->type = VAEncMiscParameterTypeHRD; misc_hrd_param = (VAEncMiscParameterHRD *)misc_param->data; if (hrd_buffer_size > 0) { misc_hrd_param->buffer_size = hrd_buffer_size; misc_hrd_param->initial_buffer_fullness = misc_hrd_param->buffer_size * 0.875; } else { if (windows_size != 0) { misc_hrd_param->buffer_size = (uint32_t)((bits_size * (uint64_t)windows_size) / 1000); } else misc_hrd_param->buffer_size = frame_bitrate; misc_hrd_param->initial_buffer_fullness = misc_hrd_param->buffer_size * 0.875; } vaUnmapBuffer(va_dpy, misc_parameter_hrd_buf_id); va_status = vaRenderPicture(va_dpy,context_id, &misc_parameter_hrd_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; return 0; } static int render_slice(void) { VABufferID slice_param_buf; VAStatus va_status; VAEncSliceParameterBufferH264 *slice_param, *current_slice; int i, j, frame_slice_cc = frame_slice_count; int mb_rendered = 0; va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType, sizeof(VAEncSliceParameterBufferH264), frame_slice_count, NULL, &slice_param_buf); CHECK_VASTATUS(va_status,"vaCreateBuffer"); va_status = vaMapBuffer(va_dpy, slice_param_buf, (void **)&slice_param); CHECK_VASTATUS(va_status,"vaMapBuffer"); memset((void *)slice_param, 0, sizeof(VAEncSliceParameterBufferH264) * frame_slice_count); update_RefPicList(); for (j = 0; j < frame_slice_cc; j++) { current_slice = slice_param + j; current_slice->disable_deblocking_filter_idc = 1; current_slice->macroblock_address = mb_rendered; if (j == frame_slice_cc - 1) { current_slice->num_macroblocks = (frame_width_mbaligned * frame_height_mbaligned) / (16 * 16) - mb_rendered; } else { current_slice->num_macroblocks = (frame_width_mbaligned * frame_slice_height) / (16 * 16); mb_rendered += current_slice->num_macroblocks; } current_slice->slice_type = (current_frame_type == FRAME_IDR)? 2 : current_frame_type; if (current_frame_type == FRAME_IDR) { if (current_frame_encoding != 0) ++current_slice->idr_pic_id; } else if (current_frame_type == FRAME_P) { int refpiclist0_max = h264_maxref & 0xffff; memcpy(current_slice->RefPicList0, RefPicList0_P, refpiclist0_max*sizeof(VAPictureH264)); for (i = refpiclist0_max; i < 32; i++) { current_slice->RefPicList0[i].picture_id = VA_INVALID_SURFACE; current_slice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID; } } else if (current_frame_type == FRAME_B) { int refpiclist0_max = h264_maxref & 0xffff; int refpiclist1_max = (h264_maxref >> 16) & 0xffff; memcpy(current_slice->RefPicList0, RefPicList0_B, refpiclist0_max*sizeof(VAPictureH264)); for (i = refpiclist0_max; i < 32; i++) { current_slice->RefPicList0[i].picture_id = VA_INVALID_SURFACE; current_slice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID; } memcpy(current_slice->RefPicList1, RefPicList1_B, refpiclist1_max*sizeof(VAPictureH264)); for (i = refpiclist1_max; i < 32; i++) { current_slice->RefPicList1[i].picture_id = VA_INVALID_SURFACE; current_slice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID; } } current_slice->slice_alpha_c0_offset_div2 = 0; current_slice->slice_beta_offset_div2 = 0; current_slice->direct_spatial_mv_pred_flag = 1; current_slice->pic_order_cnt_lsb = (current_frame_display - current_IDR_display) % MaxPicOrderCntLsb; } va_status = vaUnmapBuffer(va_dpy, slice_param_buf); CHECK_VASTATUS(va_status,"vaUnmapBuffer"); va_status = vaRenderPicture(va_dpy, context_id, &slice_param_buf, 1); CHECK_VASTATUS(va_status,"vaRenderPicture"); return 0; } static int render_max_slice_size(void) { VAStatus va_status; VABufferID misc_parameter_max_slice_size_buf_id; VAEncMiscParameterBuffer *misc_param; VAEncMiscParameterMaxSliceSize *misc_max_slize_size_param; if (max_slice_size <= 0) { printf("Invalid max slice size(%d)\n", max_slice_size); return -1; } va_status = vaCreateBuffer(va_dpy, context_id, VAEncMiscParameterBufferType, sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterMaxSliceSize), 1, NULL, &misc_parameter_max_slice_size_buf_id); CHECK_VASTATUS(va_status, "vaCreateBuffer"); vaMapBuffer(va_dpy, misc_parameter_max_slice_size_buf_id, (void **)&misc_param); misc_param->type = VAEncMiscParameterTypeMaxSliceSize; misc_max_slize_size_param = (VAEncMiscParameterMaxSliceSize *)misc_param->data; misc_max_slize_size_param->max_slice_size = max_slice_size; vaUnmapBuffer(va_dpy, misc_parameter_max_slice_size_buf_id); va_status = vaRenderPicture(va_dpy, context_id, &misc_parameter_max_slice_size_buf_id, 1); CHECK_VASTATUS(va_status,"vaRenderPicture");; return 0; } static VAStatus h264_render_frame(unsigned int mask, struct rc_param_t *rc_param) { if (current_frame_type == FRAME_IDR) { numShortTerm = 0; current_frame_num = 0; current_IDR_display = current_frame_display; } if (current_frame_type == FRAME_IDR) { render_framerate(); render_sequence(); render_picture(); if (h264_packedheader) { render_packedsequence(); render_packedpicture(); } if (rc_mode == VA_RC_CBR) { //render_packedsei(); render_hrd(); } if (enableAIR) { render_air(); } if (num_cir_mbs) { render_cir(); } if (max_slice_size) { render_max_slice_size(); } } else { //render_sequence(); render_picture(); //if (rc_mode == VA_RC_CBR) // render_packedsei(); //render_hrd(); } if (mask) render_rcparam(mask, rc_param); render_slice(); update_ReferenceFrames(); return VA_STATUS_SUCCESS; } static VAStatus h264_get_config(void) { VAProfile profile_list[]={VAProfileH264High,VAProfileH264Main, VAProfileH264Baseline,VAProfileH264ConstrainedBaseline}; VAEntrypoint entrypoints[VAEntrypointMax]={0}; int num_entrypoints,slice_entrypoint; int support_encode = 0; VAStatus va_status; unsigned int i, n; if (va_profile_str) { if (strncmp(va_profile_str, "BP", 2) == 0) h264_profile = VAProfileH264Baseline; else if (strncmp(va_profile_str, "MP", 2) == 0) h264_profile = VAProfileH264Main; else if (strncmp(va_profile_str, "HP", 2) == 0) h264_profile = VAProfileH264High; else if (strncmp(va_profile_str, "CP", 2) == 0) h264_profile = VAProfileH264ConstrainedBaseline; } /* use the highest profile */ n = sizeof(profile_list)/sizeof(profile_list[0]); for (i = 0; i < n; i++) { VAProfile tmp = profile_list[i]; if ((h264_profile != -1) && h264_profile != tmp) continue; vaQueryConfigEntrypoints(va_dpy, tmp, entrypoints, &num_entrypoints); for (slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) { if (entrypoints[slice_entrypoint] == va_entrypoint) { support_encode = 1; h264_profile = tmp; break; } } if (support_encode == 1) break; } if (support_encode == 0) { printf("Can't find the target entrypoint for H264 profiles\n"); exit(1); } else { switch (h264_profile) { case VAProfileH264Baseline: printf("Use profile VAProfileH264Baseline\n"); ip_period = 1; constraint_set_flag |= (1 << 0); /* Annex A.2.1 */ h264_entropy_mode = 0; break; case VAProfileH264ConstrainedBaseline: printf("Use profile VAProfileH264ConstrainedBaseline\n"); constraint_set_flag |= (1 << 0 | 1 << 1); /* Annex A.2.2 */ ip_period = 1; break; case VAProfileH264Main: printf("Use profile VAProfileH264Main\n"); constraint_set_flag |= (1 << 1); /* Annex A.2.2 */ break; case VAProfileH264High: constraint_set_flag |= (1 << 3); /* Annex A.2.4 */ printf("Use profile VAProfileH264High\n"); break; default: printf("unknow profile. Set to Baseline"); h264_profile = VAProfileH264Baseline; ip_period = 1; constraint_set_flag |= (1 << 0); /* Annex A.2.1 */ break; } } /* find out the format for the render target, and rate control mode */ for (i = 0; i < VAConfigAttribTypeMax; i++) h264_attrib[i].type = i; va_status = vaGetConfigAttributes(va_dpy, h264_profile, va_entrypoint, &h264_attrib[0], VAConfigAttribTypeMax); CHECK_VASTATUS_NOEXIT(va_status, "vaGetConfigAttributes"); /* check the interested configattrib */ if ((h264_attrib[VAConfigAttribRTFormat].value & VA_RT_FORMAT_YUV420) == 0) { printf("Not find desired YUV420 RT format\n"); exit(1); } else { config_attrib[config_attrib_num].type = VAConfigAttribRTFormat; config_attrib[config_attrib_num].value = VA_RT_FORMAT_YUV420; config_attrib_num++; } if (h264_attrib[VAConfigAttribRateControl].value != VA_ATTRIB_NOT_SUPPORTED) { int tmp = h264_attrib[VAConfigAttribRateControl].value; printf("Support rate control mode (0x%x):", tmp); if (tmp & VA_RC_NONE) printf("NONE "); if (tmp & VA_RC_CBR) printf("CBR "); if (tmp & VA_RC_VBR) printf("VBR "); if (tmp & VA_RC_VCM) printf("VCM "); if (tmp & VA_RC_CQP) printf("CQP "); if (tmp & VA_RC_VBR_CONSTRAINED) printf("VBR_CONSTRAINED "); printf("\n"); if (!(rc_mode & tmp)) { printf("Desired rc mode %s is not supported, exit\n", rc_to_string(rc_mode)); exit(1); } config_attrib[config_attrib_num].type = VAConfigAttribRateControl; config_attrib[config_attrib_num].value = rc_mode; config_attrib_num++; } if (h264_attrib[VAConfigAttribEncPackedHeaders].value != VA_ATTRIB_NOT_SUPPORTED) { int tmp = h264_attrib[VAConfigAttribEncPackedHeaders].value; printf("Support VAConfigAttribEncPackedHeaders\n"); h264_packedheader = 1; config_attrib[config_attrib_num].type = VAConfigAttribEncPackedHeaders; config_attrib[config_attrib_num].value = VA_ENC_PACKED_HEADER_NONE; if (tmp & VA_ENC_PACKED_HEADER_SEQUENCE) { printf("Support packed sequence headers\n"); config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_SEQUENCE; } if (tmp & VA_ENC_PACKED_HEADER_PICTURE) { printf("Support packed picture headers\n"); config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_PICTURE; } if (tmp & VA_ENC_PACKED_HEADER_SLICE) { printf("Support packed slice headers\n"); //config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_SLICE; } if (tmp & VA_ENC_PACKED_HEADER_MISC) { printf("Support packed misc headers\n"); config_attrib[config_attrib_num].value |= VA_ENC_PACKED_HEADER_MISC; } config_attrib_num++; } if (h264_attrib[VAConfigAttribEncInterlaced].value != VA_ATTRIB_NOT_SUPPORTED) { int tmp = h264_attrib[VAConfigAttribEncInterlaced].value; printf("Support VAConfigAttribEncInterlaced\n"); if (tmp & VA_ENC_INTERLACED_FRAME) printf("support VA_ENC_INTERLACED_FRAME\n"); if (tmp & VA_ENC_INTERLACED_FIELD) printf("Support VA_ENC_INTERLACED_FIELD\n"); if (tmp & VA_ENC_INTERLACED_MBAFF) printf("Support VA_ENC_INTERLACED_MBAFF\n"); if (tmp & VA_ENC_INTERLACED_PAFF) printf("Support VA_ENC_INTERLACED_PAFF\n"); config_attrib[config_attrib_num].type = VAConfigAttribEncInterlaced; config_attrib[config_attrib_num].value = VA_ENC_PACKED_HEADER_NONE; config_attrib_num++; } if (h264_attrib[VAConfigAttribEncMaxRefFrames].value != VA_ATTRIB_NOT_SUPPORTED) { h264_maxref = h264_attrib[VAConfigAttribEncMaxRefFrames].value; printf("Support %d RefPicList0 and %d RefPicList1\n", h264_maxref & 0xffff, (h264_maxref >> 16) & 0xffff ); } if (h264_attrib[VAConfigAttribEncMaxSlices].value != VA_ATTRIB_NOT_SUPPORTED) printf("Support %d slices\n", h264_attrib[VAConfigAttribEncMaxSlices].value); if (h264_attrib[VAConfigAttribEncSliceStructure].value != VA_ATTRIB_NOT_SUPPORTED) { int tmp = h264_attrib[VAConfigAttribEncSliceStructure].value; printf("Support VAConfigAttribEncSliceStructure\n"); if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS) printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS\n"); if (tmp & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) printf("Support VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS\n"); if (tmp & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) printf("Support VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS\n"); } if (h264_attrib[VAConfigAttribEncMacroblockInfo].value != VA_ATTRIB_NOT_SUPPORTED) { printf("Support VAConfigAttribEncMacroblockInfo\n"); } if (h264_attrib[VAConfigAttribEncAutoReference].value != VA_ATTRIB_NOT_SUPPORTED) { printf("Support VAConfigAttribEncAutoReference\n"); h264_autoref = 1; } va_profile = h264_profile; /* * Force to use sync mode in order to guarantee dumping * dumping rec-frame correctly */ if (write_rec && h264_autoref || frame_size_log_fp) { printf("Force to use sync mode when dumping rec-frame" \ " with auto-reference enabled or dumping frame size" " log\n"); encode_syncmode = 1; } return VA_STATUS_SUCCESS; } /* process the meta data */ static int h264_save_codeddata(FILE *coded_fp, VACodedBufferSegment *buf_list, VASurfaceID *rec_surfaceid) { unsigned int coded_size = 0; VACodedBufferSegment *p = buf_list; while (p != NULL) { *rec_surfaceid = ref_surface[p->reserved]; coded_size += fwrite(p->buf, 1, p->size, coded_fp); p = (VACodedBufferSegment *) p->next; } return coded_size; } struct codec_table_t h264_codec = { get_config: h264_get_config, render_frame: h264_render_frame, save_codeddata: h264_save_codeddata, };