Added HRD support for Gen6.
authorZhou Chang <chang.zhou@intel.com>
Mon, 6 Feb 2012 15:50:38 +0000 (23:50 +0800)
committerXiang, Haihao <haihao.xiang@intel.com>
Mon, 6 Feb 2012 08:04:11 +0000 (16:04 +0800)
src/gen6_mfc.c

index abc9a92..d3b8179 100644 (file)
@@ -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, &current_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;
         }