obs/QSVHelper/QSVStuff.cpp

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 = saturate<mfxU16>(use_custom_params ? custom_params.TargetKbps : max_bitrate);
params.mfx.BufferSizeInKB = use_custom_params ? custom_params.BufferSizeInKB : buffer_size / 8;
params.mfx.RateControlMethod = use_custom_params ? custom_params.RateControlMethod : use_cbr ? MFX_RATECONTROL_CBR : 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';
}