blob: 6e1413ad5007f4880a2f0c2ce896e3d0460a4952 [file] [log] [blame]
/* ------------------------------------------------------------------
* 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;
}