| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| #include "avcenc_lib.h" |
| #include "avcenc_api.h" |
| |
| #define LOG2_MAX_FRAME_NUM_MINUS4 12 /* 12 default */ |
| #define SLICE_GROUP_CHANGE_CYCLE 1 /* default */ |
| |
| /* initialized variables to be used in SPS*/ |
| AVCEnc_Status SetEncodeParam(AVCHandle* avcHandle, AVCEncParams* encParam, |
| void* extSPS, void* extPPS) |
| { |
| AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject; |
| AVCCommonObj *video = encvid->common; |
| AVCSeqParamSet *seqParam = video->currSeqParams; |
| AVCPicParamSet *picParam = video->currPicParams; |
| AVCSliceHeader *sliceHdr = video->sliceHdr; |
| AVCRateControl *rateCtrl = encvid->rateCtrl; |
| AVCEnc_Status status; |
| void *userData = avcHandle->userData; |
| int ii, maxFrameNum; |
| |
| AVCSeqParamSet* extS = NULL; |
| AVCPicParamSet* extP = NULL; |
| |
| if (extSPS) extS = (AVCSeqParamSet*) extSPS; |
| if (extPPS) extP = (AVCPicParamSet*) extPPS; |
| |
| /* This part sets the default values of the encoding options this |
| library supports in seqParam, picParam and sliceHdr structures and |
| also copy the values from the encParam into the above 3 structures. |
| |
| Some parameters will be assigned later when we encode SPS or PPS such as |
| the seq_parameter_id or pic_parameter_id. Also some of the slice parameters |
| have to be re-assigned per slice basis such as frame_num, slice_type, |
| first_mb_in_slice, pic_order_cnt_lsb, slice_qp_delta, slice_group_change_cycle */ |
| |
| /* profile_idc, constrained_setx_flag and level_idc is set by VerifyProfile(), |
| and VerifyLevel() functions later. */ |
| |
| encvid->fullsearch_enable = encParam->fullsearch; |
| |
| encvid->outOfBandParamSet = ((encParam->out_of_band_param_set == AVC_ON) ? TRUE : FALSE); |
| |
| /* parameters derived from the the encParam that are used in SPS */ |
| if (extS) |
| { |
| video->MaxPicOrderCntLsb = 1 << (extS->log2_max_pic_order_cnt_lsb_minus4 + 4); |
| video->PicWidthInMbs = extS->pic_width_in_mbs_minus1 + 1; |
| video->PicHeightInMapUnits = extS->pic_height_in_map_units_minus1 + 1 ; |
| video->FrameHeightInMbs = (2 - extS->frame_mbs_only_flag) * video->PicHeightInMapUnits ; |
| } |
| else |
| { |
| video->MaxPicOrderCntLsb = 1 << (encParam->log2_max_poc_lsb_minus_4 + 4); |
| video->PicWidthInMbs = (encParam->width + 15) >> 4; /* round it to multiple of 16 */ |
| video->FrameHeightInMbs = (encParam->height + 15) >> 4; /* round it to multiple of 16 */ |
| video->PicHeightInMapUnits = video->FrameHeightInMbs; |
| } |
| |
| video->PicWidthInSamplesL = video->PicWidthInMbs * 16 ; |
| if (video->PicWidthInSamplesL + 32 > 0xFFFF) |
| { |
| return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch |
| } |
| |
| video->PicWidthInSamplesC = video->PicWidthInMbs * 8 ; |
| video->PicHeightInMbs = video->FrameHeightInMbs; |
| video->PicSizeInMapUnits = video->PicWidthInMbs * video->PicHeightInMapUnits ; |
| video->PicHeightInSamplesL = video->PicHeightInMbs * 16; |
| video->PicHeightInSamplesC = video->PicHeightInMbs * 8; |
| video->PicSizeInMbs = video->PicWidthInMbs * video->PicHeightInMbs; |
| |
| if (!extS && !extP) |
| { |
| maxFrameNum = (encParam->idr_period == -1) ? (1 << 16) : encParam->idr_period; |
| ii = 0; |
| while (maxFrameNum > 0) |
| { |
| ii++; |
| maxFrameNum >>= 1; |
| } |
| if (ii < 4) ii = 4; |
| else if (ii > 16) ii = 16; |
| |
| seqParam->log2_max_frame_num_minus4 = ii - 4;//LOG2_MAX_FRAME_NUM_MINUS4; /* default */ |
| |
| video->MaxFrameNum = 1 << ii; //(LOG2_MAX_FRAME_NUM_MINUS4 + 4); /* default */ |
| video->MaxPicNum = video->MaxFrameNum; |
| |
| /************* set the SPS *******************/ |
| seqParam->seq_parameter_set_id = 0; /* start with zero */ |
| /* POC */ |
| seqParam->pic_order_cnt_type = encParam->poc_type; /* POC type */ |
| if (encParam->poc_type == 0) |
| { |
| if (/*encParam->log2_max_poc_lsb_minus_4<0 || (no need, it's unsigned)*/ |
| encParam->log2_max_poc_lsb_minus_4 > 12) |
| { |
| return AVCENC_INVALID_POC_LSB; |
| } |
| seqParam->log2_max_pic_order_cnt_lsb_minus4 = encParam->log2_max_poc_lsb_minus_4; |
| } |
| else if (encParam->poc_type == 1) |
| { |
| seqParam->delta_pic_order_always_zero_flag = encParam->delta_poc_zero_flag; |
| seqParam->offset_for_non_ref_pic = encParam->offset_poc_non_ref; |
| seqParam->offset_for_top_to_bottom_field = encParam->offset_top_bottom; |
| seqParam->num_ref_frames_in_pic_order_cnt_cycle = encParam->num_ref_in_cycle; |
| if (encParam->offset_poc_ref == NULL) |
| { |
| return AVCENC_ENCPARAM_MEM_FAIL; |
| } |
| for (ii = 0; ii < encParam->num_ref_frame; ii++) |
| { |
| seqParam->offset_for_ref_frame[ii] = encParam->offset_poc_ref[ii]; |
| } |
| } |
| /* number of reference frame */ |
| if (encParam->num_ref_frame > 16 || encParam->num_ref_frame < 0) |
| { |
| return AVCENC_INVALID_NUM_REF; |
| } |
| seqParam->num_ref_frames = encParam->num_ref_frame; /* num reference frame range 0...16*/ |
| seqParam->gaps_in_frame_num_value_allowed_flag = FALSE; |
| seqParam->pic_width_in_mbs_minus1 = video->PicWidthInMbs - 1; |
| seqParam->pic_height_in_map_units_minus1 = video->PicHeightInMapUnits - 1; |
| seqParam->frame_mbs_only_flag = TRUE; |
| seqParam->mb_adaptive_frame_field_flag = FALSE; |
| seqParam->direct_8x8_inference_flag = FALSE; /* default */ |
| seqParam->frame_cropping_flag = FALSE; |
| seqParam->frame_crop_bottom_offset = 0; |
| seqParam->frame_crop_left_offset = 0; |
| seqParam->frame_crop_right_offset = 0; |
| seqParam->frame_crop_top_offset = 0; |
| seqParam->vui_parameters_present_flag = FALSE; /* default */ |
| } |
| else if (extS) // use external SPS and PPS |
| { |
| seqParam->seq_parameter_set_id = extS->seq_parameter_set_id; |
| seqParam->log2_max_frame_num_minus4 = extS->log2_max_frame_num_minus4; |
| video->MaxFrameNum = 1 << (extS->log2_max_frame_num_minus4 + 4); |
| video->MaxPicNum = video->MaxFrameNum; |
| if (encParam->idr_period > (int)(video->MaxFrameNum) || (encParam->idr_period == -1)) |
| { |
| encParam->idr_period = (int)video->MaxFrameNum; |
| } |
| |
| seqParam->pic_order_cnt_type = extS->pic_order_cnt_type; |
| if (seqParam->pic_order_cnt_type == 0) |
| { |
| if (/*extS->log2_max_pic_order_cnt_lsb_minus4<0 || (no need it's unsigned)*/ |
| extS->log2_max_pic_order_cnt_lsb_minus4 > 12) |
| { |
| return AVCENC_INVALID_POC_LSB; |
| } |
| seqParam->log2_max_pic_order_cnt_lsb_minus4 = extS->log2_max_pic_order_cnt_lsb_minus4; |
| } |
| else if (seqParam->pic_order_cnt_type == 1) |
| { |
| seqParam->delta_pic_order_always_zero_flag = extS->delta_pic_order_always_zero_flag; |
| seqParam->offset_for_non_ref_pic = extS->offset_for_non_ref_pic; |
| seqParam->offset_for_top_to_bottom_field = extS->offset_for_top_to_bottom_field; |
| seqParam->num_ref_frames_in_pic_order_cnt_cycle = extS->num_ref_frames_in_pic_order_cnt_cycle; |
| for (ii = 0; ii < (int) extS->num_ref_frames; ii++) |
| { |
| seqParam->offset_for_ref_frame[ii] = extS->offset_for_ref_frame[ii]; |
| } |
| } |
| /* number of reference frame */ |
| if (extS->num_ref_frames > 16 /*|| extS->num_ref_frames<0 (no need, it's unsigned)*/) |
| { |
| return AVCENC_INVALID_NUM_REF; |
| } |
| seqParam->num_ref_frames = extS->num_ref_frames; /* num reference frame range 0...16*/ |
| seqParam->gaps_in_frame_num_value_allowed_flag = extS->gaps_in_frame_num_value_allowed_flag; |
| seqParam->pic_width_in_mbs_minus1 = extS->pic_width_in_mbs_minus1; |
| seqParam->pic_height_in_map_units_minus1 = extS->pic_height_in_map_units_minus1; |
| seqParam->frame_mbs_only_flag = extS->frame_mbs_only_flag; |
| if (extS->frame_mbs_only_flag != TRUE) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| seqParam->mb_adaptive_frame_field_flag = extS->mb_adaptive_frame_field_flag; |
| if (extS->mb_adaptive_frame_field_flag != FALSE) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| seqParam->direct_8x8_inference_flag = extS->direct_8x8_inference_flag; |
| seqParam->frame_cropping_flag = extS->frame_cropping_flag ; |
| if (extS->frame_cropping_flag != FALSE) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| seqParam->frame_crop_bottom_offset = 0; |
| seqParam->frame_crop_left_offset = 0; |
| seqParam->frame_crop_right_offset = 0; |
| seqParam->frame_crop_top_offset = 0; |
| seqParam->vui_parameters_present_flag = extS->vui_parameters_present_flag; |
| if (extS->vui_parameters_present_flag) |
| { |
| memcpy(&(seqParam->vui_parameters), &(extS->vui_parameters), sizeof(AVCVUIParams)); |
| } |
| } |
| else |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| /***************** now PPS ******************************/ |
| if (!extP && !extS) |
| { |
| picParam->pic_parameter_set_id = (uint)(-1); /* start with zero */ |
| picParam->seq_parameter_set_id = (uint)(-1); /* start with zero */ |
| picParam->entropy_coding_mode_flag = 0; /* default to CAVLC */ |
| picParam->pic_order_present_flag = 0; /* default for now, will need it for B-slice */ |
| /* FMO */ |
| if (encParam->num_slice_group < 1 || encParam->num_slice_group > MAX_NUM_SLICE_GROUP) |
| { |
| return AVCENC_INVALID_NUM_SLICEGROUP; |
| } |
| picParam->num_slice_groups_minus1 = encParam->num_slice_group - 1; |
| |
| if (picParam->num_slice_groups_minus1 > 0) |
| { |
| picParam->slice_group_map_type = encParam->fmo_type; |
| switch (encParam->fmo_type) |
| { |
| case 0: |
| for (ii = 0; ii <= (int)picParam->num_slice_groups_minus1; ii++) |
| { |
| picParam->run_length_minus1[ii] = encParam->run_length_minus1[ii]; |
| } |
| break; |
| case 2: |
| for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++) |
| { |
| picParam->top_left[ii] = encParam->top_left[ii]; |
| picParam->bottom_right[ii] = encParam->bottom_right[ii]; |
| } |
| break; |
| case 3: |
| case 4: |
| case 5: |
| if (encParam->change_dir_flag == AVC_ON) |
| { |
| picParam->slice_group_change_direction_flag = TRUE; |
| } |
| else |
| { |
| picParam->slice_group_change_direction_flag = FALSE; |
| } |
| if (/*encParam->change_rate_minus1 < 0 || (no need it's unsigned) */ |
| encParam->change_rate_minus1 > video->PicSizeInMapUnits - 1) |
| { |
| return AVCENC_INVALID_CHANGE_RATE; |
| } |
| picParam->slice_group_change_rate_minus1 = encParam->change_rate_minus1; |
| video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1; |
| break; |
| case 6: |
| picParam->pic_size_in_map_units_minus1 = video->PicSizeInMapUnits - 1; |
| |
| /* allocate picParam->slice_group_id */ |
| picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR); |
| if (picParam->slice_group_id == NULL) |
| { |
| return AVCENC_MEMORY_FAIL; |
| } |
| |
| if (encParam->slice_group == NULL) |
| { |
| return AVCENC_ENCPARAM_MEM_FAIL; |
| } |
| for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++) |
| { |
| picParam->slice_group_id[ii] = encParam->slice_group[ii]; |
| } |
| break; |
| default: |
| return AVCENC_INVALID_FMO_TYPE; |
| } |
| } |
| picParam->num_ref_idx_l0_active_minus1 = encParam->num_ref_frame - 1; /* assume frame only */ |
| picParam->num_ref_idx_l1_active_minus1 = 0; /* default value */ |
| picParam->weighted_pred_flag = 0; /* no weighted prediction supported */ |
| picParam->weighted_bipred_idc = 0; /* range 0,1,2 */ |
| if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */ |
| picParam->weighted_bipred_idc > 2) |
| { |
| return AVCENC_WEIGHTED_BIPRED_FAIL; |
| } |
| picParam->pic_init_qp_minus26 = 0; /* default, will be changed at slice level anyway */ |
| if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25) |
| { |
| return AVCENC_INIT_QP_FAIL; /* out of range */ |
| } |
| picParam->pic_init_qs_minus26 = 0; |
| if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25) |
| { |
| return AVCENC_INIT_QS_FAIL; /* out of range */ |
| } |
| |
| picParam->chroma_qp_index_offset = 0; /* default to zero for now */ |
| if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12) |
| { |
| return AVCENC_CHROMA_QP_FAIL; /* out of range */ |
| } |
| /* deblocking */ |
| picParam->deblocking_filter_control_present_flag = (encParam->db_filter == AVC_ON) ? TRUE : FALSE ; |
| /* constrained intra prediction */ |
| picParam->constrained_intra_pred_flag = (encParam->constrained_intra_pred == AVC_ON) ? TRUE : FALSE; |
| picParam->redundant_pic_cnt_present_flag = 0; /* default */ |
| } |
| else if (extP)// external PPS |
| { |
| picParam->pic_parameter_set_id = extP->pic_parameter_set_id - 1; /* to be increased by one */ |
| picParam->seq_parameter_set_id = extP->seq_parameter_set_id; |
| picParam->entropy_coding_mode_flag = extP->entropy_coding_mode_flag; |
| if (extP->entropy_coding_mode_flag != 0) /* default to CAVLC */ |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| picParam->pic_order_present_flag = extP->pic_order_present_flag; /* default for now, will need it for B-slice */ |
| if (extP->pic_order_present_flag != 0) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| /* FMO */ |
| if (/*(extP->num_slice_groups_minus1<0) || (no need it's unsigned) */ |
| (extP->num_slice_groups_minus1 > MAX_NUM_SLICE_GROUP - 1)) |
| { |
| return AVCENC_INVALID_NUM_SLICEGROUP; |
| } |
| picParam->num_slice_groups_minus1 = extP->num_slice_groups_minus1; |
| |
| if (picParam->num_slice_groups_minus1 > 0) |
| { |
| picParam->slice_group_map_type = extP->slice_group_map_type; |
| switch (extP->slice_group_map_type) |
| { |
| case 0: |
| for (ii = 0; ii <= (int)extP->num_slice_groups_minus1; ii++) |
| { |
| picParam->run_length_minus1[ii] = extP->run_length_minus1[ii]; |
| } |
| break; |
| case 2: |
| for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++) |
| { |
| picParam->top_left[ii] = extP->top_left[ii]; |
| picParam->bottom_right[ii] = extP->bottom_right[ii]; |
| } |
| break; |
| case 3: |
| case 4: |
| case 5: |
| picParam->slice_group_change_direction_flag = extP->slice_group_change_direction_flag; |
| if (/*extP->slice_group_change_rate_minus1 < 0 || (no need, it's unsigned) */ |
| extP->slice_group_change_rate_minus1 > video->PicSizeInMapUnits - 1) |
| { |
| return AVCENC_INVALID_CHANGE_RATE; |
| } |
| picParam->slice_group_change_rate_minus1 = extP->slice_group_change_rate_minus1; |
| video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1; |
| break; |
| case 6: |
| if (extP->pic_size_in_map_units_minus1 != video->PicSizeInMapUnits - 1) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| picParam->pic_size_in_map_units_minus1 = extP->pic_size_in_map_units_minus1; |
| |
| /* allocate picParam->slice_group_id */ |
| picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR); |
| if (picParam->slice_group_id == NULL) |
| { |
| return AVCENC_MEMORY_FAIL; |
| } |
| |
| if (extP->slice_group_id == NULL) |
| { |
| return AVCENC_ENCPARAM_MEM_FAIL; |
| } |
| for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++) |
| { |
| picParam->slice_group_id[ii] = extP->slice_group_id[ii]; |
| } |
| break; |
| default: |
| return AVCENC_INVALID_FMO_TYPE; |
| } |
| } |
| picParam->num_ref_idx_l0_active_minus1 = extP->num_ref_idx_l0_active_minus1; |
| picParam->num_ref_idx_l1_active_minus1 = extP->num_ref_idx_l1_active_minus1; /* default value */ |
| if (picParam->num_ref_idx_l1_active_minus1 != 0) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| if (extP->weighted_pred_flag) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| picParam->weighted_pred_flag = 0; /* no weighted prediction supported */ |
| picParam->weighted_bipred_idc = extP->weighted_bipred_idc; /* range 0,1,2 */ |
| if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */ |
| picParam->weighted_bipred_idc > 2) |
| { |
| return AVCENC_WEIGHTED_BIPRED_FAIL; |
| } |
| picParam->pic_init_qp_minus26 = extP->pic_init_qp_minus26; /* default, will be changed at slice level anyway */ |
| if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25) |
| { |
| return AVCENC_INIT_QP_FAIL; /* out of range */ |
| } |
| picParam->pic_init_qs_minus26 = extP->pic_init_qs_minus26; |
| if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25) |
| { |
| return AVCENC_INIT_QS_FAIL; /* out of range */ |
| } |
| |
| picParam->chroma_qp_index_offset = extP->chroma_qp_index_offset; /* default to zero for now */ |
| if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12) |
| { |
| return AVCENC_CHROMA_QP_FAIL; /* out of range */ |
| } |
| /* deblocking */ |
| picParam->deblocking_filter_control_present_flag = extP->deblocking_filter_control_present_flag; |
| /* constrained intra prediction */ |
| picParam->constrained_intra_pred_flag = extP->constrained_intra_pred_flag; |
| if (extP->redundant_pic_cnt_present_flag != 0) |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| picParam->redundant_pic_cnt_present_flag = extP->redundant_pic_cnt_present_flag; /* default */ |
| } |
| else |
| { |
| return AVCENC_NOT_SUPPORTED; |
| } |
| |
| /****************** now set up some SliceHeader parameters ***********/ |
| if (picParam->deblocking_filter_control_present_flag == TRUE) |
| { |
| /* these values only present when db_filter is ON */ |
| if (encParam->disable_db_idc > 2) |
| { |
| return AVCENC_INVALID_DEBLOCK_IDC; /* out of range */ |
| } |
| sliceHdr->disable_deblocking_filter_idc = encParam->disable_db_idc; |
| |
| if (encParam->alpha_offset < -6 || encParam->alpha_offset > 6) |
| { |
| return AVCENC_INVALID_ALPHA_OFFSET; |
| } |
| sliceHdr->slice_alpha_c0_offset_div2 = encParam->alpha_offset; |
| |
| if (encParam->beta_offset < -6 || encParam->beta_offset > 6) |
| { |
| return AVCENC_INVALID_BETA_OFFSET; |
| } |
| sliceHdr->slice_beta_offset_div_2 = encParam->beta_offset; |
| } |
| if (encvid->outOfBandParamSet == TRUE) |
| { |
| sliceHdr->idr_pic_id = 0; |
| } |
| else |
| { |
| sliceHdr->idr_pic_id = (uint)(-1); /* start with zero */ |
| } |
| sliceHdr->field_pic_flag = FALSE; |
| sliceHdr->bottom_field_flag = FALSE; /* won't be used anyway */ |
| video->MbaffFrameFlag = (seqParam->mb_adaptive_frame_field_flag && !sliceHdr->field_pic_flag); |
| |
| /* the rest will be set in InitSlice() */ |
| |
| /* now the rate control and performance related parameters */ |
| rateCtrl->scdEnable = (encParam->auto_scd == AVC_ON) ? TRUE : FALSE; |
| rateCtrl->idrPeriod = encParam->idr_period + 1; |
| rateCtrl->intraMBRate = encParam->intramb_refresh; |
| rateCtrl->dpEnable = (encParam->data_par == AVC_ON) ? TRUE : FALSE; |
| |
| rateCtrl->subPelEnable = (encParam->sub_pel == AVC_ON) ? TRUE : FALSE; |
| rateCtrl->mvRange = encParam->search_range; |
| |
| rateCtrl->subMBEnable = (encParam->submb_pred == AVC_ON) ? TRUE : FALSE; |
| rateCtrl->rdOptEnable = (encParam->rdopt_mode == AVC_ON) ? TRUE : FALSE; |
| rateCtrl->bidirPred = (encParam->bidir_pred == AVC_ON) ? TRUE : FALSE; |
| |
| rateCtrl->rcEnable = (encParam->rate_control == AVC_ON) ? TRUE : FALSE; |
| rateCtrl->initQP = encParam->initQP; |
| rateCtrl->initQP = AVC_CLIP3(0, 51, rateCtrl->initQP); |
| |
| rateCtrl->bitRate = encParam->bitrate; |
| rateCtrl->cpbSize = encParam->CPB_size; |
| rateCtrl->initDelayOffset = (rateCtrl->bitRate * encParam->init_CBP_removal_delay / 1000); |
| |
| if (encParam->frame_rate == 0) |
| { |
| return AVCENC_INVALID_FRAMERATE; |
| } |
| |
| rateCtrl->frame_rate = (OsclFloat)(encParam->frame_rate * 1.0 / 1000); |
| // rateCtrl->srcInterval = encParam->src_interval; |
| rateCtrl->first_frame = 1; /* set this flag for the first time */ |
| |
| /* contrained_setx_flag will be set inside the VerifyProfile called below.*/ |
| if (!extS && !extP) |
| { |
| seqParam->profile_idc = encParam->profile; |
| seqParam->constrained_set0_flag = FALSE; |
| seqParam->constrained_set1_flag = FALSE; |
| seqParam->constrained_set2_flag = FALSE; |
| seqParam->constrained_set3_flag = FALSE; |
| seqParam->level_idc = encParam->level; |
| } |
| else |
| { |
| seqParam->profile_idc = extS->profile_idc; |
| seqParam->constrained_set0_flag = extS->constrained_set0_flag; |
| seqParam->constrained_set1_flag = extS->constrained_set1_flag; |
| seqParam->constrained_set2_flag = extS->constrained_set2_flag; |
| seqParam->constrained_set3_flag = extS->constrained_set3_flag; |
| seqParam->level_idc = extS->level_idc; |
| } |
| |
| |
| status = VerifyProfile(encvid, seqParam, picParam); |
| if (status != AVCENC_SUCCESS) |
| { |
| return status; |
| } |
| |
| status = VerifyLevel(encvid, seqParam, picParam); |
| if (status != AVCENC_SUCCESS) |
| { |
| return status; |
| } |
| |
| return AVCENC_SUCCESS; |
| } |
| |
| /* verify the profile setting */ |
| AVCEnc_Status VerifyProfile(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam) |
| { |
| AVCRateControl *rateCtrl = encvid->rateCtrl; |
| AVCEnc_Status status = AVCENC_SUCCESS; |
| |
| if (seqParam->profile_idc == 0) /* find profile for this setting */ |
| { |
| /* find the right profile for it */ |
| if (seqParam->direct_8x8_inference_flag == TRUE && |
| picParam->entropy_coding_mode_flag == FALSE && |
| picParam->num_slice_groups_minus1 <= 7 /*&& |
| picParam->num_slice_groups_minus1>=0 (no need, it's unsigned) */) |
| { |
| seqParam->profile_idc = AVC_EXTENDED; |
| seqParam->constrained_set2_flag = TRUE; |
| } |
| |
| if (rateCtrl->dpEnable == FALSE && |
| picParam->num_slice_groups_minus1 == 0 && |
| picParam->redundant_pic_cnt_present_flag == FALSE) |
| { |
| seqParam->profile_idc = AVC_MAIN; |
| seqParam->constrained_set1_flag = TRUE; |
| } |
| |
| if (rateCtrl->bidirPred == FALSE && |
| rateCtrl->dpEnable == FALSE && |
| seqParam->frame_mbs_only_flag == TRUE && |
| picParam->weighted_pred_flag == FALSE && |
| picParam->weighted_bipred_idc == 0 && |
| picParam->entropy_coding_mode_flag == FALSE && |
| picParam->num_slice_groups_minus1 <= 7 /*&& |
| picParam->num_slice_groups_minus1>=0 (no need, it's unsigned)*/) |
| { |
| seqParam->profile_idc = AVC_BASELINE; |
| seqParam->constrained_set0_flag = TRUE; |
| } |
| |
| if (seqParam->profile_idc == 0) /* still zero */ |
| { |
| return AVCENC_PROFILE_NOT_SUPPORTED; |
| } |
| } |
| |
| /* check the list of supported profile by this library */ |
| switch (seqParam->profile_idc) |
| { |
| case AVC_BASELINE: |
| if (rateCtrl->bidirPred == TRUE || |
| rateCtrl->dpEnable == TRUE || |
| seqParam->frame_mbs_only_flag != TRUE || |
| picParam->weighted_pred_flag == TRUE || |
| picParam->weighted_bipred_idc != 0 || |
| picParam->entropy_coding_mode_flag == TRUE || |
| picParam->num_slice_groups_minus1 > 7 /*|| |
| picParam->num_slice_groups_minus1<0 (no need, it's unsigned) */) |
| { |
| status = AVCENC_TOOLS_NOT_SUPPORTED; |
| } |
| break; |
| |
| case AVC_MAIN: |
| case AVC_EXTENDED: |
| status = AVCENC_PROFILE_NOT_SUPPORTED; |
| } |
| |
| return status; |
| } |
| |
| /* verify the level setting */ |
| AVCEnc_Status VerifyLevel(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam) |
| { |
| (void)(picParam); |
| |
| AVCRateControl *rateCtrl = encvid->rateCtrl; |
| AVCCommonObj *video = encvid->common; |
| int mb_per_sec, ii; |
| int lev_idx; |
| int dpb_size; |
| |
| mb_per_sec = (int)(video->PicSizeInMbs * rateCtrl->frame_rate + 0.5); |
| dpb_size = (seqParam->num_ref_frames * video->PicSizeInMbs * 3) >> 6; |
| |
| if (seqParam->level_idc == 0) /* find level for this setting */ |
| { |
| for (ii = 0; ii < MAX_LEVEL_IDX; ii++) |
| { |
| if (mb_per_sec <= MaxMBPS[ii] && |
| video->PicSizeInMbs <= (uint)MaxFS[ii] && |
| rateCtrl->bitRate <= (int32)MaxBR[ii]*1000 && |
| rateCtrl->cpbSize <= (int32)MaxCPB[ii]*1000 && |
| rateCtrl->mvRange <= MaxVmvR[ii] && |
| dpb_size <= MaxDPBX2[ii]*512) |
| { |
| seqParam->level_idc = mapIdx2Lev[ii]; |
| break; |
| } |
| } |
| if (seqParam->level_idc == 0) |
| { |
| return AVCENC_LEVEL_NOT_SUPPORTED; |
| } |
| } |
| |
| /* check if this level is supported by this library */ |
| lev_idx = mapLev2Idx[seqParam->level_idc]; |
| if (seqParam->level_idc == AVC_LEVEL1_B) |
| { |
| seqParam->constrained_set3_flag = 1; |
| } |
| |
| |
| if (lev_idx == 255) /* not defined */ |
| { |
| return AVCENC_LEVEL_NOT_SUPPORTED; |
| } |
| |
| /* check if the encoding setting complies with the level */ |
| if (mb_per_sec > MaxMBPS[lev_idx] || |
| video->PicSizeInMbs > (uint)MaxFS[lev_idx] || |
| rateCtrl->bitRate > (int32)MaxBR[lev_idx]*1000 || |
| rateCtrl->cpbSize > (int32)MaxCPB[lev_idx]*1000 || |
| rateCtrl->mvRange > MaxVmvR[lev_idx]) |
| { |
| return AVCENC_LEVEL_FAIL; |
| } |
| |
| return AVCENC_SUCCESS; |
| } |
| |
| /* initialize variables at the beginning of each frame */ |
| /* determine the picture type */ |
| /* encode POC */ |
| /* maybe we should do more stuff here. MotionEstimation+SCD and generate a new SPS and PPS */ |
| AVCEnc_Status InitFrame(AVCEncObject *encvid) |
| { |
| AVCStatus ret; |
| AVCEnc_Status status; |
| AVCCommonObj *video = encvid->common; |
| AVCSliceHeader *sliceHdr = video->sliceHdr; |
| |
| /* look for the next frame in coding_order and look for available picture |
| in the DPB. Note, video->currFS->PicOrderCnt, currFS->FrameNum and currPic->PicNum |
| are set to wrong number in this function (right for decoder). */ |
| if (video->nal_unit_type == AVC_NALTYPE_IDR) |
| { |
| // call init DPB in here. |
| ret = AVCConfigureSequence(encvid->avcHandle, video, TRUE); |
| if (ret != AVC_SUCCESS) |
| { |
| return AVCENC_FAIL; |
| } |
| } |
| |
| /* flexible macroblock ordering (every frame)*/ |
| /* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */ |
| /* It changes once per each PPS. */ |
| FMOInit(video); |
| |
| ret = DPBInitBuffer(encvid->avcHandle, video); // get new buffer |
| |
| if (ret != AVC_SUCCESS) |
| { |
| return (AVCEnc_Status)ret; // AVCENC_PICTURE_READY, FAIL |
| } |
| |
| DPBInitPic(video, 0); /* 0 is dummy */ |
| |
| /************* determine picture type IDR or non-IDR ***********/ |
| video->currPicType = AVC_FRAME; |
| video->slice_data_partitioning = FALSE; |
| encvid->currInput->is_reference = 1; /* default to all frames */ |
| video->nal_ref_idc = 1; /* need to set this for InitPOC */ |
| video->currPic->isReference = TRUE; |
| |
| /************* set frame_num ********************/ |
| if (video->nal_unit_type == AVC_NALTYPE_IDR) |
| { |
| video->prevFrameNum = video->MaxFrameNum; |
| video->PrevRefFrameNum = 0; |
| sliceHdr->frame_num = 0; |
| } |
| /* otherwise, it's set to previous reference frame access unit's frame_num in decoding order, |
| see the end of PVAVCDecodeSlice()*/ |
| /* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */ |
| /* Basically, frame_num can't be repeated unless it's opposite fields or non reference fields */ |
| else |
| { |
| sliceHdr->frame_num = (video->PrevRefFrameNum + 1) % video->MaxFrameNum; |
| } |
| video->CurrPicNum = sliceHdr->frame_num; /* for field_pic_flag = 0 */ |
| //video->CurrPicNum = 2*sliceHdr->frame_num + 1; /* for field_pic_flag = 1 */ |
| |
| /* assign pic_order_cnt, video->PicOrderCnt */ |
| status = InitPOC(encvid); |
| if (status != AVCENC_SUCCESS) /* incorrigable fail */ |
| { |
| return status; |
| } |
| |
| /* Initialize refListIdx for this picture */ |
| RefListInit(video); |
| |
| /************* motion estimation and scene analysis ************/ |
| // , to move this to MB-based MV search for comparison |
| // use sub-optimal QP for mv search |
| AVCMotionEstimation(encvid); /* AVCENC_SUCCESS or AVCENC_NEW_IDR */ |
| |
| /* after this point, the picture type will be fixed to either IDR or non-IDR */ |
| video->currFS->PicOrderCnt = video->PicOrderCnt; |
| video->currFS->FrameNum = video->sliceHdr->frame_num; |
| video->currPic->PicNum = video->CurrPicNum; |
| video->mbNum = 0; /* start from zero MB */ |
| encvid->currSliceGroup = 0; /* start from slice group #0 */ |
| encvid->numIntraMB = 0; /* reset this counter */ |
| |
| if (video->nal_unit_type == AVC_NALTYPE_IDR) |
| { |
| RCInitGOP(encvid); |
| |
| /* calculate picture QP */ |
| RCInitFrameQP(encvid); |
| |
| return AVCENC_NEW_IDR; |
| } |
| |
| /* calculate picture QP */ |
| RCInitFrameQP(encvid); /* get QP after MV search */ |
| |
| return AVCENC_SUCCESS; |
| } |
| |
| /* initialize variables for this slice */ |
| AVCEnc_Status InitSlice(AVCEncObject *encvid) |
| { |
| AVCCommonObj *video = encvid->common; |
| AVCSliceHeader *sliceHdr = video->sliceHdr; |
| AVCPicParamSet *currPPS = video->currPicParams; |
| AVCSeqParamSet *currSPS = video->currSeqParams; |
| int slice_type = video->slice_type; |
| |
| sliceHdr->first_mb_in_slice = video->mbNum; |
| if (video->mbNum) // not first slice of a frame |
| { |
| video->sliceHdr->slice_type = (AVCSliceType)slice_type; |
| } |
| |
| /* sliceHdr->slice_type already set in InitFrame */ |
| |
| sliceHdr->pic_parameter_set_id = video->currPicParams->pic_parameter_set_id; |
| |
| /* sliceHdr->frame_num already set in InitFrame */ |
| |
| if (!currSPS->frame_mbs_only_flag) /* we shouldn't need this check */ |
| { |
| sliceHdr->field_pic_flag = sliceHdr->bottom_field_flag = FALSE; |
| return AVCENC_TOOLS_NOT_SUPPORTED; |
| } |
| |
| /* sliceHdr->idr_pic_id already set in PVAVCEncodeNAL |
| |
| sliceHdr->pic_order_cnt_lsb already set in InitFrame..InitPOC |
| sliceHdr->delta_pic_order_cnt_bottom already set in InitPOC |
| |
| sliceHdr->delta_pic_order_cnt[0] already set in InitPOC |
| sliceHdr->delta_pic_order_cnt[1] already set in InitPOC |
| */ |
| |
| sliceHdr->redundant_pic_cnt = 0; /* default if(currPPS->redundant_pic_cnt_present_flag), range 0..127 */ |
| sliceHdr->direct_spatial_mv_pred_flag = 0; // default if(slice_type == AVC_B_SLICE) |
| |
| sliceHdr->num_ref_idx_active_override_flag = FALSE; /* default, if(slice_type== P,SP or B)*/ |
| sliceHdr->num_ref_idx_l0_active_minus1 = 0; /* default, if (num_ref_idx_active_override_flag) */ |
| sliceHdr->num_ref_idx_l1_active_minus1 = 0; /* default, if above and B_slice */ |
| /* the above 2 values range from 0..15 for frame picture and 0..31 for field picture */ |
| |
| /* ref_pic_list_reordering(), currently we don't do anything */ |
| sliceHdr->ref_pic_list_reordering_flag_l0 = FALSE; /* default */ |
| sliceHdr->ref_pic_list_reordering_flag_l1 = FALSE; /* default */ |
| /* if the above are TRUE, some other params must be set */ |
| |
| if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) || |
| (currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE)) |
| { |
| // pred_weight_table(); // not supported !! |
| return AVCENC_TOOLS_NOT_SUPPORTED; |
| } |
| |
| /* dec_ref_pic_marking(), this will be done later*/ |
| sliceHdr->no_output_of_prior_pics_flag = FALSE; /* default */ |
| sliceHdr->long_term_reference_flag = FALSE; /* for IDR frame, do not make it long term */ |
| sliceHdr->adaptive_ref_pic_marking_mode_flag = FALSE; /* default */ |
| /* other params are not set here because they are not used */ |
| |
| sliceHdr->cabac_init_idc = 0; /* default, if entropy_coding_mode_flag && slice_type==I or SI, range 0..2 */ |
| sliceHdr->slice_qp_delta = 0; /* default for now */ |
| sliceHdr->sp_for_switch_flag = FALSE; /* default, if slice_type == SP */ |
| sliceHdr->slice_qs_delta = 0; /* default, if slice_type == SP or SI */ |
| |
| /* derived variables from encParam */ |
| /* deblocking filter */ |
| video->FilterOffsetA = video->FilterOffsetB = 0; |
| if (currPPS->deblocking_filter_control_present_flag == TRUE) |
| { |
| video->FilterOffsetA = sliceHdr->slice_alpha_c0_offset_div2 << 1; |
| video->FilterOffsetB = sliceHdr->slice_beta_offset_div_2 << 1; |
| } |
| |
| /* flexible macroblock ordering */ |
| /* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */ |
| /* We already call it at the end of PVAVCEncInitialize(). It changes once per each PPS. */ |
| if (video->currPicParams->num_slice_groups_minus1 > 0 && video->currPicParams->slice_group_map_type >= 3 |
| && video->currPicParams->slice_group_map_type <= 5) |
| { |
| sliceHdr->slice_group_change_cycle = SLICE_GROUP_CHANGE_CYCLE; /* default, don't understand how to set it!!!*/ |
| |
| video->MapUnitsInSliceGroup0 = |
| AVC_MIN(sliceHdr->slice_group_change_cycle * video->SliceGroupChangeRate, video->PicSizeInMapUnits); |
| |
| FMOInit(video); |
| } |
| |
| /* calculate SliceQPy first */ |
| /* calculate QSy first */ |
| |
| sliceHdr->slice_qp_delta = video->QPy - 26 - currPPS->pic_init_qp_minus26; |
| //sliceHdr->slice_qs_delta = video->QSy - 26 - currPPS->pic_init_qs_minus26; |
| |
| return AVCENC_SUCCESS; |
| } |
| |