/* ------------------------------------------------------------------ * 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; }