跳转到主要内容

设置I帧的QP,提高I帧的质量

作者:Hank FU,hankf@xilinx.com,本文转载自:<span id="profileBt"><a href="https://www.cnblogs.com/hankfu/p/15357536.html">博客园</a></span&gt;

<strong>介绍</strong>
在有些应用中,发现I帧不够大。MPSoC VCU CtrlSW可以设置每一帧的QP大小。因此,可以通过设置I帧的QP,提高I帧的大小,从而提高I帧的质量。

<strong>代码</strong>
下面是设置I帧的QP的示例代码。

<strong>GOP长度变量</strong>
在struct EncoderSink : IFrameSink的定义里添加GOP的成员变量,记录GOP长度。
<pre>#if USER_I_FRAME_QP
// USER_I_FRAME_QP changes START
float uFrameRate = 0.0f;
int uGopLength = 0;
// USER_I_FRAME_QP changes END

#endif // USER_I_FRAME_QP</pre>

<strong>记录GOP长度</strong>
在EncoderSink 的EncoderSink函数设置GOP的变量的值。
<pre> struct EncoderSink : IFrameSink
{
EncoderSink(ConfigFile const& cfg, AL_IEncScheduler* pScheduler, AL_TAllocator* pAllocator
) :
CmdFile(cfg.sCmdFileName, false),
EncCmd(CmdFile.fp, cfg.RunInfo.iScnChgLookAhead, cfg.Settings.tChParam[0].tGopParam.uFreqLT),
twoPassMngr(cfg.sTwoPassFileName, cfg.Settings.TwoPass, cfg.Settings.bEnableFirstPassSceneChangeDetection, cfg.Settings.tChParam[0].tGopParam.uGopLength,
cfg.Settings.tChParam[0].tRCParam.uCPBSize / 90, cfg.Settings.tChParam[0].tRCParam.uInitialRemDelay / 90, cfg.MainInput.FileInfo.FrameRate),
qpBuffers{cfg.Settings, cfg.RunInfo.eGenerateQpMode},
pAllocator{pAllocator},
pSettings{&cfg.Settings}
{

#if USER_I_FRAME_QP
// USER_I_FRAME_QP changes STARTED ----------------------------------
uFrameRate = cfg.Settings.tChParam.tRCParam.uFrameRate;
uGopLength = cfg.Settings.tChParam.tGopParam.uGopLength;
// USER_I_FRAME_QP changes END --------------------------------------
#endif // USER_I_FRAME_QP

} </pre>

<strong>设置QP</strong>
在EncoderSink 的ProcessFrame函数里,根据GOP长度,确定每个GOP开始的I帧。然后再设置QP的值。可以试试20-35之间的QP值。QP值是20时,能带来很好的图像质量。
<pre>void ProcessFrame(AL_TBuffer* Src) override
{
if(m_picCount == 0)
m_StartTime = GetPerfTime();

if(!Src)
{
LogVerbose("Flushing...\n\n");

if(!AL_Encoder_Process(hEnc, nullptr, nullptr))
throw std::runtime_error("Failed");
return;
}

DisplayFrameStatus(m_picCount);

if(twoPassMngr.iPass)
{
auto pPictureMetaTP = AL_TwoPassMngr_CreateAndAttachTwoPassMetaData(Src);

if(twoPassMngr.iPass == 2)
twoPassMngr.GetFrame(pPictureMetaTP);
}

AL_TBuffer* QpBuf = qpBuffers.getBuffer(m_picCount);

std::shared_ptr&lt;AL_TBuffer&gt; QpBufShared(QpBuf, [&](AL_TBuffer* pBuf) { qpBuffers.releaseBuffer(pBuf); });

if(pSettings-&gt;hRcPluginDmaContext != NULL)
RCPlugin_SetNextFrameQP(pSettings, pAllocator);

#if USER_I_FRAME_QP
if( 0 == (m_picCount%uGopLength) )
{

AL_Encoder_SetQP(hEnc, 20 );
}
#endif // USER_I_FRAME_QP

if(!AL_Encoder_Process(hEnc, Src, QpBuf))
throw std::runtime_error("Failed");

m_picCount++;
m_picGopCount++;
}</pre>