obs/QSVHelper/QSVStuff.cpp
palana 0b0b5d28e6 Add custom parameters for QSV rate control modes
Custom parameters can be set via profile settings. This also allows
selecting newer modes such as look ahead modes on Haswell+.
2014-08-13 00:37:52 +02:00

327 lines
9.1 KiB
C++

/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "QSVStuff.h"
#include "Utilities.h"
using namespace std;
namespace {
void ConvertFrameRate(mfxF64 dFrameRate, mfxU32& pnFrameRateExtN, mfxU32& pnFrameRateExtD)
{
mfxU32 fr;
fr = (mfxU32)(dFrameRate + .5);
if(fabs(fr - dFrameRate) < 0.0001)
{
pnFrameRateExtN = fr;
pnFrameRateExtD = 1;
return;
}
fr = (mfxU32)(dFrameRate * 1.001 + .5);
if(fabs(fr * 1000 - dFrameRate * 1001) < 10)
{
pnFrameRateExtN = fr * 1000;
pnFrameRateExtD = 1001;
return;
}
pnFrameRateExtN = (mfxU32)(dFrameRate * 10000 + .5);
pnFrameRateExtD = 10000;
}
}
Parameters::Parameters()
{
zero(params);
}
Parameters::Parameters(const Parameters& o) : Parameters()
{
*this = o;
}
Parameters &Parameters::operator =(const Parameters& o)
{
params = o.params;
cospspps = o.cospspps;
vsi = o.vsi;
co = o.co;
co2 = o.co2;
if (o.FindExt(o.cospspps))
AddExt(cospspps);
if (o.FindExt(o.vsi))
AddExt(vsi);
if (o.FindExt(o.co))
AddExt(co);
if (o.FindExt(o.co2))
AddExt(co2);
return *this;
}
void Parameters::Init(mfxU16 target_usage, mfxU16 profile, int fps, int keyframe_interval_frames, int bframes, int width, int height, int max_bitrate,
int buffer_size, bool use_cbr, bool use_custom_params, mfxInfoMFX custom_params, decltype(mfxExtCodingOption2::LookAheadDepth) la_depth)
{
params.mfx.CodecId = MFX_CODEC_AVC;
params.mfx.TargetUsage = target_usage;
params.mfx.GopOptFlag = MFX_GOP_CLOSED;
params.mfx.GopPicSize = keyframe_interval_frames;
params.mfx.GopRefDist = bframes+1;
params.mfx.NumSlice = 1;
params.mfx.CodecProfile = profile;
params.mfx.TargetKbps = use_custom_params ? custom_params.TargetKbps : saturate<mfxU16>(max_bitrate);
params.mfx.BufferSizeInKB = use_custom_params ? custom_params.BufferSizeInKB : buffer_size / 8;
params.mfx.RateControlMethod = use_cbr ? MFX_RATECONTROL_CBR : use_custom_params ? custom_params.RateControlMethod : MFX_RATECONTROL_VBR;
switch (params.mfx.RateControlMethod)
{
case MFX_RATECONTROL_VBR:
case MFX_RATECONTROL_VCM:
params.mfx.MaxKbps = use_custom_params ? custom_params.MaxKbps : 0;
break;
case MFX_RATECONTROL_AVBR:
params.mfx.Accuracy = custom_params.Accuracy;
params.mfx.Convergence = custom_params.Convergence;
break;
case MFX_RATECONTROL_CQP:
params.mfx.QPI = custom_params.QPI;
params.mfx.QPP = custom_params.QPP;
params.mfx.QPB = custom_params.QPB;
break;
case MFX_RATECONTROL_ICQ:
case MFX_RATECONTROL_LA_ICQ:
params.mfx.ICQQuality = custom_params.ICQQuality;
case MFX_RATECONTROL_LA:
AddCodingOption2();
co2.LookAheadDepth = la_depth;
break;
}
params.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
auto& fi = params.mfx.FrameInfo;
ConvertFrameRate(fps, fi.FrameRateExtN, fi.FrameRateExtD);
fi.FourCC = MFX_FOURCC_NV12;
fi.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
fi.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
fi.Width = align16(width);
fi.Height = align16(height);
fi.CropX = 0;
fi.CropY = 0;
fi.CropW = width;
fi.CropH = height;
}
void Parameters::SetCodingOptionSPSPPS(mfxU8 *sps_buff, mfxU16 sps_size, mfxU8 *pps_buff, mfxU16 pps_size)
{
if(!FindExt(cospspps))
InitAddExt(cospspps, MFX_EXTBUFF_CODING_OPTION_SPSPPS);
cospspps.SPSBuffer = sps_buff;
cospspps.SPSBufSize = sps_size;
cospspps.PPSBuffer = pps_buff;
cospspps.PPSBufSize = pps_size;
}
void Parameters::SetVideoSignalInfo(int full_range, int primaries, int transfer, int matrix)
{
if (!FindExt(vsi))
InitAddExt(vsi, MFX_EXTBUFF_VIDEO_SIGNAL_INFO);
vsi.ColourDescriptionPresent = 1;
vsi.VideoFullRange = full_range;
vsi.ColourPrimaries = primaries;
vsi.TransferCharacteristics = transfer;
vsi.MatrixCoefficients = matrix;
vsi.VideoFormat = 5; //unspecified
}
void Parameters::AddCodingOption()
{
if (!FindExt(co))
InitAddExt(co, MFX_EXTBUFF_CODING_OPTION);
}
void Parameters::AddCodingOption2()
{
if (!FindExt(co2))
InitAddExt(co2, MFX_EXTBUFF_CODING_OPTION2);
}
void Parameters::UpdateExt()
{
params.ExtParam = const_cast<mfxExtBuffer**>(&ext_buffers.front());
params.NumExtParam = ext_buffers.size();
}
void EncodeCtrl::AddSEIData(sei_type type, vector<mfxU8> data)
{
unsigned payload_size = data.size();
vector<mfxU8> buffer;
mfxU16 type_ = type;
while(type_ > 255)
{
buffer.emplace_back(0xff);
type_ -= 255;
}
buffer.emplace_back((mfxU8)type_);
while(payload_size > 255)
{
buffer.emplace_back(0xff);
payload_size -= 255;
}
buffer.emplace_back(payload_size);
buffer.insert(end(buffer), begin(data), end(data));
data_buffers.emplace_back(buffer);
payloads.emplace_back(mfxPayload());
mfxPayload &sei_payload = payloads.back();
zero(sei_payload);
sei_payload.Type = type;
sei_payload.BufSize = buffer.size();
sei_payload.NumBit = sei_payload.BufSize*8;
sei_payload.Data = &data_buffers.back().front();
payload_list.clear();
for(auto &payload = begin(payloads); payload != end(payloads); payload++)
payload_list.emplace_back(&*payload);
ctrl.Payload = &payload_list.front();
ctrl.NumPayload = payload_list.size();
}
void Parameters::Dump(std::wostream &log_file)
{
auto &mfx = params.mfx;
#define OUT(name) log_file << " mfx." #name " = " << mfx.name << '\n'
OUT(BRCParamMultiplier);
OUT(CodecId);
OUT(CodecProfile);
OUT(CodecLevel);
OUT(NumThread);
OUT(TargetUsage);
OUT(GopPicSize);
OUT(GopRefDist);
OUT(GopOptFlag);
OUT(IdrInterval);
OUT(RateControlMethod);
OUT(InitialDelayInKB);
OUT(BufferSizeInKB);
OUT(TargetKbps);
OUT(MaxKbps);
OUT(NumSlice);
OUT(NumRefFrame);
OUT(EncodedOrder);
#undef OUT
for (auto i : ext_buffers)
{
#define OUT(name) log_file << " " #name " = " << name << '\n'
switch (i->BufferId)
{
case MFX_EXTBUFF_VIDEO_SIGNAL_INFO:
OUT(vsi.VideoFormat);
OUT(vsi.VideoFullRange);
OUT(vsi.ColourDescriptionPresent);
OUT(vsi.ColourPrimaries);
OUT(vsi.TransferCharacteristics);
OUT(vsi.MatrixCoefficients);
break;
case MFX_EXTBUFF_CODING_OPTION:
OUT(co.RateDistortionOpt);
OUT(co.MECostType);
OUT(co.MESearchType);
OUT(co.MVSearchWindow.x);
OUT(co.MVSearchWindow.y);
OUT(co.EndOfSequence);
OUT(co.FramePicture);
OUT(co.CAVLC);
OUT(co.RecoveryPointSEI);
OUT(co.ViewOutput);
OUT(co.NalHrdConformance);
OUT(co.SingleSeiNalUnit);
OUT(co.VuiVclHrdParameters);
OUT(co.RefPicListReordering);
OUT(co.ResetRefList);
OUT(co.RefPicMarkRep);
OUT(co.FieldOutput);
OUT(co.IntraPredBlockSize);
OUT(co.InterPredBlockSize);
OUT(co.MVPrecision);
OUT(co.MaxDecFrameBuffering);
OUT(co.AUDelimiter);
OUT(co.EndOfStream);
OUT(co.PicTimingSEI);
OUT(co.VuiNalHrdParameters);
break;
case MFX_EXTBUFF_CODING_OPTION2:
OUT(co2.IntRefType);
OUT(co2.IntRefCycleSize);
OUT(co2.IntRefQPDelta);
OUT(co2.MaxFrameSize);
OUT(co2.MaxSliceSize);
OUT(co2.BitrateLimit);
OUT(co2.MBBRC);
OUT(co2.ExtBRC);
OUT(co2.LookAheadDepth);
OUT(co2.Trellis);
OUT(co2.RepeatPPS);
OUT(co2.BRefType);
OUT(co2.AdaptiveI);
OUT(co2.AdaptiveB);
OUT(co2.LookAheadDS);
OUT(co2.NumMbPerSlice);
OUT(co2.SkipFrame);
OUT(co2.MinQPI);
OUT(co2.MaxQPI);
OUT(co2.MinQPP);
OUT(co2.MaxQPP);
OUT(co2.MinQPB);
OUT(co2.MaxQPB);
OUT(co2.FixedFrameRate);
OUT(co2.DisableDeblockingIdc);
break;
}
}
log_file << '\n';
}