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 targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP) { OSCL_UNUSED_ARG(encvid); OsclFloat curr_mad;//, average_mad; int diff_counter_BTsrc, diff_counter_BTdst, prev_counter_diff, curr_counter_diff, bound; /* BT = Bit Transfer, for pMP->counter_BTsrc, pMP->counter_BTdst */ /* some stuff about frame dropping remained here to be done because pMP cannot be inserted into updateRateControl()*/ updateRC_PostProc(rateCtrl, pMP); /* update pMP->counter_BTsrc and pMP->counter_BTdst to avoid interger overflow */ if (pMP->counter_BTsrc > 1000 && pMP->counter_BTdst > 1000) { pMP->counter_BTsrc -= 1000; pMP->counter_BTdst -= 1000; } /* ---------------------------------------------------------------------------------------------------*/ /* target calculation */ curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */ diff_counter_BTsrc = diff_counter_BTdst = 0; pMP->diff_counter = 0; /*1.calculate average mad */ pMP->sum_mad += curr_mad; //average_mad = (pMP->encoded_frames < 1 ? curr_mad : pMP->sum_mad/(OsclFloat)(pMP->encoded_frames+1)); /* this function is called from the scond encoded frame*/ //pMP->aver_mad = average_mad; if (pMP->encoded_frames >= 0) /* pMP->encoded_frames is set to -1 initially, so forget about the very first I frame */ pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames + curr_mad) / (pMP->encoded_frames + 1); if (pMP->overlapped_win_size > 0 && pMP->encoded_frames_prev >= 0) pMP->aver_mad_prev = (pMP->aver_mad_prev * pMP->encoded_frames_prev + curr_mad) / (pMP->encoded_frames_prev + 1); /*2.average_mad, mad ==> diff_counter_BTsrc, diff_counter_BTdst */ if (pMP->overlapped_win_size == 0) { /* original verison */ if (curr_mad > pMP->aver_mad*1.1) { if (curr_mad / (pMP->aver_mad + 0.0001) > 2) diff_counter_BTdst = (int)(oscl_sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.4) - 10; //diff_counter_BTdst = (int)((sqrt(curr_mad/pMP->aver_mad)*2+curr_mad/pMP->aver_mad)/(3*0.1) + 0.4) - 10; else diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad + 0.0001) * 10 + 0.4) - 10; } else /* curr_mad <= average_mad*1.1 */ //diff_counter_BTsrc = 10 - (int)((sqrt(curr_mad/pMP->aver_mad) + pow(curr_mad/pMP->aver_mad, 1.0/3.0))/(2.0*0.1) + 0.4); diff_counter_BTsrc = 10 - (int)(oscl_sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.5); /* actively fill in the possible gap */ if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 && curr_mad <= pMP->aver_mad*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst) diff_counter_BTsrc = 1; } else if (pMP->overlapped_win_size > 0) { /* transition time: use previous average mad "pMP->aver_mad_prev" instead of the current average mad "pMP->aver_mad" */ if (curr_mad > pMP->aver_mad_prev*1.1) { if (curr_mad / pMP->aver_mad_prev > 2) diff_counter_BTdst = (int)(oscl_sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.4) - 10; //diff_counter_BTdst = (int)((M4VENC_SQRT(curr_mad/pMP->aver_mad_prev)*2+curr_mad/pMP->aver_mad_prev)/(3*0.1) + 0.4) - 10; else diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad_prev + 0.0001) * 10 + 0.4) - 10; } else /* curr_mad <= average_mad*1.1 */ //diff_counter_BTsrc = 10 - (Int)((sqrt(curr_mad/pMP->aver_mad_prev) + pow(curr_mad/pMP->aver_mad_prev, 1.0/3.0))/(2.0*0.1) + 0.4); diff_counter_BTsrc = 10 - (int)(oscl_sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.5); /* actively fill in the possible gap */ if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 && curr_mad <= pMP->aver_mad_prev*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst) diff_counter_BTsrc = 1; if (--pMP->overlapped_win_size <= 0) pMP->overlapped_win_size = 0; } /* if difference is too much, do clipping */ /* First, set the upper bound for current bit allocation variance: 80% of available buffer */ bound = (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.6 / (pMP->target_bits_per_frame / 10)); /* rateCtrl->Bs */ diff_counter_BTsrc = AVC_MIN(diff_counter_BTsrc, bound); diff_counter_BTdst = AVC_MIN(diff_counter_BTdst, bound); /* Second, set another upper bound for current bit allocation: 4-5*bitrate/framerate */ bound = 50; // if(video->encParams->RC_Type == CBR_LOWDELAY) // not necessary bound = 10; -- For Low delay */ diff_counter_BTsrc = AVC_MIN(diff_counter_BTsrc, bound); diff_counter_BTdst = AVC_MIN(diff_counter_BTdst, bound); /* Third, check the buffer */ prev_counter_diff = pMP->counter_BTdst - pMP->counter_BTsrc; curr_counter_diff = prev_counter_diff + (diff_counter_BTdst - diff_counter_BTsrc); if (AVC_ABS(prev_counter_diff) >= rateCtrl->max_BitVariance_num || AVC_ABS(curr_counter_diff) >= rateCtrl->max_BitVariance_num) { //diff_counter_BTsrc = diff_counter_BTdst = 0; if (curr_counter_diff > rateCtrl->max_BitVariance_num && diff_counter_BTdst) { diff_counter_BTdst = (rateCtrl->max_BitVariance_num - prev_counter_diff) + diff_counter_BTsrc; if (diff_counter_BTdst < 0) diff_counter_BTdst = 0; } else if (curr_counter_diff < -rateCtrl->max_BitVariance_num && diff_counter_BTsrc) { diff_counter_BTsrc = diff_counter_BTdst - (-rateCtrl->max_BitVariance_num - prev_counter_diff); if (diff_counter_BTsrc < 0) diff_counter_BTsrc = 0; } } /*3.diff_counter_BTsrc, diff_counter_BTdst ==> TMN_TH */ rateCtrl->TMN_TH = (int)(pMP->target_bits_per_frame); pMP->diff_counter = 0; if (diff_counter_BTsrc) { rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame * diff_counter_BTsrc * 0.1); pMP->diff_counter = -diff_counter_BTsrc; } else if (diff_counter_BTdst) { rateCtrl->TMN_TH += (int)(pMP->target_bits_per_frame * diff_counter_BTdst * 0.1); pMP->diff_counter = diff_counter_BTdst; } /*4.update pMP->counter_BTsrc, pMP->counter_BTdst */ pMP->counter_BTsrc += diff_counter_BTsrc; pMP->counter_BTdst += diff_counter_BTdst; /*5.target bit calculation */ rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W; 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; } } }