From 0d05a06cfeed9bc98bd70a43f6b2f5443fbfffd1 Mon Sep 17 00:00:00 2001 From: "Zhou,Chang" Date: Wed, 29 Feb 2012 13:57:42 +0800 Subject: [PATCH] Synced IVB with SNB, added HRD and multipul slices support. --- src/gen7_mfc.c | 337 ++++++++++++++++++++++++++++++++++++++------------------- src/gen7_mfc.h | 26 +++++ 2 files changed, 252 insertions(+), 111 deletions(-) diff --git a/src/gen7_mfc.c b/src/gen7_mfc.c index d55ec54..ec6e11e 100644 --- a/src/gen7_mfc.c +++ b/src/gen7_mfc.c @@ -299,7 +299,7 @@ gen7_mfc_avc_directmode_state(VADriverContextP ctx, struct intel_encoder_context static void gen7_mfc_avc_slice_state(VADriverContextP ctx, - int slice_type, + VAEncSliceParameterBufferH264 *slice_param, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, int rate_control_enable, @@ -307,7 +307,16 @@ gen7_mfc_avc_slice_state(VADriverContextP ctx, { struct intel_batchbuffer *batch = encoder_context->base.batch; struct gen7_mfc_context *mfc_context = encoder_context->mfc_context; - VAEncSliceParameterBufferH264 *pSliceParameter = (VAEncSliceParameterBufferH264 *)encode_state->slice_params_ext[0]->buffer; /* TODO: multi slices support */ + int width_in_mbs = (mfc_context->surface_state.width + 15) / 16; + int height_in_mbs = (mfc_context->surface_state.height + 15) / 16; + int beginmb = slice_param->starting_macroblock_address; + int endmb = beginmb + slice_param->number_of_mbs; + int beginx = beginmb % width_in_mbs; + int beginy = beginmb / width_in_mbs; + int nextx = endmb % width_in_mbs; + int nexty = endmb / width_in_mbs; + int slice_type = slice_param->slice_type; + int last_slice = (endmb == (width_in_mbs * height_in_mbs)); int bit_rate_control_target, maxQpN, maxQpP; unsigned char correct[6], grow, shrink; int i; @@ -340,12 +349,14 @@ gen7_mfc_avc_slice_state(VADriverContextP ctx, } OUT_BCS_BATCH(batch, - (pSliceParameter->direct_spatial_mv_pred_flag << 29) | /*Direct Prediction Type*/ + (slice_param->direct_spatial_mv_pred_flag << 29) | /*Direct Prediction Type*/ (0 << 24) | /*Enable deblocking operation*/ (qp << 16) | /*Slice Quantization Parameter*/ (0x0202 << 0)); - OUT_BCS_BATCH(batch, 0); /*First MB X&Y , the postion of current slice*/ - OUT_BCS_BATCH(batch, (((mfc_context->surface_state.height+15)/16) << 16)); + OUT_BCS_BATCH(batch, (beginy << 24) | /*First MB X&Y , the begin postion of current slice*/ + (beginx << 16) | + slice_param->starting_macroblock_address ); + OUT_BCS_BATCH(batch, (nexty << 16) | nextx); /*Next slice first MB X&Y*/ OUT_BCS_BATCH(batch, (rate_control_enable << 31) | /*in CBR mode RateControlCounterEnable = enable*/ (1 << 30) | /*ResetRateControlCounter*/ @@ -355,7 +366,7 @@ gen7_mfc_avc_slice_state(VADriverContextP ctx, (0 << 22) | /*QP mode, don't modfiy CBP*/ (0 << 21) | /*MB Type Direct Conversion Enabled*/ (0 << 20) | /*MB Type Skip Conversion Enabled*/ - (1 << 19) | /*IsLastSlice*/ + (last_slice << 19) | /*IsLastSlice*/ (0 << 18) | /*BitstreamOutputFlag Compressed BitStream Output Disable Flag 0:enable 1:disable*/ (1 << 17) | /*HeaderPresentFlag*/ (1 << 16) | /*SliceData PresentFlag*/ @@ -672,145 +683,213 @@ gen7_mfc_init(VADriverContextP ctx, struct intel_encoder_context *encoder_contex mfc_context->bsd_mpc_row_store_scratch_buffer.bo = bo; } -static void -gen7_mfc_avc_pipeline_programing(VADriverContextP ctx, - struct encode_state *encode_state, - struct intel_encoder_context *encoder_context) +static void gen7_mfc_avc_pipeline_header_programing(VADriverContextP ctx, + struct encode_state *encode_state, + struct intel_encoder_context *encoder_context) +{ + static int count = 0; + VAEncSequenceParameterBufferH264 *pSequenceParameter = (VAEncSequenceParameterBufferH264 *)encode_state->seq_param_ext->buffer; + int rate_control_mode = pSequenceParameter->rate_control_method; + + if (encode_state->packed_header_data[VAEncPackedHeaderSPS]) { + VAEncPackedHeaderParameterBuffer *param = NULL; + unsigned int *header_data = (unsigned int *)encode_state->packed_header_data[VAEncPackedHeaderSPS]->buffer; + unsigned int length_in_bits; + + assert(encode_state->packed_header_param[VAEncPackedHeaderSPS]); + param = (VAEncPackedHeaderParameterBuffer *)encode_state->packed_header_param[VAEncPackedHeaderSPS]->buffer; + length_in_bits = param->length_in_bits[0]; + + gen7_mfc_avc_insert_object(ctx, + encoder_context, + header_data, + ALIGN(length_in_bits, 32) >> 5, + length_in_bits & 0x1f, + param->skip_emulation_check_count, + 0, + 0, + param->insert_emulation_bytes); + } + + if (encode_state->packed_header_data[VAEncPackedHeaderPPS]) { + VAEncPackedHeaderParameterBuffer *param = NULL; + unsigned int *header_data = (unsigned int *)encode_state->packed_header_data[VAEncPackedHeaderPPS]->buffer; + unsigned int length_in_bits; + + assert(encode_state->packed_header_param[VAEncPackedHeaderPPS]); + param = (VAEncPackedHeaderParameterBuffer *)encode_state->packed_header_param[VAEncPackedHeaderPPS]->buffer; + length_in_bits = param->length_in_bits[0]; + + gen7_mfc_avc_insert_object(ctx, + encoder_context, + header_data, + ALIGN(length_in_bits, 32) >> 5, + length_in_bits & 0x1f, + param->skip_emulation_check_count, + 0, + 0, + param->insert_emulation_bytes); + } + + if ( (rate_control_mode == 0) && encode_state->packed_header_data[VAEncPackedHeaderSPS]) { // this is frist AU + int target_bit_rate = pSequenceParameter->bits_per_second; + int initial_remove_delay = pSequenceParameter->initial_hrd_buffer_fullness * 90000 / target_bit_rate; + + unsigned char *sei_data = NULL; + int length_in_bits = build_avc_sei_buffering_period(24, initial_remove_delay, 0, &sei_data); + gen7_mfc_avc_insert_object(ctx, + encoder_context, + (unsigned int *)sei_data, + ALIGN(length_in_bits, 32) >> 5, + length_in_bits & 0x1f, + 4, + 0, + 0, + 1); + free(sei_data); + } + + // SEI pic_timing header + if ( rate_control_mode == 0) { + unsigned char *sei_data = NULL; + int length_in_bits = build_avc_sei_pic_timing(24, count * 10, 24, 0, &sei_data); + gen7_mfc_avc_insert_object(ctx, + encoder_context, + (unsigned int *)sei_data, + ALIGN(length_in_bits, 32) >> 5, + length_in_bits & 0x1f, + 4, + 0, + 0, + 1); + free(sei_data); + } + + count++; +} + +static void gen7_mfc_avc_pipeline_picture_programing( VADriverContextP ctx, + struct encode_state *encode_state, + struct intel_encoder_context *encoder_context) +{ + gen7_mfc_pipe_mode_select(ctx, MFX_FORMAT_AVC, encoder_context); + gen7_mfc_surface_state(ctx, encoder_context); + gen7_mfc_ind_obj_base_addr_state(ctx, encoder_context); + gen7_mfc_pipe_buf_addr_state(ctx, encoder_context); + gen7_mfc_bsp_buf_base_addr_state(ctx, encoder_context); + gen7_mfc_avc_img_state(ctx, encode_state, encoder_context); + gen7_mfc_avc_qm_state(ctx, encoder_context); + gen7_mfc_avc_fqm_state(ctx, encoder_context); + gen7_mfc_avc_directmode_state(ctx, encoder_context); + gen7_mfc_avc_ref_idx_state(ctx, encoder_context); +} + +static void +gen7_mfc_avc_pipeline_slice_programing(VADriverContextP ctx, + struct encode_state *encode_state, + struct intel_encoder_context *encoder_context, + int slice_index) { - struct intel_batchbuffer *batch = encoder_context->base.batch; struct gen7_mfc_context *mfc_context = encoder_context->mfc_context; struct gen6_vme_context *vme_context = encoder_context->vme_context; VAEncSequenceParameterBufferH264 *pSequenceParameter = (VAEncSequenceParameterBufferH264 *)encode_state->seq_param_ext->buffer; VAEncPictureParameterBufferH264 *pPicParameter = (VAEncPictureParameterBufferH264 *)encode_state->pic_param_ext->buffer; - VAEncSliceParameterBufferH264 *pSliceParameter = (VAEncSliceParameterBufferH264 *)encode_state->slice_params_ext[0]->buffer; /* FIXME: multi slices */ + VAEncSliceParameterBufferH264 *pSliceParameter = (VAEncSliceParameterBufferH264 *)encode_state->slice_params_ext[slice_index]->buffer; VAEncH264DecRefPicMarkingBuffer *pDecRefPicMarking = NULL; unsigned int *msg = NULL, offset = 0; - int emit_new_state = 1, object_len_in_bytes; int is_intra = pSliceParameter->slice_type == SLICE_TYPE_I; int width_in_mbs = (mfc_context->surface_state.width + 15) / 16; int height_in_mbs = (mfc_context->surface_state.height + 15) / 16; - int x,y; - int rate_control_mode = pSequenceParameter->rate_control_method; - unsigned char target_mb_size = mfc_context->bit_rate_control_context[1-is_intra].TargetSizeInWord; - unsigned char max_mb_size = mfc_context->bit_rate_control_context[1-is_intra].MaxSizeInWord; + int last_slice = (pSliceParameter->starting_macroblock_address + pSliceParameter->number_of_mbs) == (width_in_mbs * height_in_mbs); + int i,x,y; int qp = pPicParameter->pic_init_qp + pSliceParameter->slice_qp_delta; + int rate_control_mode = pSequenceParameter->rate_control_method; unsigned char *slice_header = NULL; int slice_header_length_in_bits = 0; - unsigned int tail_data[] = { 0x0 }; + unsigned int tail_data[] = { 0x0, 0x0 }; + + gen7_mfc_avc_slice_state(ctx, pSliceParameter, + encode_state, encoder_context, + (rate_control_mode == 0), qp); + + if ( slice_index == 0) + gen7_mfc_avc_pipeline_header_programing(ctx, encode_state, encoder_context); if (encode_state->dec_ref_pic_marking) pDecRefPicMarking = (VAEncH264DecRefPicMarkingBuffer *)encode_state->dec_ref_pic_marking->buffer; - slice_header_length_in_bits = build_avc_slice_header(pSequenceParameter, pPicParameter, pSliceParameter, pDecRefPicMarking, &slice_header); + // slice hander + gen7_mfc_avc_insert_object(ctx, encoder_context, + (unsigned int *)slice_header, ALIGN(slice_header_length_in_bits, 32) >> 5, slice_header_length_in_bits & 0x1f, + 5, /* first 5 bytes are start code + nal unit type */ + 1, 0, 1); + if ( rate_control_mode == 0) { qp = mfc_context->bit_rate_control_context[1-is_intra].QpPrimeY; } - intel_batchbuffer_start_atomic_bcs(batch, 0x1000); - if (is_intra) { dri_bo_map(vme_context->vme_output.bo , 1); msg = (unsigned int *)vme_context->vme_output.bo->virtual; } - - for (y = 0; y < height_in_mbs; y++) { - for (x = 0; x < width_in_mbs; x++) { - int last_mb = (y == (height_in_mbs-1)) && ( x == (width_in_mbs-1) ); - - if (emit_new_state) { - intel_batchbuffer_emit_mi_flush(batch); - - gen7_mfc_pipe_mode_select(ctx, MFX_FORMAT_AVC, encoder_context); - gen7_mfc_surface_state(ctx, encoder_context); - gen7_mfc_ind_obj_base_addr_state(ctx, encoder_context); - gen7_mfc_pipe_buf_addr_state(ctx, encoder_context); - gen7_mfc_bsp_buf_base_addr_state(ctx, encoder_context); - gen7_mfc_avc_img_state(ctx, encode_state, encoder_context); - gen7_mfc_avc_qm_state(ctx, encoder_context); - gen7_mfc_avc_fqm_state(ctx, encoder_context); - gen7_mfc_avc_directmode_state(ctx, encoder_context); - gen7_mfc_avc_ref_idx_state(ctx, encoder_context); - gen7_mfc_avc_slice_state(ctx, pSliceParameter->slice_type, - encode_state, encoder_context, - rate_control_mode == 0, pPicParameter->pic_init_qp + pSliceParameter->slice_qp_delta); - - if (encode_state->packed_header_data[VAEncPackedHeaderSPS]) { - VAEncPackedHeaderParameterBuffer *param = NULL; - unsigned int *header_data = (unsigned int *)encode_state->packed_header_data[VAEncPackedHeaderSPS]->buffer; - unsigned int length_in_bits; - - assert(encode_state->packed_header_param[VAEncPackedHeaderSPS]); - param = (VAEncPackedHeaderParameterBuffer *)encode_state->packed_header_param[VAEncPackedHeaderSPS]->buffer; - length_in_bits = param->length_in_bits[0]; - - gen7_mfc_avc_insert_object(ctx, - encoder_context, - header_data, - ALIGN(length_in_bits, 32) >> 5, - length_in_bits & 0x1f, - param->skip_emulation_check_count, - 0, - 0, - param->insert_emulation_bytes); - } - - if (encode_state->packed_header_data[VAEncPackedHeaderPPS]) { - VAEncPackedHeaderParameterBuffer *param = NULL; - unsigned int *header_data = (unsigned int *)encode_state->packed_header_data[VAEncPackedHeaderPPS]->buffer; - unsigned int length_in_bits; - - assert(encode_state->packed_header_param[VAEncPackedHeaderPPS]); - param = (VAEncPackedHeaderParameterBuffer *)encode_state->packed_header_param[VAEncPackedHeaderPPS]->buffer; - length_in_bits = param->length_in_bits[0]; - - gen7_mfc_avc_insert_object(ctx, - encoder_context, - header_data, - ALIGN(length_in_bits, 32) >> 5, - length_in_bits & 0x1f, - param->skip_emulation_check_count, - 0, - 0, - param->insert_emulation_bytes); - } - - gen7_mfc_avc_insert_object(ctx, encoder_context, - (unsigned int *)slice_header, ALIGN(slice_header_length_in_bits, 32) >> 5, slice_header_length_in_bits & 0x1f, - 5, /* first 5 bytes are start code + nal unit type */ - 1, 0, 1); - emit_new_state = 0; - } - - if (is_intra) { - assert(msg); - object_len_in_bytes = gen7_mfc_avc_pak_object_intra(ctx, x, y, last_mb, qp, msg, encoder_context,target_mb_size, max_mb_size); - msg += 4; - } else { - object_len_in_bytes = gen7_mfc_avc_pak_object_inter(ctx, x, y, last_mb, qp, offset, encoder_context, target_mb_size, max_mb_size, pSliceParameter->slice_type); - offset += 64; - } - - if (intel_batchbuffer_check_free_space(batch, object_len_in_bytes) == 0) { - assert(0); - intel_batchbuffer_end_atomic(batch); - intel_batchbuffer_flush(batch); - emit_new_state = 1; - intel_batchbuffer_start_atomic_bcs(batch, 0x1000); - } + + for (i = pSliceParameter->starting_macroblock_address; + i < pSliceParameter->starting_macroblock_address + pSliceParameter->number_of_mbs; i++) { + int last_mb = (i == (pSliceParameter->starting_macroblock_address + pSliceParameter->number_of_mbs - 1) ); + x = i % width_in_mbs; + y = i / width_in_mbs; + + if (is_intra) { + assert(msg); + gen7_mfc_avc_pak_object_intra(ctx, x, y, last_mb, qp, msg, encoder_context, 0, 0); + msg += 4; + } else { + gen7_mfc_avc_pak_object_inter(ctx, x, y, last_mb, qp, offset, encoder_context, 0, 0, pSliceParameter->slice_type); + offset += 64; } } - - gen7_mfc_avc_insert_object(ctx, encoder_context, - tail_data, sizeof(tail_data) >> 2, 32, - sizeof(tail_data), 1, 1, 1); - + if (is_intra) dri_bo_unmap(vme_context->vme_output.bo); + if ( last_slice ) { + gen7_mfc_avc_insert_object(ctx, encoder_context, + tail_data, 2, 8, + 2, 1, 1, 0); + } else { + gen7_mfc_avc_insert_object(ctx, encoder_context, + tail_data, 1, 8, + 1, 1, 1, 0); + } free(slice_header); +} + +static void +gen7_mfc_avc_pipeline_programing(VADriverContextP ctx, + struct encode_state *encode_state, + struct intel_encoder_context *encoder_context) +{ + struct intel_batchbuffer *batch = encoder_context->base.batch; + int i; + + // begin programing + intel_batchbuffer_start_atomic_bcs(batch, 0x4000); + intel_batchbuffer_emit_mi_flush(batch); + + // picture level programing + gen7_mfc_avc_pipeline_picture_programing(ctx, encode_state, encoder_context); + + for ( i = 0; i < encode_state->num_slice_params_ext; i++) { + // slice level programing + gen7_mfc_avc_pipeline_slice_programing(ctx, encode_state, encoder_context, i); + } + + // end programing intel_batchbuffer_end_atomic(batch); + + return; } static void @@ -908,6 +987,36 @@ gen7_mfc_bit_rate_control_context_update(struct encode_state *encode_state, return 1; } +static void +gen7_mfc_hrd_context_init(struct encode_state *encode_state, + struct gen7_mfc_context *mfc_context) +{ + VAEncSequenceParameterBufferH264 *pSequenceParameter = (VAEncSequenceParameterBufferH264 *)encode_state->seq_param_ext->buffer; + int rate_control_mode = pSequenceParameter->rate_control_method; + int target_bit_rate = pSequenceParameter->bits_per_second; + + // current we only support CBR mode. + if ( rate_control_mode == 0) { + mfc_context->vui_hrd.i_cpb_cnt = 0; + mfc_context->vui_hrd.i_bit_rate_scale = 0; + mfc_context->vui_hrd.i_cpb_size_scale = 2; + mfc_context->vui_hrd.i_cbr_flag = 0; + + mfc_context->vui_hrd.i_bit_rate_unscaled = target_bit_rate; + mfc_context->vui_hrd.i_cpb_size_unscaled = target_bit_rate / 5; + mfc_context->vui_hrd.i_bit_rate_value = target_bit_rate >> ( 6 + mfc_context->vui_hrd.i_bit_rate_scale ); + mfc_context->vui_hrd.i_cpb_size_value = (target_bit_rate / 5) >> ( 4 + mfc_context->vui_hrd.i_cpb_size_scale ); + + mfc_context->vui_hrd.i_initial_cpb_removal_delay_length = 24; + mfc_context->vui_hrd.i_cpb_removal_delay_length = 24; + mfc_context->vui_hrd.i_dpb_output_delay_length = 24; + mfc_context->vui_hrd.i_time_offset_length = 24; + } + +} + + + static VAStatus gen7_mfc_avc_prepare(VADriverContextP ctx, struct encode_state *encode_state, @@ -920,6 +1029,8 @@ gen7_mfc_avc_prepare(VADriverContextP ctx, struct gen7_mfc_avc_surface_aux* gen7_avc_surface; dri_bo *bo; VAEncPictureParameterBufferH264 *pPicParameter = (VAEncPictureParameterBufferH264 *)encode_state->pic_param_ext->buffer; + VAEncSequenceParameterBufferH264 *pSequenceParameter = (VAEncSequenceParameterBufferH264 *)encode_state->seq_param_ext->buffer; + int rate_control_mode = pSequenceParameter->rate_control_method; VAStatus vaStatus = VA_STATUS_SUCCESS; int i; @@ -1019,6 +1130,10 @@ gen7_mfc_avc_prepare(VADriverContextP ctx, if ( mfc_context->bit_rate_control_context[0].MaxSizeInWord == 0 ) gen7_mfc_bit_rate_control_context_init(encode_state, mfc_context); + /*Programing HRD control */ + if ( (rate_control_mode == 0) && (mfc_context->vui_hrd.i_cpb_size_value == 0) ) + gen7_mfc_hrd_context_init(encode_state, mfc_context); + /*Programing bcs pipeline*/ gen7_mfc_avc_pipeline_programing(ctx, encode_state, encoder_context); //filling the pipeline diff --git a/src/gen7_mfc.h b/src/gen7_mfc.h index 631ba4f..6b355b2 100644 --- a/src/gen7_mfc.h +++ b/src/gen7_mfc.h @@ -121,6 +121,32 @@ struct gen7_mfc_context unsigned int target_frame_size; } bit_rate_control_context[2]; //INTERNAL: 0 for intra frames, 1 for inter frames. + // HRD control context + struct { + int i_cpb_cnt; + int i_bit_rate_scale; + int i_cpb_size_scale; + int i_cbr_flag; + int i_bit_rate_value; + int i_cpb_size_value; + int i_bit_rate_unscaled; + int i_cpb_size_unscaled; + + int i_initial_cpb_removal_delay_length; + int i_cpb_removal_delay_length; + int i_dpb_output_delay_length; + int i_time_offset_length; + + }vui_hrd; + + struct { + double cpb_initial_arrival_time; + double cpb_final_arrival_time; + double cpb_removal_time; + + double dpb_output_time; + }hrd_frame_result; + }; #endif /* _GEN7_MFC_BCS_H_ */ -- 2.7.4