📄 umc_vc1_enc_brc_gop.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_brc_gop.h"
#include "umc_vc1_common_defs.h"
#include "umc_vc1_enc_debug.h"
namespace UMC_VC1_ENCODER
{
VC1BRC::VC1BRC(): m_GOPLength (1), m_BFrLength (0), m_SizeAbberation(0),
m_recoding(0), m_currSize(0), m_IdealFrameSize(0),
m_picType(VC1_I_FRAME), m_ratio_min(0.6),m_buffer_overflow(1.1),
m_encMode(VC1_BRC_HIGHT_QUALITY_MODE)
{
m_CurQuant.PQIndex = 1;
m_CurQuant.HalfPQ = 1;
m_Quant.IQuant = 1;
m_Quant.PQuant = 1;
m_Quant.BQuant = 1;
m_Quant.LimIQuant = 1;
m_Quant.LimPQuant = 1;
m_Quant.LimBQuant = 1;
m_Quant.IHalf = 0;
m_Quant.PHalf = 0;
m_Quant.BHalf = 0;
};
VC1BRC::~VC1BRC()
{
};
////////////////////////////////////////////
// VC1BRC_I
////////////////////////////////////////////
VC1BRC_I::VC1BRC_I():m_needISize(0)
{
};
VC1BRC_I::~VC1BRC_I()
{
Close();
};
UMC::Status VC1BRC_I::Init(Ipp32u yuvFSize, Ipp32u bitrate, Ipp64f framerate,
Ipp32u mode, Ipp32u GOPLength, Ipp32u BFrLength,
Ipp32u doubleQuant)
{
UMC::Status VC1Sts = UMC::UMC_OK;
m_bitrate = bitrate;
m_framerate = framerate;
m_GOPLength = GOPLength;
m_BFrLength = BFrLength;
m_IdealFrameSize = (Ipp32u)(bitrate/framerate/8);
m_needISize = m_IdealFrameSize;
#ifdef VC1_GOP_DEBUG
printf("\n\n m_GOPSize = %d\n", m_needISize);
#endif
if(!doubleQuant)
{
Ipp32s AverageCompression = (Ipp32s)((yuvFSize)/m_needISize)/3;
VC1_QUANT_CLIP(AverageCompression, 0);
m_CurQuant.PQIndex = m_Quant.IQuant = AverageCompression;
}
else
{
if(doubleQuant > (VC1_MAX_QUANT*2))
return UMC::UMC_ERR_ALLOC;
m_encMode = VC1_BRC_CONST_QUANT_MODE;
m_CurQuant.PQIndex = m_Quant.IQuant = m_Quant.PQuant = m_Quant.BQuant = (doubleQuant>>1);
m_CurQuant.HalfPQ = m_Quant.IHalf = m_Quant.PHalf = m_Quant.BHalf = doubleQuant&0x1;
}
switch(m_encMode)
{
case VC1_BRC_HIGHT_QUALITY_MODE:
case VC1_BRC_CONST_QUANT_MODE:
m_ratio_min = (Ipp32f)(0.6);
m_buffer_overflow = (Ipp32f)(1.1);
break;
default:
m_ratio_min = (Ipp32f)(0.6);
m_buffer_overflow = (Ipp32f)(1.1);
break;
}
return VC1Sts;
};
void VC1BRC_I::Close()
{
Reset();
};
void VC1BRC_I::Reset()
{
//GOP parameters
m_SizeAbberation = 0;
//Frames parameters
m_currSize = 0;
//Flags
m_recoding = 0;
};
UMC::Status VC1BRC_I::CheckFrameCompression(Ipp32u picType, Ipp32u currSize, UMC::Status HRDSts)
{
UMC::Status UMCSts = UMC::UMC_OK;
Ipp32s Sts = 0;
Ipp32f ratio = 0;
if(currSize < 0)
return UMC::UMC_ERR_INVALID_PARAMS;
m_currSize = currSize;
ratio = ((Ipp32f)currSize/(Ipp32f)m_needISize);
#ifdef VC1_BRC_DEBUG
printf("current ratio = %f\n", ratio);
#endif
#ifdef VC1_GOP_DEBUG
printf("I ");
printf("current ratio = %f %d %d % d\n", ratio, m_CurQuant.PQIndex, m_CurQuant.HalfPQ, currSize);
#endif
switch(m_encMode)
{
case VC1_BRC_HIGHT_QUALITY_MODE:
CheckFrame_QualityMode(ratio, HRDSts);
break;
case VC1_BRC_CONST_QUANT_MODE:
break;
default:
break;
}
m_recoding++;
#ifdef VC1_BRC_DEBUG
printf("coded size %d\n", currSize);
#endif
return UMCSts;
};
void VC1BRC_I::CompleteFrame(Ipp32u picType)
{
UMC::Status UMCSts = UMC::UMC_OK;
Ipp32f ratioI = 0;
Ipp32s prefINeedSize = m_needISize;
#ifdef BRC_TEST
if(BRCFileSizeTest.RES_File)
fprintf(BRCFileSizeTest.RES_File, "%d,",m_currSize);
#endif
if(m_encMode == VC1_BRC_CONST_QUANT_MODE)
return;
#ifdef VC1_GOP_DEBUG
printf("\nGOP ratio = %f\n\n", ((Ipp32f)m_currSize/(Ipp32f)m_needISize));
printf("-----------------------------------NEW GOP");
printf("------------------------------------------\n\n\n");
#endif
m_SizeAbberation += m_IdealFrameSize - m_currSize;
//check overflow m_SizeAbberation
if(m_SizeAbberation > 4*m_IdealFrameSize)
m_SizeAbberation = 4*m_IdealFrameSize;
if(m_SizeAbberation < (- 4*m_IdealFrameSize))
m_SizeAbberation = -(4*m_IdealFrameSize);
m_needISize = m_IdealFrameSize + m_SizeAbberation;
//check m_needISize
if(m_needISize > m_IdealFrameSize + (m_IdealFrameSize>>1))
m_needISize = m_IdealFrameSize + (m_IdealFrameSize>>1);
if(m_needISize < (m_IdealFrameSize>>1))
m_needISize = (m_IdealFrameSize>>1);
#ifdef VC1_GOP_DEBUG
printf("nextGOPSize = %d\n", m_needISize);
printf("m_SizeAbberation = %d\n", m_SizeAbberation);
#endif
ratioI = ((Ipp32f)prefINeedSize/(Ipp32f)m_needISize);
QuantForNewGOP(ratioI);
m_recoding = 0;
#ifdef VC1_BRC_DEBUG
printf("\n\n\n");
#endif
};
void VC1BRC_I::CheckFrame_QualityMode(Ipp32f ratio, UMC::Status UMCSts)
{
Ipp32s curQuant = 0;
Ipp32s Sts = VC1_BRC_OK;
bool HalfQP = 0;
//new quant calculation
curQuant = (Ipp32s)(ratio * m_CurQuant.PQIndex + 0.5);
VC1_QUANT_CLIP(curQuant, 0);
//check compression
if((ratio <= m_buffer_overflow) && (ratio >= VC1_GOOD_COMPRESSION))
Sts = VC1_BRC_OK; //good frame
else if(ratio > m_buffer_overflow)
Sts |= VC1_BRC_NOT_ENOUGH_BUFFER; //could be critical situation, if HRD buffer small
else if(ratio <= m_ratio_min)
{
//very small frame
Sts |= VC1_BRC_ERR_SMALL_FRAME;
if(m_CurQuant.PQIndex > 1)
HalfQP = 1;
}
else if(ratio >= VC1_MIN_RATIO_HALF)
{
if((m_CurQuant.PQIndex > 1) && ((Ipp32u)curQuant > m_CurQuant.PQIndex))
HalfQP = 1;
Sts |= VC1_BRC_SMALL_FRAME;
}
else
Sts |= VC1_BRC_SMALL_FRAME;
//check HRD status
if(UMCSts == UMC::UMC_ERR_NOT_ENOUGH_BUFFER)
{
Sts |= VC1_BRC_NOT_ENOUGH_BUFFER;
HalfQP = 0;
}
if(Sts != VC1_BRC_OK)
{
#ifdef VC1_BRC_DEBUG
printf("m_LimIQuant %d\n", m_Quant.LimIQuant);
#endif
m_Quant.IQuant = (m_Quant.IQuant + curQuant)/2;
if(Sts & VC1_BRC_NOT_ENOUGH_BUFFER)
{
if(ratio > VC1_RATIO_ILIM)
{
m_Quant.IQuant++;
m_Quant.LimIQuant = m_CurQuant.PQIndex + 2;
}
else
{
if(m_CurQuant.PQIndex > 9)
m_Quant.LimIQuant = m_CurQuant.PQIndex + 1;
else if(m_Quant.IQuant <= m_CurQuant.PQIndex)
HalfQP = 1;
}
}
else if(Sts & VC1_BRC_ERR_SMALL_FRAME)
{
m_Quant.LimIQuant--;
if(m_Quant.IQuant >= m_CurQuant.PQIndex)
m_Quant.IQuant--;
if((ratio > VC1_MIN_RATIO_HALF) && (m_CurQuant.PQIndex > 1))
HalfQP = 1;
}
else if(Sts & VC1_BRC_SMALL_FRAME)
{
m_Quant.LimIQuant--;
if((m_Quant.IQuant < m_CurQuant.PQIndex) && m_Quant.IQuant && (m_CurQuant.PQIndex > 1))
HalfQP = 1;
}
VC1_QUANT_CLIP(m_Quant.LimIQuant,0);
VC1_QUANT_CLIP(m_Quant.IQuant, m_Quant.LimIQuant);
m_Quant.IHalf = HalfQP;
}
};
void VC1BRC_I::QuantForNewGOP(Ipp32f ratio)
{
Ipp32s curQuant = 0;
//new quant calculation
curQuant = (Ipp32s)(ratio * m_Quant.IQuant + 0.5);
VC1_QUANT_CLIP(curQuant, 0);
if(curQuant != m_Quant.IQuant)
m_Quant.IHalf = 0;
m_Quant.IQuant = (m_Quant.IQuant + curQuant + 1)/2;
//m_Quant.LimIQuant = (m_Quant.LimIQuant + m_Quant.IQuant - 1)/2;
//VC1_QUANT_CLIP(m_Quant.LimIQuant,0);
VC1_QUANT_CLIP(m_Quant.IQuant, m_Quant.LimIQuant);
};
void VC1BRC_I::GetQuant(Ipp32u picType, Ipp8u* PQuant, bool* Half)
{
m_CurQuant.PQIndex = m_Quant.IQuant;
m_CurQuant.HalfPQ = m_Quant.IHalf;
if(m_CurQuant.PQIndex > 8)
m_CurQuant.HalfPQ = 0;
#ifdef VC1_BRC_DEBUG
printf("cur quant %d\n", m_CurQuant.PQIndex);
printf("half quant %d\n", m_CurQuant.HalfPQ);
#endif
*PQuant = m_CurQuant.PQIndex;
*Half = m_CurQuant.HalfPQ;
}
////////////////////////////////////////////
// VC1BRC_IP
////////////////////////////////////////////
VC1BRC_IP::VC1BRC_IP() : m_I_GOPSize(0), m_P_GOPSize(0),
m_needISize(0), m_needPSize(0),
m_INum(0), m_PNum(0),
m_CurrINum(0), m_CurrPNum(0),
m_currFrameInGOP(0), m_poorRefFrame(0),
m_GOPHalfFlag(0), m_GOPSize(0),
m_currGOPSize(0), m_nextGOPSize(0),
m_currISize(0), m_currPSize(0),
m_IP_size((Ipp32f)(VC1_P_SIZE)),
m_failPQuant(0), m_failGOP(0),
m_AverageIQuant(0), m_AveragePQuant(0)
{
};
VC1BRC_IP::~VC1BRC_IP()
{
Close();
};
UMC::Status VC1BRC_IP::Init(Ipp32u yuvFSize, Ipp32u bitrate, Ipp64f framerate,
Ipp32u mode, Ipp32u GOPLength, Ipp32u BFrLength,
Ipp32u doubleQuant)
{
UMC::Status VC1Sts = UMC::UMC_OK;
m_bitrate = bitrate;
m_framerate = framerate;
m_GOPLength = GOPLength;
m_BFrLength = BFrLength;
m_INum = 1;
m_PNum = GOPLength - 1;
m_IdealFrameSize = (Ipp32u)(bitrate/framerate/8);
m_GOPSize = m_IdealFrameSize * m_GOPLength;
m_nextGOPSize = m_GOPSize;
#ifdef VC1_GOP_DEBUG
printf("\n\n m_GOPSize = %d\n", m_GOPSize);
#endif
m_needISize = (Ipp32s)(m_GOPSize/(1 + m_IP_size*m_PNum));
m_needPSize = (Ipp32s)(m_IP_size*m_needISize);
m_currISize = m_needISize;
m_currPSize = m_needPSize;
if(!doubleQuant)
{
Ipp32s AverageCompression = (Ipp32s)((yuvFSize)/m_needISize)/3;
VC1_QUANT_CLIP(AverageCompression, 0);
m_CurQuant.PQIndex = m_Quant.IQuant = AverageCompression;
AverageCompression = (Ipp32s)((yuvFSize)/m_needPSize)/5;
VC1_QUANT_CLIP(AverageCompression, 0);
m_Quant.PQuant = AverageCompression;
if(m_Quant.PQuant > 2)
m_Quant.PQuant -= 2;
}
else
{
if(doubleQuant > (VC1_MAX_QUANT*2))
return UMC::UMC_ERR_ALLOC;
m_encMode = VC1_BRC_CONST_QUANT_MODE;
m_CurQuant.PQIndex = m_Quant.IQuant = m_Quant.PQuant = m_Quant.BQuant = (doubleQuant>>1);
m_CurQuant.HalfPQ = m_Quant.IHalf = m_Quant.PHalf = m_Quant.BHalf = doubleQuant&0x1;
}
switch(m_encMode)
{
case VC1_BRC_HIGHT_QUALITY_MODE:
case VC1_BRC_CONST_QUANT_MODE:
m_ratio_min = (Ipp32f)(0.6);
m_buffer_overflow = (Ipp32f)(1.1);
break;
default:
m_ratio_min = (Ipp32f)(0.6);
m_buffer_overflow = (Ipp32f)(1.1);
break;
}
return VC1Sts;
};
void VC1BRC_IP::Close()
{
Reset();
};
void VC1BRC_IP::Reset()
{
//GOP parameters
m_GOPSize = m_IdealFrameSize * m_GOPLength;
m_nextGOPSize = m_GOPSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -