diff options
Diffstat (limited to 'media/libstagefright/codecs/avc/enc/src/rate_control.cpp')
-rw-r--r-- | media/libstagefright/codecs/avc/enc/src/rate_control.cpp | 981 |
1 files changed, 981 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/avc/enc/src/rate_control.cpp b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp new file mode 100644 index 0000000..15b55fb --- /dev/null +++ b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp @@ -0,0 +1,981 @@ +/* ------------------------------------------------------------------ + * 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 <math.h> + +/* rate control variables */ +#define RC_MAX_QUANT 51 +#define RC_MIN_QUANT 0 //cap to 10 to prevent rate fluctuation + +#define MAD_MIN 1 /* handle the case of devision by zero in RC */ + + +/* local functions */ +double QP2Qstep(int QP); +int Qstep2QP(double Qstep); + +double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl); + +void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP); + +void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video, + AVCRateControl *rateCtrl, MultiPass *pMP); + +void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP); + +void AVCSaveRDSamples(MultiPass *pMP, int counter_samples); + +void updateRateControl(AVCRateControl *rateControl, int nal_type); + +int GetAvgFrameQP(AVCRateControl *rateCtrl) +{ + return rateCtrl->Qc; +} + +AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum) +{ + AVCCommonObj *video = encvid->common; + AVCSliceHeader *sliceHdr = video->sliceHdr; + uint32 modTimeRef = encvid->modTimeRef; + int32 currFrameNum ; + int frameInc; + + + /* check with the buffer fullness to make sure that we have enough bits to encode this frame */ + /* we can use a threshold to guarantee minimum picture quality */ + /**********************************/ + + /* for now, the default is to encode every frame, To Be Changed */ + if (rateCtrl->first_frame) + { + encvid->modTimeRef = modTime; + encvid->wrapModTime = 0; + encvid->prevFrameNum = 0; + encvid->prevProcFrameNum = 0; + + *frameNum = 0; + + /* set frame type to IDR-frame */ + video->nal_unit_type = AVC_NALTYPE_IDR; + sliceHdr->slice_type = AVC_I_ALL_SLICE; + video->slice_type = AVC_I_SLICE; + + return AVCENC_SUCCESS; + } + else + { + if (modTime < modTimeRef) /* modTime wrapped around */ + { + encvid->wrapModTime += ((uint32)0xFFFFFFFF - modTimeRef) + 1; + encvid->modTimeRef = modTimeRef = 0; + } + modTime += encvid->wrapModTime; /* wrapModTime is non zero after wrap-around */ + + currFrameNum = (int32)(((modTime - modTimeRef) * rateCtrl->frame_rate + 200) / 1000); /* add small roundings */ + + if (currFrameNum <= (int32)encvid->prevProcFrameNum) + { + return AVCENC_FAIL; /* this is a late frame do not encode it */ + } + + frameInc = currFrameNum - encvid->prevProcFrameNum; + + if (frameInc < rateCtrl->skip_next_frame + 1) + { + return AVCENC_FAIL; /* frame skip required to maintain the target bit rate. */ + } + + RCUpdateBuffer(video, rateCtrl, frameInc - rateCtrl->skip_next_frame); /* in case more frames dropped */ + + *frameNum = currFrameNum; + + /* This part would be similar to DetermineVopType of m4venc */ + if ((*frameNum >= (uint)rateCtrl->idrPeriod && rateCtrl->idrPeriod > 0) || (*frameNum > video->MaxFrameNum)) /* first frame or IDR*/ + { + /* set frame type to IDR-frame */ + if (rateCtrl->idrPeriod) + { + encvid->modTimeRef += (uint32)(rateCtrl->idrPeriod * 1000 / rateCtrl->frame_rate); + *frameNum -= rateCtrl->idrPeriod; + } + else + { + encvid->modTimeRef += (uint32)(video->MaxFrameNum * 1000 / rateCtrl->frame_rate); + *frameNum -= video->MaxFrameNum; + } + + video->nal_unit_type = AVC_NALTYPE_IDR; + sliceHdr->slice_type = AVC_I_ALL_SLICE; + video->slice_type = AVC_I_SLICE; + encvid->prevProcFrameNum = *frameNum; + } + else + { + video->nal_unit_type = AVC_NALTYPE_SLICE; + sliceHdr->slice_type = AVC_P_ALL_SLICE; + video->slice_type = AVC_P_SLICE; + encvid->prevProcFrameNum = currFrameNum; + } + + } + + return AVCENC_SUCCESS; +} + +void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc) +{ + int tmp; + MultiPass *pMP = rateCtrl->pMP; + + OSCL_UNUSED_ARG(video); + + if (rateCtrl->rcEnable == TRUE) + { + if (frameInc > 1) + { + tmp = rateCtrl->bitsPerFrame * (frameInc - 1); + rateCtrl->VBV_fullness -= tmp; + pMP->counter_BTsrc += 10 * (frameInc - 1); + + /* Check buffer underflow */ + if (rateCtrl->VBV_fullness < rateCtrl->low_bound) + { + rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2; + rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound; + pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10)); + } + } + } +} + + +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; + } + 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++) 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 CleanupRateControlModule(AVCHandle *avcHandle) +{ + AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject; + AVCRateControl *rateCtrl = encvid->rateCtrl; + int i; + + if (rateCtrl->MADofMB) + { + avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->MADofMB)); + } + + if (rateCtrl->pMP) + { + if (rateCtrl->pMP->pRDSamples) + { + for (i = 0; i < 30; i++) + { + if (rateCtrl->pMP->pRDSamples[i]) + { + avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples[i]); + } + } + avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples); + } + avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->pMP)); + } + + return ; +} + +void RCInitGOP(AVCEncObject *encvid) +{ + /* in BX RC, there's no GOP-level RC */ + + OSCL_UNUSED_ARG(encvid); + + return ; +} + + +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 ; +} + +/* Mad based variable bit allocation + QP calculation with a new quadratic method */ +void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video, + AVCRateControl *rateCtrl, MultiPass *pMP) +{ + int prev_actual_bits = 0, curr_target, /*pos=0,*/i, j; + OsclFloat Qstep, prev_QP = 0.625; + + OsclFloat curr_mad, prev_mad, curr_RD, prev_RD, average_mad, aver_QP; + + /* Mad based variable bit allocation */ + targetBitCalculation(encvid, video, rateCtrl, pMP); + + if (rateCtrl->T <= 0 || rateCtrl->totalSAD == 0) + { + if (rateCtrl->T < 0) rateCtrl->Qc = RC_MAX_QUANT; + return; + } + + /* ---------------------------------------------------------------------------------------------------*/ + /* current frame QP estimation */ + curr_target = rateCtrl->T; + 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 */ + curr_RD = (OsclFloat)curr_target / curr_mad; + + if (rateCtrl->skip_next_frame == -1) // previous was skipped + { + i = pMP->framePos; + prev_mad = pMP->pRDSamples[i][0].mad; + prev_QP = pMP->pRDSamples[i][0].QP; + prev_actual_bits = pMP->pRDSamples[i][0].actual_bits; + } + else + { + /* Another version of search the optimal point */ + prev_mad = 0.0; + i = 0; + while (i < pMP->frameRange && prev_mad < 0.001) /* find first one with nonzero prev_mad */ + { + prev_mad = pMP->pRDSamples[i][0].mad; + i++; + } + + if (i < pMP->frameRange) + { + prev_actual_bits = pMP->pRDSamples[i-1][0].actual_bits; + + for (j = 0; i < pMP->frameRange; i++) + { + if (pMP->pRDSamples[i][0].mad != 0 && + AVC_ABS(prev_mad - curr_mad) > AVC_ABS(pMP->pRDSamples[i][0].mad - curr_mad)) + { + prev_mad = pMP->pRDSamples[i][0].mad; + prev_actual_bits = pMP->pRDSamples[i][0].actual_bits; + j = i; + } + } + prev_QP = QP2Qstep(pMP->pRDSamples[j][0].QP); + + for (i = 1; i < pMP->samplesPerFrame[j]; i++) + { + if (AVC_ABS(prev_actual_bits - curr_target) > AVC_ABS(pMP->pRDSamples[j][i].actual_bits - curr_target)) + { + prev_actual_bits = pMP->pRDSamples[j][i].actual_bits; + prev_QP = QP2Qstep(pMP->pRDSamples[j][i].QP); + } + } + } + } + + // quadratic approximation + if (prev_mad > 0.001) // only when prev_mad is greater than 0, otherwise keep using the same QP + { + prev_RD = (OsclFloat)prev_actual_bits / prev_mad; + //rateCtrl->Qc = (Int)(prev_QP * sqrt(prev_actual_bits/curr_target) + 0.4); + if (prev_QP == 0.625) // added this to allow getting out of QP = 0 easily + { + Qstep = (int)(prev_RD / curr_RD + 0.5); + } + else + { + // rateCtrl->Qc =(Int)(prev_QP * M4VENC_SQRT(prev_RD/curr_RD) + 0.9); + + if (prev_RD / curr_RD > 0.5 && prev_RD / curr_RD < 2.0) + Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + prev_RD / curr_RD) / 2.0 + 0.9); /* Quadratic and linear approximation */ + else + Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + pow(prev_RD / curr_RD, 1.0 / 3.0)) / 2.0 + 0.9); + } + // lower bound on Qc should be a function of curr_mad + // When mad is already low, lower bound on Qc doesn't have to be small. + // Note, this doesn't work well for low complexity clip encoded at high bit rate + // it doesn't hit the target bit rate due to this QP lower bound. + /// if((curr_mad < 8) && (rateCtrl->Qc < 12)) rateCtrl->Qc = 12; + // else if((curr_mad < 128) && (rateCtrl->Qc < 3)) rateCtrl->Qc = 3; + + rateCtrl->Qc = Qstep2QP(Qstep); + + if (rateCtrl->Qc < RC_MIN_QUANT) rateCtrl->Qc = RC_MIN_QUANT; + if (rateCtrl->Qc > RC_MAX_QUANT) rateCtrl->Qc = RC_MAX_QUANT; + } + + /* active bit resource protection */ + aver_QP = (pMP->encoded_frames == 0 ? 0 : pMP->sum_QP / (OsclFloat)pMP->encoded_frames); + average_mad = (pMP->encoded_frames == 0 ? 0 : pMP->sum_mad / (OsclFloat)pMP->encoded_frames); /* this function is called from the scond encoded frame*/ + if (pMP->diff_counter == 0 && + ((OsclFloat)rateCtrl->Qc <= aver_QP*1.1 || curr_mad <= average_mad*1.1) && + pMP->counter_BTsrc <= (pMP->counter_BTdst + (int)(pMP->framerate*1.0 + 0.5))) + { + rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame / 10.0); + rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W; + pMP->counter_BTsrc++; + pMP->diff_counter--; + } + +} + +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)(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)(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)(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)(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 ; +} + +void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP) +{ + if (rateCtrl->skip_next_frame > 0) /* skip next frame */ + { + pMP->counter_BTsrc += 10 * rateCtrl->skip_next_frame; + + } + else if (rateCtrl->skip_next_frame == -1) /* skip current frame */ + { + pMP->counter_BTdst -= pMP->diff_counter; + pMP->counter_BTsrc += 10; + + pMP->sum_mad -= pMP->mad; + pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames - pMP->mad) / (pMP->encoded_frames - 1 + 0.0001); + pMP->sum_QP -= pMP->QP; + pMP->encoded_frames --; + } + /* some stuff in update VBV_fullness remains here */ + //if(rateCtrl->VBV_fullness < -rateCtrl->Bs/2) /* rateCtrl->Bs */ + if (rateCtrl->VBV_fullness < rateCtrl->low_bound) + { + rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2; + rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound; + pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10)); + } +} + + +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 ; +} + + +void RCInitMBQP(AVCEncObject *encvid) +{ + AVCCommonObj *video = encvid->common; + AVCMacroblock *currMB = video->currMB; + + currMB->QPy = video->QPy; /* set to previous value or picture level */ + + RCInitChromaQP(encvid); + +} + +void RCPostMB(AVCCommonObj *video, AVCRateControl *rateCtrl, int num_header_bits, int num_texture_bits) +{ + OSCL_UNUSED_ARG(video); + rateCtrl->numMBHeaderBits = num_header_bits; + rateCtrl->numMBTextureBits = num_texture_bits; + rateCtrl->NumberofHeaderBits += rateCtrl->numMBHeaderBits; + rateCtrl->NumberofTextureBits += rateCtrl->numMBTextureBits; +} + +void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid) +{ + currMB->QPy = video->QPy; /* use previous QP */ + RCInitChromaQP(encvid); + + return ; +} + + +void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch) +{ + AVCCommonObj *video = encvid->common; + AVCRateControl *rateCtrl = encvid->rateCtrl; + uint32 dmin_lx; + + if (rateCtrl->rcEnable == TRUE) + { + if (currMB->mb_intra) + { + if (currMB->mbMode == AVC_I16) + { + dmin_lx = (0xFFFF << 16) | orgPitch; + rateCtrl->MADofMB[video->mbNum] = AVCSAD_Macroblock_C(orgL, + encvid->pred_i16[currMB->i16Mode], dmin_lx, NULL); + } + else /* i4 */ + { + rateCtrl->MADofMB[video->mbNum] = encvid->i4_sad / 256.; + } + } + /* for INTER, we have already saved it with the MV search */ + } + + return ; +} + + + +AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid) +{ + AVCCommonObj *video = encvid->common; + AVCRateControl *rateCtrl = encvid->rateCtrl; + AVCEnc_Status status = AVCENC_SUCCESS; + MultiPass *pMP = rateCtrl->pMP; + int diff_BTCounter; + int nal_type = video->nal_unit_type; + + /* update the complexity weight of I, P, B frame */ + + if (rateCtrl->rcEnable == TRUE) + { + pMP->actual_bits = rateCtrl->numFrameBits; + pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl); + + AVCSaveRDSamples(pMP, 0); + + pMP->encoded_frames++; + + /* for pMP->samplesPerFrame */ + pMP->samplesPerFrame[pMP->framePos] = 0; + + pMP->sum_QP += pMP->QP; + + /* update pMP->counter_BTsrc, pMP->counter_BTdst */ + /* re-allocate the target bit again and then stop encoding */ + diff_BTCounter = (int)((OsclFloat)(rateCtrl->TMN_TH - rateCtrl->TMN_W - pMP->actual_bits) / + (pMP->bitrate / (pMP->framerate + 0.0001) + 0.0001) / 0.1); + if (diff_BTCounter >= 0) + pMP->counter_BTsrc += diff_BTCounter; /* pMP->actual_bits is smaller */ + else + pMP->counter_BTdst -= diff_BTCounter; /* pMP->actual_bits is bigger */ + + rateCtrl->TMN_TH -= (int)((OsclFloat)pMP->bitrate / (pMP->framerate + 0.0001) * (diff_BTCounter * 0.1)); + rateCtrl->T = pMP->target_bits = rateCtrl->TMN_TH - rateCtrl->TMN_W; + pMP->diff_counter -= diff_BTCounter; + + rateCtrl->Rc = rateCtrl->numFrameBits; /* Total Bits for current frame */ + rateCtrl->Hc = rateCtrl->NumberofHeaderBits; /* Total Bits in Header and Motion Vector */ + + /* BX_RC */ + updateRateControl(rateCtrl, nal_type); + if (rateCtrl->skip_next_frame == -1) // skip current frame + { + status = AVCENC_SKIPPED_PICTURE; + } + } + + rateCtrl->first_frame = 0; // reset here after we encode the first frame. + + return status; +} + +void AVCSaveRDSamples(MultiPass *pMP, int counter_samples) +{ + /* for pMP->pRDSamples */ + pMP->pRDSamples[pMP->framePos][counter_samples].QP = pMP->QP; + pMP->pRDSamples[pMP->framePos][counter_samples].actual_bits = pMP->actual_bits; + pMP->pRDSamples[pMP->framePos][counter_samples].mad = pMP->mad; + pMP->pRDSamples[pMP->framePos][counter_samples].R_D = (OsclFloat)pMP->actual_bits / (pMP->mad + 0.0001); + + return ; +} + +void updateRateControl(AVCRateControl *rateCtrl, int nal_type) +{ + int frame_bits; + MultiPass *pMP = rateCtrl->pMP; + + /* BX rate contro\l */ + frame_bits = (int)(rateCtrl->bitRate / rateCtrl->frame_rate); + rateCtrl->TMN_W += (rateCtrl->Rc - rateCtrl->TMN_TH); + rateCtrl->VBV_fullness += (rateCtrl->Rc - frame_bits); //rateCtrl->Rp); + //if(rateCtrl->VBV_fullness < 0) rateCtrl->VBV_fullness = -1; + + rateCtrl->encoded_frames++; + + /* frame dropping */ + rateCtrl->skip_next_frame = 0; + + if ((rateCtrl->VBV_fullness > rateCtrl->Bs / 2) && nal_type != AVC_NALTYPE_IDR) /* skip the current frame */ /* rateCtrl->Bs */ + { + rateCtrl->TMN_W -= (rateCtrl->Rc - rateCtrl->TMN_TH); + rateCtrl->VBV_fullness -= rateCtrl->Rc; + rateCtrl->skip_next_frame = -1; + } + else if ((OsclFloat)(rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95) /* skip next frame */ + { + rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp; + rateCtrl->skip_next_frame = 1; + pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10)); + /* BX_1, skip more than 1 frames */ + //while(rateCtrl->VBV_fullness > rateCtrl->Bs*0.475) + while ((rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95) + { + rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp; + rateCtrl->skip_next_frame++; + pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10)); + } + + /* END BX_1 */ + } +} + + +double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl) +{ + double TotalMAD; + int i; + TotalMAD = 0.0; + for (i = 0; i < (int)video->PicSizeInMbs; i++) + TotalMAD += rateCtrl->MADofMB[i]; + TotalMAD /= video->PicSizeInMbs; + return TotalMAD; +} + + + + + +/* convert from QP to Qstep */ +double QP2Qstep(int QP) +{ + int i; + double Qstep; + static const double QP2QSTEP[6] = { 0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125 }; + + Qstep = QP2QSTEP[QP % 6]; + for (i = 0; i < (QP / 6); i++) + Qstep *= 2; + + return Qstep; +} + +/* convert from step size to QP */ +int Qstep2QP(double Qstep) +{ + int q_per = 0, q_rem = 0; + + // assert( Qstep >= QP2Qstep(0) && Qstep <= QP2Qstep(51) ); + if (Qstep < QP2Qstep(0)) + return 0; + else if (Qstep > QP2Qstep(51)) + return 51; + + while (Qstep > QP2Qstep(5)) + { + Qstep /= 2; + q_per += 1; + } + + if (Qstep <= (0.625 + 0.6875) / 2) + { + Qstep = 0.625; + q_rem = 0; + } + else if (Qstep <= (0.6875 + 0.8125) / 2) + { + Qstep = 0.6875; + q_rem = 1; + } + else if (Qstep <= (0.8125 + 0.875) / 2) + { + Qstep = 0.8125; + q_rem = 2; + } + else if (Qstep <= (0.875 + 1.0) / 2) + { + Qstep = 0.875; + q_rem = 3; + } + else if (Qstep <= (1.0 + 1.125) / 2) + { + Qstep = 1.0; + q_rem = 4; + } + else + { + Qstep = 1.125; + q_rem = 5; + } + + return (q_per * 6 + q_rem); +} + + + |