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+.master
parent
2697fa9893
commit
0b0b5d28e6
|
@ -102,7 +102,7 @@ struct Encoder
|
|||
, using_d3d11(false), session(), encoder(session), event_prefix(event_prefix), encoder_flushed(event_prefix + ENCODER_FLUSHED), flushed(false), log_file(log_file)
|
||||
{
|
||||
params.Init(init_req->target_usage, init_req->profile, init_req->fps, init_req->keyint, init_req->bframes, init_req->width, init_req->height, init_req->max_bitrate,
|
||||
init_req->buffer_size, init_req->use_cbr);
|
||||
init_req->buffer_size, init_req->use_cbr, init_req->use_custom_parameters, init_req->custom_parameters, init_req->la_depth);
|
||||
params.SetVideoSignalInfo(init_req->full_range, init_req->primaries, init_req->transfer, init_req->matrix);
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,8 @@ struct Encoder
|
|||
Parameters query = params;
|
||||
encoder.GetVideoParam(query);
|
||||
|
||||
init_res->rate_control = query->mfx.RateControlMethod;
|
||||
|
||||
switch (query->mfx.CodecProfile)
|
||||
{
|
||||
case MFX_PROFILE_AVC_BASELINE:
|
||||
|
|
|
@ -31,7 +31,9 @@ struct init_request
|
|||
uint32_t obs_process_id;
|
||||
uint16_t target_usage, profile;
|
||||
int32_t fps, keyint, bframes, width, height, max_bitrate, buffer_size;
|
||||
bool use_cbr;
|
||||
bool use_cbr, use_custom_parameters;
|
||||
mfxInfoMFX custom_parameters;
|
||||
decltype(mfxExtCodingOption2::LookAheadDepth) la_depth;
|
||||
int32_t full_range, matrix, primaries, transfer;
|
||||
bool use_custom_impl;
|
||||
mfxVersion custom_version;
|
||||
|
@ -44,6 +46,7 @@ struct init_response
|
|||
mfxVersion version;
|
||||
mfxIMPL requested_impl,
|
||||
actual_impl;
|
||||
decltype(mfxInfoMFX::RateControlMethod) rate_control;
|
||||
|
||||
bool using_custom_impl;
|
||||
|
||||
|
|
|
@ -80,20 +80,48 @@ Parameters &Parameters::operator =(const Parameters& o)
|
|||
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)
|
||||
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.TargetKbps = saturate<mfxU16>(max_bitrate);
|
||||
params.mfx.MaxKbps = saturate<mfxU16>(max_bitrate);
|
||||
params.mfx.BufferSizeInKB = buffer_size/8;
|
||||
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.RateControlMethod = use_cbr ? MFX_RATECONTROL_CBR : MFX_RATECONTROL_VBR;
|
||||
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;
|
||||
|
|
|
@ -51,7 +51,8 @@ public:
|
|||
mfxVideoParam* operator->() { return ¶ms; }
|
||||
const mfxVideoParam* operator->() const { return ¶ms; }
|
||||
|
||||
void Init(mfxU16 preset, mfxU16 profile, int fps, int keyframe_interval_frames, int bframes, int width, int height, int max_bitrate, int buffer_size, bool use_cbr);
|
||||
void Init(mfxU16 preset, 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);
|
||||
void SetCodingOptionSPSPPS(mfxU8 *sps_buff, mfxU16 sps_size, mfxU8 *pps_buff, mfxU16 pps_size);
|
||||
void SetVideoSignalInfo(int full_range, int primaries, int transfer, int matrix);
|
||||
void AddCodingOption();
|
||||
|
|
|
@ -52,7 +52,7 @@ void InitFrame(mfxFrameData &frame, mfxU8 *Y, mfxU8 *UV, mfxU8 *V, mfxU16 pitch)
|
|||
frame.Pitch = pitch;
|
||||
}
|
||||
|
||||
std::vector<mfxU8> InitSEIUserData(bool use_cbr, const mfxVideoParam& params, const mfxVersion& ver)
|
||||
std::vector<mfxU8> InitSEIUserData(bool use_cbr, const Parameters& params, const mfxVersion& ver)
|
||||
{
|
||||
#define TO_STR(x) #x
|
||||
static const char *usage_str[] = {
|
||||
|
@ -66,6 +66,24 @@ std::vector<mfxU8> InitSEIUserData(bool use_cbr, const mfxVideoParam& params, co
|
|||
TO_STR(MFX_TARGETUSAGE_BEST_SPEED)
|
||||
};
|
||||
#undef TO_STR
|
||||
|
||||
#define RATE_CONTROL(x) {MFX_RATECONTROL_##x, #x}
|
||||
struct
|
||||
{
|
||||
decltype(mfxInfoMFX::RateControlMethod) method;
|
||||
const char* name;
|
||||
} rate_control_str[] = {
|
||||
RATE_CONTROL(CBR),
|
||||
RATE_CONTROL(VBR),
|
||||
RATE_CONTROL(CQP),
|
||||
RATE_CONTROL(AVBR),
|
||||
RATE_CONTROL(LA),
|
||||
RATE_CONTROL(ICQ),
|
||||
RATE_CONTROL(VCM),
|
||||
RATE_CONTROL(LA_ICQ),
|
||||
};
|
||||
#undef RATE_CONTROL
|
||||
|
||||
using namespace std;
|
||||
vector<mfxU8> data;
|
||||
|
||||
|
@ -73,14 +91,59 @@ std::vector<mfxU8> InitSEIUserData(bool use_cbr, const mfxVideoParam& params, co
|
|||
0x90, 0x24, 0x00, 0x50, 0xc2, 0x49, 0x00, 0x48 }; //6d1a26a0-bddc-11e2-9024-0050c2490048
|
||||
data.insert(end(data), begin(UUID), end(UUID));
|
||||
|
||||
auto method = params->mfx.RateControlMethod;
|
||||
|
||||
const char *name = "UKNOWN";
|
||||
for (const auto &names : rate_control_str)
|
||||
{
|
||||
if (names.method != method)
|
||||
continue;
|
||||
|
||||
name = names.name;
|
||||
break;
|
||||
}
|
||||
|
||||
ostringstream str;
|
||||
str << "QSV hardware encoder options:"
|
||||
<< " rate control: " << (use_cbr ? "cbr" : "vbr")
|
||||
<< "; target bitrate: " << params.mfx.TargetKbps
|
||||
<< "; max bitrate: " << params.mfx.MaxKbps
|
||||
<< "; buffersize: " << params.mfx.BufferSizeInKB * 8
|
||||
<< "; API level: " << ver.Major << "." << ver.Minor
|
||||
<< "; Target Usage: " << usage_str[params.mfx.TargetUsage];
|
||||
<< " rate control: " << name;
|
||||
switch (method)
|
||||
{
|
||||
case MFX_RATECONTROL_CBR:
|
||||
case MFX_RATECONTROL_VBR:
|
||||
case MFX_RATECONTROL_VCM:
|
||||
str << "; target bitrate: " << params->mfx.TargetKbps;
|
||||
if (method != MFX_RATECONTROL_CBR)
|
||||
str << "; max bitrate: " << params->mfx.MaxKbps;
|
||||
str << "; buffersize: " << params->mfx.BufferSizeInKB * 8;
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_AVBR:
|
||||
str << "; target bitrate: " << params->mfx.TargetKbps
|
||||
<< "; accuracy: " << params->mfx.Accuracy
|
||||
<< "; convergence: " << params->mfx.Convergence;
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_CQP:
|
||||
str << "; QPI: " << params->mfx.QPI
|
||||
<< "; QPP: " << params->mfx.QPP
|
||||
<< "; QPB: " << params->mfx.QPB;
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_LA:
|
||||
str << "; target bitrate: " << params->mfx.TargetKbps
|
||||
<< "; look ahead: " << params.co2.LookAheadDepth;
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_ICQ:
|
||||
case MFX_RATECONTROL_LA_ICQ:
|
||||
str << "; ICQQuality: " << params->mfx.ICQQuality;
|
||||
if (method == MFX_RATECONTROL_LA_ICQ)
|
||||
str << "; look ahead: " << params.co2.LookAheadDepth;
|
||||
break;
|
||||
}
|
||||
str << "; API level: " << ver.Major << "." << ver.Minor
|
||||
<< "; Target Usage: " << usage_str[params->mfx.TargetUsage];
|
||||
|
||||
string str_(str.str());
|
||||
|
||||
data.insert(end(data), begin(str_), end(str_));
|
||||
|
|
|
@ -42,3 +42,39 @@ static inline T saturate(U val)
|
|||
return std::numeric_limits<T>::min();
|
||||
return val;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
static inline void saturate(T &t, U val)
|
||||
{
|
||||
if (val > std::numeric_limits<T>::max())
|
||||
t = std::numeric_limits<T>::max();
|
||||
else if (val < std::numeric_limits<T>::min())
|
||||
t = std::numeric_limits<T>::min();
|
||||
else
|
||||
t = static_cast<T>(val);
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename V>
|
||||
static inline T clamp(T t, U u, V v)
|
||||
{
|
||||
if (t < u)
|
||||
return u;
|
||||
return t > v ? v : t;
|
||||
}
|
||||
|
||||
static bool valid_method(decltype(mfxInfoMFX::RateControlMethod) method)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case MFX_RATECONTROL_CBR:
|
||||
case MFX_RATECONTROL_VBR:
|
||||
case MFX_RATECONTROL_CQP:
|
||||
case MFX_RATECONTROL_AVBR:
|
||||
case MFX_RATECONTROL_LA:
|
||||
case MFX_RATECONTROL_ICQ:
|
||||
case MFX_RATECONTROL_VCM:
|
||||
case MFX_RATECONTROL_LA_ICQ:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,24 @@ namespace
|
|||
TO_STR(MFX_TARGETUSAGE_7_BEST_SPEED)
|
||||
};
|
||||
|
||||
#define RATE_CONTROL(x, cq) {MFX_RATECONTROL_##x, #x, cq}
|
||||
struct
|
||||
{
|
||||
decltype(mfxInfoMFX::RateControlMethod) method;
|
||||
const char* name;
|
||||
bool cq;
|
||||
} rate_control_str[] = {
|
||||
RATE_CONTROL(CBR, false),
|
||||
RATE_CONTROL(VBR, false),
|
||||
RATE_CONTROL(CQP, true),
|
||||
RATE_CONTROL(AVBR, false),
|
||||
RATE_CONTROL(LA, false),
|
||||
RATE_CONTROL(ICQ, true),
|
||||
RATE_CONTROL(VCM, false),
|
||||
RATE_CONTROL(LA_ICQ, true),
|
||||
};
|
||||
#undef RATE_CONTROL
|
||||
|
||||
CTSTR qsv_intf_str(const mfxU32 impl)
|
||||
{
|
||||
switch(impl & (-MFX_IMPL_VIA_ANY))
|
||||
|
@ -325,6 +343,26 @@ bool CheckQSVHardwareSupport(bool log=true, bool *configurationWarning = nullptr
|
|||
return false;
|
||||
}
|
||||
|
||||
bool QSVMethodAvailable(decltype(mfxInfoMFX::RateControlMethod) method)
|
||||
{
|
||||
static qsv_cpu_platform plat = qsv_get_cpu_platform();
|
||||
switch (method)
|
||||
{
|
||||
case MFX_RATECONTROL_CBR:
|
||||
case MFX_RATECONTROL_VBR:
|
||||
case MFX_RATECONTROL_AVBR:
|
||||
case MFX_RATECONTROL_CQP:
|
||||
return plat != QSV_CPU_PLATFORM_UNKNOWN;
|
||||
|
||||
case MFX_RATECONTROL_VCM:
|
||||
case MFX_RATECONTROL_LA:
|
||||
case MFX_RATECONTROL_ICQ:
|
||||
case MFX_RATECONTROL_LA_ICQ:
|
||||
return plat >= QSV_CPU_PLATFORM_HSW;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct VideoPacket
|
||||
{
|
||||
List<BYTE> Packet;
|
||||
|
@ -372,6 +410,7 @@ class QSVEncoder : public VideoEncoder
|
|||
|
||||
mfxU16 target_usage, profile,
|
||||
max_bitrate;
|
||||
decltype(mfxInfoMFX::RateControlMethod) rate_control;
|
||||
|
||||
String event_prefix;
|
||||
|
||||
|
@ -505,6 +544,51 @@ public:
|
|||
|
||||
ipc_init_request request((event_prefix + INIT_REQUEST).Array());
|
||||
|
||||
if (AppConfig->GetInt(L"QSV (Advanced)", L"UseCustomParams"))
|
||||
{
|
||||
Log(L"QSV: Using custom parameters");
|
||||
request->use_custom_parameters = true;
|
||||
auto &mfx = request->custom_parameters;
|
||||
mfx.RateControlMethod = AppConfig->GetInt(L"QSV (Advanced)", L"RateControlMethod", MFX_RATECONTROL_VBR);
|
||||
if (!valid_method(mfx.RateControlMethod))
|
||||
mfx.RateControlMethod = MFX_RATECONTROL_VBR;
|
||||
|
||||
auto load_int = [&](CTSTR name, int def) { return AppConfig->GetInt(L"QSV (Advanced)", name, def); };
|
||||
|
||||
bool use_global_bitrate = !!load_int(L"UseGlobalBitrate", true);
|
||||
bool use_global_buffer = !!load_int(L"UseGlobalBufferSize", true);
|
||||
|
||||
mfx.TargetKbps = use_global_bitrate ? maxBitrate : load_int(L"TargetKbps", 1000);
|
||||
mfx.BufferSizeInKB = use_global_buffer ? (bufferSize / 8) : load_int(L"BufferSizeInKB", 0);
|
||||
|
||||
switch (mfx.RateControlMethod)
|
||||
{
|
||||
case MFX_RATECONTROL_VBR:
|
||||
case MFX_RATECONTROL_VCM:
|
||||
mfx.MaxKbps = load_int(L"MaxKbps", 0);
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_AVBR:
|
||||
mfx.Accuracy = clamp(load_int(L"Accuracy", 1000), 0, 1000);
|
||||
mfx.Convergence = load_int(L"Convergence", 1);
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_CQP:
|
||||
mfx.QPI = clamp(load_int(L"QPI", 23), 1, 51);
|
||||
mfx.QPP = clamp(load_int(L"QPP", 23), 1, 51);
|
||||
mfx.QPB = clamp(load_int(L"QPB", 23), 1, 51);
|
||||
break;
|
||||
|
||||
case MFX_RATECONTROL_ICQ:
|
||||
case MFX_RATECONTROL_LA_ICQ:
|
||||
mfx.ICQQuality = clamp(load_int(L"ICQQuality", 23), 1, 51);
|
||||
case MFX_RATECONTROL_LA:
|
||||
request->la_depth = load_int(L"LADepth", 40);
|
||||
if (request->la_depth != 0)
|
||||
request->la_depth = clamp(request->la_depth, 10, 100);
|
||||
}
|
||||
}
|
||||
|
||||
request->mode = request->MODE_ENCODE;
|
||||
request->obs_process_id = GetCurrentProcessId();
|
||||
|
||||
|
@ -549,6 +633,11 @@ public:
|
|||
CrashError(TEXT("QSVHelper.exe could not find a valid configuration. Make sure you have a (virtual) display connected to your iGPU")); //FIXME: convert to localized error
|
||||
CrashError(TEXT("QSVHelper.exe could not find a valid configuration"));
|
||||
default:
|
||||
if (code == EXIT_ENCODER_INIT_FAILED && request->use_custom_parameters)
|
||||
{
|
||||
Log(L"Encoder initialization failed with code %i while using custom parameters", code);
|
||||
throw Str("Encoder.QSV.InitCustomParamsFailed");
|
||||
}
|
||||
CrashError(TEXT("QSVHelper.exe has exited with code %i (before response)"), code); //FIXME: convert to localized error
|
||||
}
|
||||
}
|
||||
|
@ -569,6 +658,7 @@ public:
|
|||
|
||||
target_usage = response->target_usage;
|
||||
profile = response->profile;
|
||||
rate_control = response->rate_control;
|
||||
|
||||
encode_tasks.SetSize(response->bitstream_num);
|
||||
|
||||
|
@ -1088,6 +1178,16 @@ public:
|
|||
{
|
||||
String strInfo;
|
||||
|
||||
const char* name = "UNKNOWN";
|
||||
for (auto &names : rate_control_str)
|
||||
{
|
||||
if (names.method != rate_control)
|
||||
continue;
|
||||
|
||||
name = names.name;
|
||||
break;
|
||||
}
|
||||
|
||||
strInfo << TEXT("Video Encoding: QSV") <<
|
||||
TEXT("\r\n fps: ") << IntString(fps) <<
|
||||
TEXT("\r\n width: ") << IntString(width) << TEXT(", height: ") << IntString(height) <<
|
||||
|
@ -1095,12 +1195,9 @@ public:
|
|||
TEXT("\r\n profile: ") << qsv_profile_str(profile) <<
|
||||
TEXT("\r\n CBR: ") << CTSTR((bUseCBR) ? TEXT("yes") : TEXT("no")) <<
|
||||
TEXT("\r\n CFR: ") << CTSTR((bUseCFR) ? TEXT("yes") : TEXT("no")) <<
|
||||
TEXT("\r\n max bitrate: ") << IntString(max_bitrate);
|
||||
|
||||
if(!bUseCBR)
|
||||
{
|
||||
strInfo << TEXT("\r\n buffer size: ") << IntString(encode_tasks[0].bs.MaxLength*8/1000);
|
||||
}
|
||||
TEXT("\r\n max bitrate: ") << IntString(max_bitrate) <<
|
||||
TEXT("\r\n buffer size: ") << IntString(encode_tasks[0].bs.MaxLength * 8 / 1000) <<
|
||||
TEXT("\r\n rate control: ") << name;
|
||||
|
||||
return strInfo;
|
||||
}
|
||||
|
@ -1163,5 +1260,17 @@ VideoEncoder* CreateQSVEncoder(int fps, int width, int height, int quality, CTST
|
|||
}
|
||||
}
|
||||
|
||||
return new QSVEncoder(fps, width, height, quality, preset, bUse444, colorDesc, maxBitRate, bufferSize, bUseCFR);
|
||||
try
|
||||
{
|
||||
return new QSVEncoder(fps, width, height, quality, preset, bUse444, colorDesc, maxBitRate, bufferSize, bUseCFR);
|
||||
}
|
||||
catch (CTSTR str)
|
||||
{
|
||||
errors << str;
|
||||
return nullptr;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CrashError(L"Caught unhandled exception");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue