From: Zhou Chang Date: Mon, 6 Feb 2012 15:50:38 +0000 (+0800) Subject: Added HRD support for Gen6. X-Git-Tag: 1.0_branch~148 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7eeb6c9233d1c63d83b578bfca4f292eac8d320c;p=profile%2Fivi%2Fvaapi-intel-driver.git Added HRD support for Gen6. --- diff --git a/src/gen6_mfc.c b/src/gen6_mfc.c index abc9a92..d3b8179 100644 --- a/src/gen6_mfc.c +++ b/src/gen6_mfc.c @@ -296,11 +296,21 @@ static void gen6_mfc_avc_slice_state(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, int rate_control_enable, - int qp) + int qp, + int slice_index) { struct intel_batchbuffer *batch = encoder_context->base.batch; struct gen6_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 = pSliceParameter->starting_macroblock_address; + int endmb = beginmb + pSliceParameter->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 last_slice = (pSliceParameter->starting_macroblock_address + pSliceParameter->number_of_mbs) == (width_in_mbs * height_in_mbs); int bit_rate_control_target; if ( slice_type == SLICE_TYPE_I ) bit_rate_control_target = 0; @@ -335,9 +345,10 @@ static void gen6_mfc_avc_slice_state(VADriverContextP ctx, (0<<24) | /*Enable deblocking operation*/ (qp<<16) | /*Slice Quantization Parameter*/ 0x0202 ); - 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) | + pSliceParameter->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*/ @@ -347,7 +358,7 @@ static void gen6_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*/ @@ -616,143 +627,217 @@ static void gen6_mfc_init(VADriverContextP ctx, struct intel_encoder_context *en mfc_context->bsd_mpc_row_store_scratch_buffer.bo = bo; } -void gen6_mfc_avc_pipeline_programing(VADriverContextP ctx, +static void gen6_mfc_avc_pipeline_header_programing(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { - struct intel_batchbuffer *batch = encoder_context->base.batch; + 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]; + + gen6_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]; + + gen6_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 + struct gen6_mfc_context *mfc_context = encoder_context->mfc_context; + + unsigned char *sei_data = NULL; + int length_in_bits = build_avc_sei_buffering_period(mfc_context->vui_hrd.i_initial_cpb_removal_delay_length, + mfc_context->vui_hrd.i_initial_cpb_removal_delay, 0, &sei_data); + gen6_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) { + struct gen6_mfc_context *mfc_context = encoder_context->mfc_context; + unsigned char *sei_data = NULL; + int length_in_bits = build_avc_sei_pic_timing( mfc_context->vui_hrd.i_cpb_removal_delay_length, + mfc_context->vui_hrd.i_cpb_removal_delay * mfc_context->vui_hrd.i_frame_number, + mfc_context->vui_hrd.i_dpb_output_delay_length, + 0, &sei_data); + gen6_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 gen6_mfc_avc_pipeline_picture_programing( VADriverContextP ctx, + struct encode_state *encode_state, + struct intel_encoder_context *encoder_context) +{ + gen6_mfc_pipe_mode_select(ctx, encoder_context); + gen6_mfc_surface_state(ctx, encoder_context); + gen6_mfc_ind_obj_base_addr_state(ctx, encoder_context); + gen6_mfc_pipe_buf_addr_state(ctx, encoder_context); + gen6_mfc_bsp_buf_base_addr_state(ctx, encoder_context); + gen6_mfc_avc_img_state(ctx, encode_state, encoder_context); + gen6_mfc_avc_qm_state(ctx, encoder_context); + gen6_mfc_avc_fqm_state(ctx, encoder_context); + gen6_mfc_avc_directmode_state(ctx, encoder_context); + gen6_mfc_avc_ref_idx_state(ctx, encoder_context); +} + +static void +gen6_mfc_avc_pipeline_slice_programing(VADriverContextP ctx, + struct encode_state *encode_state, + struct intel_encoder_context *encoder_context, + int slice_index) +{ struct gen6_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 }; + + gen6_mfc_avc_slice_state(ctx, pSliceParameter->slice_type, + encode_state, encoder_context, + (rate_control_mode == 0), qp, slice_index); + + if ( slice_index == 0) + gen6_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 + gen6_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); - gen6_mfc_pipe_mode_select(ctx, encoder_context); - gen6_mfc_surface_state(ctx, encoder_context); - gen6_mfc_ind_obj_base_addr_state(ctx, encoder_context); - gen6_mfc_pipe_buf_addr_state(ctx, encoder_context); - gen6_mfc_bsp_buf_base_addr_state(ctx, encoder_context); - gen6_mfc_avc_img_state(ctx, encode_state,encoder_context); - gen6_mfc_avc_qm_state(ctx, encoder_context); - gen6_mfc_avc_fqm_state(ctx, encoder_context); - gen6_mfc_avc_directmode_state(ctx, encoder_context); - gen6_mfc_avc_ref_idx_state(ctx, encoder_context); - gen6_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]; - - gen6_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]; - - gen6_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); - } - - gen6_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 = gen6_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 = gen6_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); + gen6_mfc_avc_pak_object_intra(ctx, x, y, last_mb, qp, msg, encoder_context, 0, 0); + msg += 4; + } else { + gen6_mfc_avc_pak_object_inter(ctx, x, y, last_mb, qp, offset, encoder_context, 0, 0, pSliceParameter->slice_type); + offset += 64; } } - - gen6_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 ) { + gen6_mfc_avc_insert_object(ctx, encoder_context, + tail_data, 2, 8, + 2, 1, 1, 0); + } else { + gen6_mfc_avc_insert_object(ctx, encoder_context, + tail_data, 1, 8, + 1, 1, 1, 0); + } free(slice_header); +} + +static void +gen6_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 + gen6_mfc_avc_pipeline_picture_programing(ctx, encode_state, encoder_context); + + for ( i = 0; i < encode_state->num_slice_params_ext; i++) { + // slice level programing + gen6_mfc_avc_pipeline_slice_programing(ctx, encode_state, encoder_context, i); + } + + // end programing intel_batchbuffer_end_atomic(batch); + + return; } static void @@ -854,6 +939,43 @@ static int gen6_mfc_bit_rate_control_context_update(struct encode_state *encode_ return 1; } +static void +gen6_mfc_hrd_context_init(struct encode_state *encode_state, + struct gen6_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_bit_rate_value = target_bit_rate >> 10; + mfc_context->vui_hrd.i_cpb_size_value = (target_bit_rate * 8) >> 10; + mfc_context->vui_hrd.i_initial_cpb_removal_delay = mfc_context->vui_hrd.i_cpb_size_value * 0.5 * 1024 / target_bit_rate * 90000; + mfc_context->vui_hrd.i_cpb_removal_delay = 2; + mfc_context->vui_hrd.i_frame_number = 0; + + 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; + } + +} + +static VAStatus +gen6_mfc_hrd_context_check(struct encode_state *encode_state, + struct gen6_mfc_context *mfc_context) +{ + return VA_STATUS_SUCCESS; +} + +static void +gen6_mfc_hrd_context_update(struct encode_state *encode_state, + struct gen6_mfc_context *mfc_context) +{ + mfc_context->vui_hrd.i_frame_number++; +} + static VAStatus gen6_mfc_avc_prepare(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) @@ -865,6 +987,8 @@ static VAStatus gen6_mfc_avc_prepare(VADriverContextP ctx, struct gen6_mfc_avc_surface_aux* gen6_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; @@ -962,6 +1086,10 @@ static VAStatus gen6_mfc_avc_prepare(VADriverContextP ctx, if ( mfc_context->bit_rate_control_context[0].MaxSizeInWord == 0 ) gen6_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) ) + gen6_mfc_hrd_context_init(encode_state, mfc_context); + /*Programing bcs pipeline*/ gen6_mfc_avc_pipeline_programing(ctx, encode_state, encoder_context); //filling the pipeline @@ -1024,8 +1152,11 @@ gen6_mfc_avc_encode_picture(VADriverContextP ctx, gen6_mfc_run(ctx, encode_state, encoder_context); gen6_mfc_stop(ctx, encode_state, encoder_context, ¤t_frame_bits_size); if ( rate_control_mode == 0) { - if ( gen6_mfc_bit_rate_control_context_update( encode_state, mfc_context, current_frame_bits_size) ) + //gen6_mfc_hrd_context_check(encode_state, mfc_context); + if ( gen6_mfc_bit_rate_control_context_update( encode_state, mfc_context, current_frame_bits_size) ) { + gen6_mfc_hrd_context_update(encode_state, mfc_context); break; + } } else { break; }