⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp4_enc_rc.cpp

📁 audio-video-codecs.rar语音编解码器
💻 CPP
字号:
/*
//
//               INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//      Copyright (c) 2007 Intel Corporation. All Rights Reserved.
//
//  Purpose
//    bitrate control
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_MPEG4_VIDEO_ENCODER)

#include <math.h>
#include "mp4_enc.hpp"

namespace MPEG4_ENC
{

MPEG4_RC::MPEG4_RC()
{
    ippsZero_8u((Ipp8u*)this, sizeof(MPEG4_RC));
}


MPEG4_RC::~MPEG4_RC()
{
    Close();
}


void MPEG4_RC::Close()
{
    mIsInit = false;
}


Ipp32s MPEG4_RC::GetInitQP(Ipp32s frameWidth, Ipp32s frameHeight)
{
    Ipp32s q = (Ipp32s)(frameWidth * frameHeight / mBitsDesiredFrame * 3 >> 2);
    mp4_ClipL(q, 2);
    mp4_Clip(q, mQuantMin, mQuantMax);
    return q;
}


#define SetQuantB() \
    mQuantB = (((mQuantP + mQuantPrev) * 1229) >> 11) + 1; \
    mp4_Clip(mQuantB, 2, 31)


void MPEG4_RC::Init(Ipp32s qas, Ipp32s fas, Ipp32s bas, Ipp32s bitRate, Ipp64f frameRate, Ipp32s frameWidth, Ipp32s frameHeight, Ipp32s qMin, Ipp32s qMax)
{
    if (mIsInit)
        Close();
    mMethod = 1;
    if (qas <= 0)
        qas = 100;
    if (fas <= 0)
        fas = 10;
    if (bas <= 0)
        bas = 100;
    mQuantMax = qMax;
    mQuantMin = qMin;
    mBitRate = bitRate;
    mBitsDesiredTotal = 0;
    mBitsEncodedTotal = 0;
    mBitsDesiredFrame = (Ipp32s)(mBitRate / frameRate);
    Ipp32s q = GetInitQP(frameWidth, frameHeight);
    mQuantPrev = mQuantI = mQuantP = q;
    SetQuantB();
    mRCfap = fas;
    mRCqap = qas;
    mRCbap = bas;
    mRCq = q;
    mRCqa = 1. / (Ipp64f)mRCq;
    mRCfa = mBitsDesiredFrame;
    mIsInit = true;
    //mRCqh = -1; mRCqs = 0; mRCbf = 0;
}


void MPEG4_RC::PostFrame(Ipp32s frameType, Ipp64s bEncoded)
{
    Ipp64f  bo, qs, dq;
    Ipp32s  quant, bpfEncoded;

    bpfEncoded = (Ipp32s)(bEncoded - mBitsEncodedTotal);
    mBitsEncodedTotal = bEncoded;
    mBitsDesiredTotal += mBitsDesiredFrame;
    quant = (frameType == MP4_VOP_TYPE_I) ? mQuantI : (frameType == MP4_VOP_TYPE_B) ? mQuantB : mQuantP;
    mRCqa += (1. / quant - mRCqa) / mRCqap;
    mp4_Clip(mRCqa, 1./mQuantMax , 1./mQuantMin);
    if (frameType != MP4_VOP_TYPE_I/* || mRCfap < 30*/)
        mRCfa += (bpfEncoded - mRCfa) / mRCfap;
    SetQuantB();
    if (frameType == MP4_VOP_TYPE_B)
        return;
    qs = pow(mBitsDesiredFrame / mRCfa, 1.5);
    dq = mRCqa * qs;
    bo = (Ipp64f)((Ipp64s)mBitsEncodedTotal - (Ipp64s)mBitsDesiredTotal) / mRCbap / mBitsDesiredFrame;
    mp4_Clip(bo, -1.0, 1.0);
    //dq = dq * (1.0 - bo);
    dq = dq + (1./31 - dq) * bo;
    mp4_ClipL(dq, 1./31.);
    if (bo > -0.05) {
        mp4_ClipR(dq, 1./2.);
    } else {
        mp4_ClipR(dq, 1./1.);
    }
    quant = (int) (1. / dq + 0.5);
    if (quant >= mRCq + 3)
         quant = mRCq + 2;
    else if (quant > mRCq + 1)
        quant = mRCq + 1;
    else if (quant <= mRCq - 3)
        quant = mRCq - 2;
    else if (quant < mRCq - 1)
        quant = mRCq - 1;
    mp4_Clip(quant, mQuantMin, mQuantMax);
    mQuantPrev = mQuantP;
    mRCq = mQuantI = mQuantP = quant;
#if 0
#define RCBS 32
    int    bpfExpected, delay, quant, coding_type, bpfEncoded, qa;

    bpfEncoded = mBitsEncodedFrame;
    mBitsDesiredTotal += mBitsDesiredFrame;
    coding_type = VOL.short_video_header ? VOP.picture_coding_type : VOP.vop_coding_type;
    SetQuantBVOP();
    if (coding_type == MP4_VOP_TYPE_B)
        return;
    delay = (int)(mBitsDesiredTotal - mBitsEncodedTotal);
    if (coding_type == MP4_VOP_TYPE_I) {
        bpfExpected = (mBitsDesiredFrame << 2) + (delay >> 1);
        mp4_ClipL(bpfExpected, mBitsDesiredFrame * 7 >> 3);
    } else if (coding_type == MP4_VOP_TYPE_B) {
        bpfExpected = (mBitsDesiredFrame / 3) + (delay >> 2);
        mp4_Clip(bpfExpected, mBitsDesiredFrame / 4, mBitsDesiredFrame * 3 >> 2);
    } else { // P- and S(GMC)-VOP
        bpfExpected = mBitsDesiredFrame + (delay >> 1);
        mp4_Clip(bpfExpected, mBitsDesiredFrame >> 1, mBitsDesiredFrame << 1);
    }
    quant = (coding_type == MP4_VOP_TYPE_I) ? mQuantIVOP : (coding_type == MP4_VOP_TYPE_B) ? mQuantBVOP : mQuantPVOP;
    mRCqs += quant;
    mRCqh ++; if (mRCqh >= RCBS) mRCqh = 0;
    if (mRCbf) {
        mRCqs -= mRCqb[mRCqh];
        qa = (mRCqs + RCBS/2) / RCBS;
    } else {
        if (mRCqh == RCBS-1)
            mRCbf = 1;
        qa = (mRCqs + ((mRCqh + 1) >> 1)) / (mRCqh + 1);
    }
    mRCqb[mRCqh] = (Ipp8u)quant;
    if (mp4_Abs(bpfEncoded - bpfExpected) > (bpfExpected >> 2)) {
        if (bpfEncoded > bpfExpected) {
            //if (quant == 31) {
            //    mCoeffsCut ++;
            //    mp4_ClipR(mCoeffsCut, 64);
            //}
            quant ++;
            //if (bpfEncoded > 4 * bpfExpected)
            //    quant ++;
            int cq = IPP_MIN(31, qa + 4);
            mp4_ClipR(quant, cq);
        } else if (bpfEncoded < bpfExpected) {
            //mCoeffsCut --;
            //mp4_ClipL(mCoeffsCut, 0);
            quant --;
            //if (bpfEncoded * 4 < bpfExpected)
            //    quant --;
            int cq = IPP_MAX(2, qa - 4);
            mp4_ClipL(quant, cq);
        }
    }
    if (VOL.short_video_header && quant < 3)
        quant = 3;
    if (coding_type == MP4_VOP_TYPE_B) {
        //if (quant <= mQuantPVOP + 1) {
        //   quant = mQuantPVOP + 2;
        //   mp4_ClipR(quant, 31);
        //}
        //quant = mQuantPVOP * 3 >> 1;
        //mp4_Clip(quant, 4, 31);
        mQuantBVOP = quant;
    } else {
        mQuantPrev = mQuantPVOP;
        mQuantIVOP = mQuantPVOP = quant;
    }
#endif
}


Ipp32s MPEG4_RC::GetQP(Ipp32s frameType)
{
    return ((frameType == MP4_VOP_TYPE_I) ? mQuantI : (frameType == MP4_VOP_TYPE_B) ? mQuantB : mQuantP);
}

void MPEG4_RC::SetQP(Ipp32s frameType, Ipp32s q)
{
    mp4_Clip(q, mQuantMin, mQuantMax);
    if (frameType == MP4_VOP_TYPE_B)
        mQuantB = q;
    else {
        mRCq = mQuantI = mQuantP = q;
        SetQuantB();
    }
}

// ----------------------------------

MPEG4_RC_MB::MPEG4_RC_MB()
{
    ippsZero_8u((Ipp8u*)this, sizeof(MPEG4_RC_MB));
}


MPEG4_RC_MB::~MPEG4_RC_MB()
{
    Close();
}


void MPEG4_RC_MB::Close()
{
    mIsInit = false;
}


Ipp32s MPEG4_RC_MB::GetInitQP(Ipp32s bitRate, Ipp64f frameRate, Ipp32s frameWidth, Ipp32s frameHeight)
{
    Ipp32s q = (Ipp32s)(frameWidth * frameHeight * frameRate * 0.5 / bitRate) + 1;
    mp4_Clip(q, mQuantMin, mQuantMax);
    return q;
}


Ipp32s MPEG4_RC_MB::GetQP()
{
    return mQuant;
}


void MPEG4_RC_MB::Init(Ipp32s bitRate, Ipp64f frameRate, Ipp32s frameWidth, Ipp32s frameHeight, Ipp32s mbPerRow, Ipp32s mbPerCol, Ipp32s keyInt, Ipp32s dp, Ipp32s qMin, Ipp32s qMax)
{
    if (mIsInit)
        Close();
    mNumMacroBlockPerRow = mbPerRow;
    mNumMacroBlockPerCol = mbPerCol;
    mIVOPdist = keyInt;
    mDP = dp;
    mQuantMax = qMax;
    mQuantMin = qMin;
    mBitRate = bitRate;
    mBitsDesiredTotal = 0;
    mBitsEncodedTotal = 0;
    mBitsDesiredFrame = (Ipp32s)(mBitRate / frameRate);
    mQuant = GetInitQP(bitRate, frameRate, frameWidth, frameHeight);
    mIsInit = true;
}


void MPEG4_RC_MB::Start(mp4_Slice *slice, Ipp32s frameType, Ipp32s quant)
{
    int bb, bpf;

    bb = (int)(mBitsDesiredTotal - mBitsEncodedTotal) * slice->numRow / mNumMacroBlockPerCol;
    if (frameType == MP4_VOP_TYPE_I) {
        bpf = 4 * mBitsDesiredFrame * slice->numRow / mNumMacroBlockPerCol;
        bpf += mIVOPdist < 30 ? (bb * 2 / mIVOPdist) : (bb >> 4);
        mp4_Clip(bpf, mBitsDesiredFrame * slice->numRow / mNumMacroBlockPerCol, mBitRate * slice->numRow / mNumMacroBlockPerCol >> 1);
    } else {
        bpf = mBitsDesiredFrame * slice->numRow / mNumMacroBlockPerCol;
        bpf += mIVOPdist < 30 ? (bb * 2 / mIVOPdist) : (bb >> 4);
        mp4_Clip(bpf, mBitsDesiredFrame * slice->numRow / mNumMacroBlockPerCol >> 1, mBitRate * slice->numRow / mNumMacroBlockPerCol >> 2);
    }
    slice->rc.bpuAvg = (bpf + (slice->numRow * mNumMacroBlockPerRow >> 1)) / (slice->numRow * mNumMacroBlockPerRow);
    slice->rc.bpsAvg = slice->rc.bpsEnc = 0;
    slice->rc.sQuant = quant;
    //slice->cBS.GetPos(&slice->rc.sBitPtr, &slice->rc.sBitOff);
    slice->rc.sBitPtr = slice->cBS.GetPtr();  slice->rc.sBitOff = 0;
    slice->cBS_1.GetPos(&slice->rc.sBitPtr_1, &slice->rc.sBitOff_1);
    slice->cBS_2.GetPos(&slice->rc.sBitPtr_2, &slice->rc.sBitOff_2);
}


void MPEG4_RC_MB::Update(mp4_Slice *slice, int *dquant, Ipp32s frameType)
{
    int    bpuEnc, bpuExp, delay, quant=0;

    bpuEnc = slice->cBS.GetNumBits(slice->rc.sBitPtr, slice->rc.sBitOff);
    slice->cBS.GetPos(&slice->rc.sBitPtr, &slice->rc.sBitOff);
    if (mDP) {
        bpuEnc += slice->cBS_1.GetNumBits(slice->rc.sBitPtr_1, slice->rc.sBitOff_1) + slice->cBS_2.GetNumBits(slice->rc.sBitPtr_2, slice->rc.sBitOff_2);
        slice->cBS_1.GetPos(&slice->rc.sBitPtr_1, &slice->rc.sBitOff_1);
        slice->cBS_2.GetPos(&slice->rc.sBitPtr_2, &slice->rc.sBitOff_2);
    }
    slice->rc.bpsAvg += slice->rc.bpuAvg;
    slice->rc.bpsEnc += bpuEnc;
    delay = slice->rc.bpsAvg - slice->rc.bpsEnc;
    bpuExp = slice->rc.bpuAvg + (delay >> 1);
    mp4_Clip(bpuExp, slice->rc.bpuAvg >> 1, slice->rc.bpuAvg << 1);
    if (mp4_Abs(bpuEnc - bpuExp) > (bpuExp >> 4)) {
        quant = slice->rc.sQuant;
        if (bpuEnc > bpuExp) {
            if (frameType != MP4_VOP_TYPE_B) {
                quant ++;
                mp4_ClipR(quant, mQuantMax);
            } else {
                if (quant + 2 <= mQuantMax)
                    quant += 2;
            }
        } else if (bpuEnc < bpuExp) {
            if (frameType != MP4_VOP_TYPE_B) {
                quant --;
                mp4_ClipL(quant, mQuantMin);
            } else {
                if (quant - 2 >= mQuantMin)
                    quant -= 2;
            }
        }
        *dquant = quant - slice->rc.sQuant;
        slice->rc.sQuant = quant;
    } else
        *dquant = 0;
}


void MPEG4_RC_MB::PostFrame(Ipp32s bpfEncoded, Ipp32s quantSum)
{
    mBitsEncodedTotal += bpfEncoded;
    mBitsDesiredTotal += mBitsDesiredFrame;
    Ipp32s mbF = mNumMacroBlockPerCol * mNumMacroBlockPerRow;
    mQuant = (quantSum + (mbF >> 1)) / mbF;
}


} //namespace MPEG4_ENC

#endif //defined (UMC_ENABLE_MPEG4_VIDEO_ENCODER)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -