void RCUpdateParams(AVCRateControl *rateCtrl, AVCEncObject *encvid) { int32 prevFrameNum, newFrameNum; uint32 prevModTime; if (rateCtrl->frame_rate != rateCtrl->pMP->framerate) { /* this part for frame rate change */ rateCtrl->pMP->frameRange = (int)(rateCtrl->frame_rate * 1.0); /* 1.0s time frame*/ rateCtrl->pMP->frameRange = AVC_MAX(rateCtrl->pMP->frameRange, 5); rateCtrl->pMP->frameRange = AVC_MIN(rateCtrl->pMP->frameRange, 30); prevFrameNum = encvid->prevProcFrameNum; // previous frame number // convert from frame num to time based on the previous frame rate prevModTime = (uint32)(prevFrameNum * 1000 / rateCtrl->pMP->framerate); // offseted by modTimeRef // convert back from time to frame num based on new frame rate newFrameNum = (int32)((prevModTime * rateCtrl->frame_rate) / 1000); // assign the newFrameNum to prevFrameNum // note, this will cause the IDR frame to come earlier and later than expected !! encvid->prevProcFrameNum = newFrameNum; } // recalculate fixed values that are dependent on bitrate and framerate rateCtrl->bitsPerFrame = (int32)(rateCtrl->bitRate / rateCtrl->frame_rate); rateCtrl->max_BitVariance_num = (int)((OsclFloat)(rateCtrl->Bs - rateCtrl->VBV_fullness) / (rateCtrl->bitsPerFrame / 10.0)) - 5; if (rateCtrl->max_BitVariance_num < 0) rateCtrl->max_BitVariance_num += 5; /* no change to rateCtrl->cpbSize, rateCtrl->Bs, rateCtrl->low_bound, rateCtrl->VBV_fullness_offset*/ /* keep continuity to the following values */ /* rateCtrl->pMP->framePos, rateCtrl->TMN_TH, rateCtrl->TMN_W */ /* rateCtrl->VBV_fullness, rateCtrl->pMP->counter_BTsrc, */ /* reset some stats for CalculateQuantizerMultiPass and active bit resource protection */ rateCtrl->pMP->sum_QP /= rateCtrl->pMP->encoded_frames; // reset it to 1 rateCtrl->pMP->encoded_frames = 1; rateCtrl->pMP->sum_mad = 0; rateCtrl->T = 0; /* Finalizing bitrate and framerate to pMP structure*/ rateCtrl->pMP->bitrate = rateCtrl->bitRate; rateCtrl->pMP->framerate = rateCtrl->frame_rate; rateCtrl->pMP->target_bits_per_frame = rateCtrl->pMP->bitrate / rateCtrl->pMP->framerate; return ; }
void RCInitChromaQP(AVCEncObject *encvid) { AVCCommonObj *video = encvid->common; AVCMacroblock *currMB = video->currMB; int q_bits; /* we have to do the same thing for AVC_CLIP3(0,51,video->QSy) */ video->QPy_div_6 = (currMB->QPy * 43) >> 8; video->QPy_mod_6 = currMB->QPy - 6 * video->QPy_div_6; currMB->QPc = video->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, currMB->QPy + video->currPicParams->chroma_qp_index_offset)]; video->QPc_div_6 = (video->QPc * 43) >> 8; video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6; /* pre-calculate this to save computation */ q_bits = 4 + video->QPy_div_6; if (video->slice_type == AVC_I_SLICE) { encvid->qp_const = 682 << q_bits; // intra } else { encvid->qp_const = 342 << q_bits; // inter } q_bits = 4 + video->QPc_div_6; if (video->slice_type == AVC_I_SLICE) { encvid->qp_const_c = 682 << q_bits; // intra } else { encvid->qp_const_c = 342 << q_bits; // inter } encvid->lambda_mode = QP2QUANT[AVC_MAX(0, currMB->QPy-SHIFT_QP)]; encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode); return ; }
AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle) { AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject; AVCCommonObj *video = encvid->common; AVCRateControl *rateCtrl = encvid->rateCtrl; double L1, L2, L3, bpp; int qp; int i, j; rateCtrl->basicUnit = video->PicSizeInMbs; rateCtrl->MADofMB = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, video->PicSizeInMbs * sizeof(double), DEFAULT_ATTR); if (!rateCtrl->MADofMB) { goto CLEANUP_RC; } if (rateCtrl->rcEnable == TRUE) { rateCtrl->pMP = (MultiPass*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, sizeof(MultiPass), DEFAULT_ATTR); if (!rateCtrl->pMP) { goto CLEANUP_RC; } oscl_memset(rateCtrl->pMP, 0, sizeof(MultiPass)); rateCtrl->pMP->encoded_frames = -1; /* forget about the very first I frame */ /* RDInfo **pRDSamples */ rateCtrl->pMP->pRDSamples = (RDInfo **)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (30 * sizeof(RDInfo *)), DEFAULT_ATTR); if (!rateCtrl->pMP->pRDSamples) { goto CLEANUP_RC; } for (i = 0; i < 30; i++) { rateCtrl->pMP->pRDSamples[i] = (RDInfo *)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (32 * sizeof(RDInfo)), DEFAULT_ATTR); if (!rateCtrl->pMP->pRDSamples[i]) { goto CLEANUP_RC; } for (j = 0; j < 32; j++) oscl_memset(&(rateCtrl->pMP->pRDSamples[i][j]), 0, sizeof(RDInfo)); } rateCtrl->pMP->frameRange = (int)(rateCtrl->frame_rate * 1.0); /* 1.0s time frame*/ rateCtrl->pMP->frameRange = AVC_MAX(rateCtrl->pMP->frameRange, 5); rateCtrl->pMP->frameRange = AVC_MIN(rateCtrl->pMP->frameRange, 30); rateCtrl->pMP->framePos = -1; rateCtrl->bitsPerFrame = (int32)(rateCtrl->bitRate / rateCtrl->frame_rate); /* BX rate control */ rateCtrl->skip_next_frame = 0; /* must be initialized */ rateCtrl->Bs = rateCtrl->cpbSize; rateCtrl->TMN_W = 0; rateCtrl->VBV_fullness = (int)(rateCtrl->Bs * 0.5); /* rateCtrl->Bs */ rateCtrl->encoded_frames = 0; rateCtrl->TMN_TH = rateCtrl->bitsPerFrame; rateCtrl->max_BitVariance_num = (int)((OsclFloat)(rateCtrl->Bs - rateCtrl->VBV_fullness) / (rateCtrl->bitsPerFrame / 10.0)) - 5; if (rateCtrl->max_BitVariance_num < 0) rateCtrl->max_BitVariance_num += 5; // Set the initial buffer fullness /* According to the spec, the initial buffer fullness needs to be set to 1/3 */ rateCtrl->VBV_fullness = (int)(rateCtrl->Bs / 3.0 - rateCtrl->Bs / 2.0); /* the buffer range is [-Bs/2, Bs/2] */ rateCtrl->pMP->counter_BTsrc = (int)((rateCtrl->Bs / 2.0 - rateCtrl->Bs / 3.0) / (rateCtrl->bitsPerFrame / 10.0)); rateCtrl->TMN_W = (int)(rateCtrl->VBV_fullness + rateCtrl->pMP->counter_BTsrc * (rateCtrl->bitsPerFrame / 10.0)); rateCtrl->low_bound = -rateCtrl->Bs / 2; rateCtrl->VBV_fullness_offset = 0; /* Setting the bitrate and framerate */ rateCtrl->pMP->bitrate = rateCtrl->bitRate; rateCtrl->pMP->framerate = rateCtrl->frame_rate; rateCtrl->pMP->target_bits_per_frame = rateCtrl->pMP->bitrate / rateCtrl->pMP->framerate; /*compute the initial QP*/ bpp = 1.0 * rateCtrl->bitRate / (rateCtrl->frame_rate * (video->PicSizeInMbs << 8)); if (video->PicWidthInSamplesL == 176) { L1 = 0.1; L2 = 0.3; L3 = 0.6; } else if (video->PicWidthInSamplesL == 352) { L1 = 0.2; L2 = 0.6; L3 = 1.2; } else { L1 = 0.6; L2 = 1.4; L3 = 2.4; } if (rateCtrl->initQP == 0) { if (bpp <= L1) qp = 35; else if (bpp <= L2) qp = 25; else if (bpp <= L3) qp = 20; else qp = 15; rateCtrl->initQP = qp; } rateCtrl->Qc = rateCtrl->initQP; } return AVCENC_SUCCESS; CLEANUP_RC: CleanupRateControlModule(avcHandle); return AVCENC_MEMORY_FAIL; }
void RCInitFrameQP(AVCEncObject *encvid) { AVCCommonObj *video = encvid->common; AVCRateControl *rateCtrl = encvid->rateCtrl; AVCPicParamSet *picParam = video->currPicParams; MultiPass *pMP = rateCtrl->pMP; if (rateCtrl->rcEnable == TRUE) { /* frame layer rate control */ if (rateCtrl->encoded_frames == 0) { video->QPy = rateCtrl->Qc = rateCtrl->initQP; } else { calculateQuantizer_Multipass(encvid, video, rateCtrl, pMP); video->QPy = rateCtrl->Qc; } rateCtrl->NumberofHeaderBits = 0; rateCtrl->NumberofTextureBits = 0; rateCtrl->numFrameBits = 0; // reset /* update pMP->framePos */ if (++pMP->framePos == pMP->frameRange) pMP->framePos = 0; if (rateCtrl->T == 0) { pMP->counter_BTdst = (int)(rateCtrl->frame_rate * 7.5 + 0.5); /* 0.75s time frame */ pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, (int)(rateCtrl->max_BitVariance_num / 2 * 0.40)); /* 0.75s time frame may go beyond VBV buffer if we set the buffer size smaller than 0.75s */ pMP->counter_BTdst = AVC_MAX(pMP->counter_BTdst, (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.30 / (rateCtrl->TMN_TH / 10.0) + 0.5)); /* At least 30% of VBV buffer size/2 */ pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, 20); /* Limit the target to be smaller than 3C */ pMP->target_bits = rateCtrl->T = rateCtrl->TMN_TH = (int)(rateCtrl->TMN_TH * (1.0 + pMP->counter_BTdst * 0.1)); pMP->diff_counter = pMP->counter_BTdst; } /* collect the necessary data: target bits, actual bits, mad and QP */ pMP->target_bits = rateCtrl->T; pMP->QP = video->QPy; pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl); if (pMP->mad < MAD_MIN) pMP->mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */ pMP->bitrate = rateCtrl->bitRate; /* calculated in RCVopQPSetting */ pMP->framerate = rateCtrl->frame_rate; /* first pass encoding */ pMP->nRe_Quantized = 0; } // rcEnable else { video->QPy = rateCtrl->initQP; } // printf(" %d ",video->QPy); if (video->CurrPicNum == 0 && encvid->outOfBandParamSet == FALSE) { picParam->pic_init_qs_minus26 = 0; picParam->pic_init_qp_minus26 = video->QPy - 26; } // need this for motion estimation encvid->lambda_mode = QP2QUANT[AVC_MAX(0, video->QPy-SHIFT_QP)]; encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode); return ; }
/* follow the text rather than the JM, it's quite different. */ void FmoGenerateType3MapUnitMap(AVCCommonObj *video, AVCPicParamSet* pps, int *mapUnitToSliceGroupMap, int PicWidthInMbs) { uint i, k; int leftBound, topBound, rightBound, bottomBound; int x, y, xDir, yDir; int mapUnitVacant; uint PicSizeInMapUnits = video->PicSizeInMapUnits; uint MapUnitsInSliceGroup0 = video->MapUnitsInSliceGroup0; for (i = 0; i < PicSizeInMapUnits; i++) { mapUnitToSliceGroupMap[ i ] = 1; } x = (PicWidthInMbs - pps->slice_group_change_direction_flag) / 2; y = (video->PicHeightInMapUnits - pps->slice_group_change_direction_flag) / 2; leftBound = x; topBound = y; rightBound = x; bottomBound = y; xDir = pps->slice_group_change_direction_flag - 1; yDir = pps->slice_group_change_direction_flag; for (k = 0; k < MapUnitsInSliceGroup0; k += mapUnitVacant) { mapUnitVacant = (mapUnitToSliceGroupMap[ y * PicWidthInMbs + x ] == 1); if (mapUnitVacant) { mapUnitToSliceGroupMap[ y * PicWidthInMbs + x ] = 0; } if (xDir == -1 && x == leftBound) { leftBound = AVC_MAX(leftBound - 1, 0); x = leftBound; xDir = 0; yDir = 2 * pps->slice_group_change_direction_flag - 1; } else if (xDir == 1 && x == rightBound) { rightBound = AVC_MIN(rightBound + 1, (int)PicWidthInMbs - 1); x = rightBound; xDir = 0; yDir = 1 - 2 * pps->slice_group_change_direction_flag; } else if (yDir == -1 && y == topBound) { topBound = AVC_MAX(topBound - 1, 0); y = topBound; xDir = 1 - 2 * pps->slice_group_change_direction_flag; yDir = 0; } else if (yDir == 1 && y == bottomBound) { bottomBound = AVC_MIN(bottomBound + 1, (int)video->PicHeightInMapUnits - 1); y = bottomBound; xDir = 2 * pps->slice_group_change_direction_flag - 1; yDir = 0; } else { x = x + xDir; y = y + yDir; } } }