📄 umc_vc1_enc_bit_rate_control.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.
//
//
// VC-1 (VC1) encoder, bit rate control
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_VC1_VIDEO_ENCODER)
#include "umc_vc1_enc_bit_rate_control.h"
#include "umc_vc1_common_defs.h"
#include "umc_vc1_enc_debug.h"
#include "umc_vc1_enc_sequence_adv.h"
#include "umc_vc1_enc_sequence_sm.h"
namespace UMC_VC1_ENCODER
{
VC1BitRateControl::VC1BitRateControl(): m_BRC(NULL), m_HRD(NULL),m_LBucketNum(0),
m_bitrate(1024000), m_framerate(30),
m_currSize(0),
m_GOPLength(1), m_BFrLength(0),
m_encMode(VC1_BRC_HIGHT_QUALITY_MODE)
{
#ifdef BRC_TEST
memset(&BRCFileSizeTest, 0, sizeof(BRCFileSizeTest));
#endif
}
UMC::Status VC1BitRateControl::Init(Ipp32u yuvFSize, Ipp32u bitrate, Ipp64f framerate, Ipp32u mode,
Ipp32u GOPLength, Ipp32u BFrLength, Ipp32u doubleQuant)
{
UMC::Status VC1Sts = UMC::UMC_OK;
Ipp32s i = 0;
if(GOPLength == 0)
return UMC::UMC_ERR_ALLOC;
Close();
m_encMode = mode;
if(doubleQuant)
m_encMode = VC1_BRC_CONST_QUANT_MODE;
if(bitrate == 0) bitrate = 2*1024000;
if(framerate == 0)framerate = 30;
m_bitrate = bitrate;
m_framerate = framerate;
m_GOPLength = GOPLength;
m_BFrLength = BFrLength;
//hypothetical reference decoder
m_HRD = new VC1HRDecoder *[VC1_ENC_MAX_NUM_LEAKY_BUCKET];
if(!m_HRD)
{
Close();
return UMC::UMC_ERR_ALLOC;
}
for(i = 0; i < VC1_ENC_MAX_NUM_LEAKY_BUCKET; i++)
{
m_HRD[i] = new VC1HRDecoder();
if (!m_HRD[i])
{
Close();
return UMC::UMC_ERR_ALLOC;
}
}
if(GOPLength == 1)
m_BRC = new VC1BRC_I();
else if (BFrLength == 0)
m_BRC = new VC1BRC_IP();
else
m_BRC = new VC1BRC_IPB();
if(!m_BRC)
{
Close();
return UMC::UMC_ERR_ALLOC;
}
m_BRC->Init(yuvFSize, m_bitrate,m_framerate,m_encMode,m_GOPLength,BFrLength,doubleQuant);
#ifdef BRC_TEST
memset(&BRCFileSizeTest, 0, sizeof(BRCFileSizeTest));
BRCFileSizeTest.RES_File = fopen("BRCTest.txt","a");
#endif
return VC1Sts;
}
VC1BitRateControl::~VC1BitRateControl()
{
Close();
}
UMC::Status VC1BitRateControl::InitBuffer(Ipp32s profile, Ipp32s level,Ipp32s BufferSize, Ipp32s initFull)
{
UMC::Status UMCSts = UMC::UMC_OK;
if(m_LBucketNum + 1 >= VC1_ENC_MAX_NUM_LEAKY_BUCKET)
return UMC::UMC_ERR_FAILED;
UMCSts = m_HRD[m_LBucketNum]->InitBuffer(profile, level, BufferSize, initFull, m_bitrate, m_framerate);
m_LBucketNum++;
return UMCSts;
}
void VC1BitRateControl::Close()
{
Ipp32s i = 0;
//------------------------------------------------------
#ifdef BRC_TEST
if(BRCFileSizeTest.RES_File)
fclose(BRCFileSizeTest.RES_File);
memset(&BRCFileSizeTest, 0, sizeof(BRCFileSizeTest));
#endif
//------------------------------------------------------
if(m_HRD)
{
for(i = 0; i < VC1_ENC_MAX_NUM_LEAKY_BUCKET; i++)
{
if(m_HRD[i])
{
delete m_HRD[i];
m_HRD[i] = NULL;
}
}
delete m_HRD;
m_HRD = NULL;
}
m_LBucketNum = 0;
if(m_BRC)
{
delete m_BRC;
m_BRC = NULL;
}
Reset();
}
void VC1BitRateControl::Reset()
{
Ipp32s i = 0;
//hypothetical ref decoder
for(i = 0; i < m_LBucketNum; i++)
{
if(m_HRD[i])
m_HRD[i]->Reset();
}
if(m_BRC)
m_BRC->Reset();
}
void VC1BitRateControl::GetQuant(Ipp32u picType, Ipp8u* PQuant, bool* Half)
{
m_BRC->GetQuant(picType, PQuant, Half);
}
UMC::Status VC1BitRateControl::CheckFrameCompression(Ipp32u picType, Ipp32u currSize)
{
UMC::Status UMCSts = UMC::UMC_OK;
Ipp32s Sts = 0;
Ipp32s i = 0;
m_currSize = currSize;
#ifdef BRC_TEST
if(BRCFileSizeTest.RES_File)
fprintf(BRCFileSizeTest.RES_File, "%d,", currSize);
#endif
//check HRD status
for(i = 0; i < m_LBucketNum; i++)
{
Sts = m_HRD[i]->CheckBuffer(m_currSize);
UMCSts |= HandleHRDResult(Sts);
}
#ifdef VC1_HRD_DEBUG
// printf("CheckBuffer Sts = %d\n", Sts);
#endif
// UMCSts = UMC::UMC_OK;
m_BRC->CheckFrameCompression(picType, m_currSize, UMCSts);
return UMCSts;
}
UMC::Status VC1BitRateControl::CompleteFrame(Ipp32u picType)
{
Ipp32s Sts = 0;
UMC::Status umcSts = UMC::UMC_OK;
Ipp32s i = 0;
for(i = 0; i < m_LBucketNum; i++)
{
Sts = m_HRD[i]->ReleaseData(m_currSize);
umcSts |= HandleHRDResult(Sts);
}
#ifdef VC1_HRD_DEBUG
// printf("CompleteFrame Sts = %d\n", Sts);
#endif
if(m_encMode == VC1_BRC_CONST_QUANT_MODE)
return umcSts;
m_BRC->CompleteFrame(picType);
return umcSts;
}
void VC1BitRateControl::GetAllHRDParams(VC1_HRD_PARAMS* param)
{
VC1_hrd_OutData hrdParams;
Ipp32s i = 0;
Ipp32s j = 0;
Ipp32s BufferSize[32];
Ipp32s Fullness[32];
Ipp32s Rate[32];
Ipp32s rate_exponent = 0;;
Ipp32s buffer_size_exponent = 0;
Ipp32s temp = 0;
param->HRD_NUM_LEAKY_BUCKETS = m_LBucketNum;
if(m_LBucketNum == 0)
return;
for(i = 0; i < m_LBucketNum; i++)
{
m_HRD[i]->GetHRDParams(&hrdParams);
Fullness[i] = hrdParams.hrd_fullness;
BufferSize[i] = hrdParams.hrd_buffer;
Rate[i] = hrdParams.hrd_max_rate;
}
rate_exponent = GetHRD_Rate(Rate);
buffer_size_exponent = GetHRD_Buffer(BufferSize);
param->BIT_RATE_EXPONENT = rate_exponent - 6;
assert (param->BIT_RATE_EXPONENT > 5);
assert (param->BIT_RATE_EXPONENT < 22);
param->BUFFER_SIZE_EXPONENT = buffer_size_exponent - 4;
assert(param->BUFFER_SIZE_EXPONENT > 3);
assert(param->BUFFER_SIZE_EXPONENT < 20);
for(i = 0; i < m_LBucketNum; i++)
{
Rate[i] = Rate[i]>>rate_exponent;
BufferSize[i] = BufferSize[i]>>buffer_size_exponent;
}
//Sort data
for(i = 0; i < m_LBucketNum - 1; i++)
for(j = i; j < m_LBucketNum - 1; j++)
{
if(Rate[i] > Rate[i+1])
{
temp = Rate[i];
Rate[i] = Rate[i+1];
Rate[i+1] = temp;
temp = BufferSize[i];
BufferSize[i] = BufferSize[i+1];
BufferSize[i+1] = temp;
temp = Fullness[i];
Fullness[i] = Fullness[i+1];
Fullness[i+1] = temp;
}
}
for(i = 0; i < m_LBucketNum; i++)
{
param->HRD_RATE[i] = Rate[i];
param->HRD_BUFFER[i] = BufferSize[i] - 1;
param->HRD_FULLNESS[i] = Fullness[i] - 1;
}
}
UMC::Status VC1BitRateControl::GetCurrentHRDParams(Ipp32s HRDNum, VC1_hrd_OutData* hrdParams)
{
UMC::Status err = UMC::UMC_OK;
if(!m_HRD)
return UMC::UMC_ERR_NOT_INITIALIZED;
m_HRD[HRDNum]->GetHRDParams(hrdParams);
return err;
}
Ipp32s VC1BitRateControl::GetHRD_Rate(Ipp32s* rate)
{
Ipp32s exponent = 32;
Ipp32s i = 0;
Ipp32s j = 0;
Ipp32s zero_num = 0;
Ipp32s temp = 0;
for(i = 0; i < m_LBucketNum; i++)
{
zero_num = 0;
temp = rate[i];
j = 0;
while((j < 32) && ((temp & 1)==0))
{
temp>>=1;
zero_num++;
j++;
}
if(zero_num < exponent)
exponent = zero_num;
}
if(exponent > 27)
exponent = 27;
if(exponent < 12)
exponent = 12;
return exponent;
}
Ipp32s VC1BitRateControl::GetHRD_Buffer(Ipp32s* size)
{
Ipp32s exponent = 32;
Ipp32s i = 0;
Ipp32s j = 0;
Ipp32s zero_num = 0;
Ipp32s temp = 0;
for(i = 0; i < m_LBucketNum; i++)
{
zero_num = 0;
temp = size[i];
j = 0;
while((j < 32) && ((temp & 1)==0))
{
temp>>=1;
zero_num++;
j++;
}
if(zero_num < exponent)
exponent = zero_num;
}
if(exponent > 23)
exponent = 23;
if(exponent < 8)
exponent = 8;
return exponent;
}
Ipp32s VC1BitRateControl::GetLevel(Ipp32u profile, Ipp32u bitrate, Ipp32u widthMB, Ipp32u heightMB)
{
Ipp32s i = 0;
Ipp32s j = 0;
Ipp32s level = 0;
Ipp32u mbNum = widthMB * heightMB;
if(profile == VC1_ENC_PROFILE_A) j = 2;
else
if(profile == VC1_ENC_PROFILE_M) j = 1;
while((i < 4) && (rMax_LevelLimits[j][i] < bitrate))
i++;
while((i < 4) && (MBfLimits[j][i] < mbNum))
i++;
if(profile == VC1_ENC_PROFILE_A)
{
if(i == 4)
level = VC1_ENC_LEVEL_4;
else if (i == 3)
level = VC1_ENC_LEVEL_3;
else if (i == 2)
level = VC1_ENC_LEVEL_2;
else if (i == 1)
level = VC1_ENC_LEVEL_1;
else
level = VC1_ENC_LEVEL_0;
if((rMax_LevelLimits[j][i]) == 0)
level = VC1_ENC_LEVEL_4;
}
else if(profile == VC1_ENC_PROFILE_M)
{
if(i == 2)
level = VC1_ENC_LEVEL_H;
else if(i == 1)
level = VC1_ENC_LEVEL_M;
else
level = VC1_ENC_LEVEL_S;
if((rMax_LevelLimits[j][i]) == 0)
level = VC1_ENC_LEVEL_H;
}
else
{
if(i == 2)
level = VC1_ENC_LEVEL_H;
else if(i == 1)
level = VC1_ENC_LEVEL_M;
else
level = VC1_ENC_LEVEL_S;
if((rMax_LevelLimits[j][i]) == 0)
level = VC1_ENC_LEVEL_H;
}
return level;
}
UMC::Status VC1BitRateControl::HandleHRDResult(Ipp32s hrdStatus)
{
UMC::Status umcSts = UMC::UMC_OK;
//HRD decoder returns decoder buffer status, it should be corrected for encoder
//if decoder status NOT_ENOUGH_DATA, it means that frames size is very big,
//decoder gets more bits(frame size), than it is possible for current bitrate
if(hrdStatus == VC1_HRD_OK)
umcSts = UMC::UMC_OK;
else
if((hrdStatus & VC1_HRD_ERR_ENC_NOT_ENOUGH_DATA) || (hrdStatus & VC1_HRD_ERR_DEC_NOT_ENOUGH_DATA))
umcSts = UMC::UMC_ERR_NOT_ENOUGH_BUFFER; //frame size is very big, no data for decoder
else if((hrdStatus & VC1_HRD_ERR_ENC_NOT_ENOUGH_BUFFER) || (hrdStatus & VC1_HRD_ERR_DEC_NOT_ENOUGH_BUFFER))
umcSts = UMC::UMC_ERR_NOT_ENOUGH_DATA; //frame size is very small, no place for adding data
else umcSts = UMC::UMC_ERR_FAILED;
return umcSts;
}
//Ipp32s VC1BitRateControl::CheckBlockQuality(Ipp16s* pSrc, Ipp32u srcStep,
// Ipp32u quant, Ipp32u intra)
//{
// Ipp32u i = 0;
// Ipp32u j = 0;
// Ipp32s temp = 0;
// Ipp16s* ptr = pSrc;
// Ipp32u zeroCoef = 0;
//
// for(i = intra; i < VC1_PIXEL_IN_BLOCK; i++)
// {
// for (j = 0; j < VC1_PIXEL_IN_BLOCK; j++)
// {
// temp = ptr[j]/quant;
// zeroCoef += !temp;
// }
//
// ptr+=srcStep;
// }
//
// return zeroCoef;
//}
UMC::Status VC1BitRateControl::GetBRInfo(VC1BRInfo* pInfo)
{
UMC::Status err = UMC::UMC_OK;
Ipp8u pQuant;
bool HalfQP;
pInfo->bitrate = m_bitrate;
pInfo->framerate = m_framerate;
if(!m_BRC)
return UMC::UMC_ERR_NOT_INITIALIZED;
if(m_encMode == VC1_BRC_CONST_QUANT_MODE)
{
m_BRC->GetQuant(VC1_I_FRAME, &pQuant, &HalfQP);
pInfo->constQuant = (pQuant<<1) + HalfQP;
}
else
{
pInfo->constQuant = 0;
}
return err;
}
}
#endif // defined (UMC_ENABLE_VC1_VIDEO_ENCODER)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -