hb_qsv_param_t param;
av_qsv_space enc_space;
+ hb_qsv_info_t *qsv_info;
mfxEncodeCtrl force_keyframe;
hb_list_t *delayed_chapters;
pv->job = job;
pv->is_sys_mem = !hb_qsv_decode_is_enabled(job);
+ pv->qsv_info = hb_qsv_info_get(job->vcodec);
pv->delayed_processing = hb_list_init();
pv->last_start = INT64_MIN;
pv->frames_in = 0;
// default encoding parameters
if (hb_qsv_param_default_preset(&pv->param, &pv->enc_space.m_mfxVideoParam,
- job->encoder_preset))
+ pv->qsv_info, job->encoder_preset))
{
hb_error("encqsvInit: hb_qsv_param_default_preset failed");
return -1;
options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec);
while ((option = hb_dict_next(options_list, option)) != NULL)
{
- switch (hb_qsv_param_parse(&pv->param,
- option->key, option->value, job->vcodec))
+ switch (hb_qsv_param_parse(&pv->param, pv->qsv_info,
+ option->key, option->value))
{
case HB_QSV_PARAM_OK:
break;
hb_error("encqsvInit: bad level %s", job->encoder_level);
return -1;
}
- else if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
+ else if (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
{
pv->param.videoParam->mfx.CodecLevel = HB_QSV_CLIP3(MFX_LEVEL_AVC_1,
MFX_LEVEL_AVC_52,
}
}
- // set rate control paremeters
- if (job->vquality >= 0)
+ // sanitize ICQ
+ if (!(pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_ICQ))
{
- // introduced in API 1.1
- pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CQP;
- pv->param.videoParam->mfx.QPI = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[0]);
- pv->param.videoParam->mfx.QPP = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[1]);
- pv->param.videoParam->mfx.QPB = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[2]);
- // CQP + ExtBRC can cause bad output
- pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF;
+ // ICQ not supported
+ pv->param.rc.icq = 0;
}
- else if (job->vbitrate > 0)
+ else
+ {
+ pv->param.rc.icq = !!pv->param.rc.icq;
+ }
+
+ // sanitize lookahead
+ if (!(pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_LA))
+ {
+ // lookahead not supported
+ pv->param.rc.lookahead = 0;
+ }
+ else if ((pv->param.rc.lookahead) &&
+ (pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_LAi) == 0 &&
+ (pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE))
{
- // sanitize lookahead
- if (!(hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD))
+ // lookahead enabled but we can't use it
+ hb_log("encqsvInit: LookAhead not used (LookAhead is progressive-only)");
+ pv->param.rc.lookahead = 0;
+ }
+ else
+ {
+ pv->param.rc.lookahead = !!pv->param.rc.lookahead;
+ }
+
+ // set VBV here (this will be overridden for CQP and ignored for LA)
+ // only set BufferSizeInKB, InitialDelayInKB and MaxKbps if we have
+ // them - otheriwse Media SDK will pick values for us automatically
+ if (pv->param.rc.vbv_buffer_size > 0)
+ {
+ if (pv->param.rc.vbv_buffer_init > 1.0)
+ {
+ pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_init / 8);
+ }
+ else if (pv->param.rc.vbv_buffer_init > 0.0)
{
- // lookahead not supported
- pv->param.rc.lookahead = 0;
+ pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_size *
+ pv->param.rc.vbv_buffer_init / 8);
}
- else if (pv->param.rc.lookahead &&
- pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE)
+ pv->param.videoParam->mfx.BufferSizeInKB = (pv->param.rc.vbv_buffer_size / 8);
+ }
+ if (pv->param.rc.vbv_max_bitrate > 0)
+ {
+ pv->param.videoParam->mfx.MaxKbps = pv->param.rc.vbv_max_bitrate;
+ }
+
+ // set rate control paremeters
+ if (job->vquality >= 0)
+ {
+ if (pv->param.rc.icq)
{
- // lookahead enabled but we can't use it
- hb_log("encqsvInit: MFX_RATECONTROL_LA not used (LookAhead is progressive-only)");
- pv->param.rc.lookahead = 0;
+ // introduced in API 1.8
+ if (pv->param.rc.lookahead)
+ {
+ pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_LA_ICQ;
+ }
+ else
+ {
+ pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_ICQ;
+ }
+ pv->param.videoParam->mfx.ICQQuality = HB_QSV_CLIP3(1, 51, job->vquality);
}
else
{
- pv->param.rc.lookahead = !!pv->param.rc.lookahead;
+ // introduced in API 1.1
+ pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CQP;
+ pv->param.videoParam->mfx.QPI = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[0]);
+ pv->param.videoParam->mfx.QPP = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[1]);
+ pv->param.videoParam->mfx.QPB = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[2]);
+ // CQP + ExtBRC can cause bad output
+ pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF;
}
+ }
+ else if (job->vbitrate > 0)
+ {
if (pv->param.rc.lookahead)
{
// introduced in API 1.7
pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_LA;
pv->param.videoParam->mfx.TargetKbps = job->vbitrate;
- if (pv->param.rc.vbv_max_bitrate > 0 ||
- pv->param.rc.vbv_buffer_size > 0)
- {
- hb_log("encqsvInit: MFX_RATECONTROL_LA, ignoring VBV");
- }
// ignored, but some drivers will change AsyncDepth because of it
pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF;
}
{
pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_VBR;
}
- // only set BufferSizeInKB, InitialDelayInKB and MaxKbps if we have
- // them - otheriwse Media SDK will pick values for us automatically
- if (pv->param.rc.vbv_buffer_size > 0)
- {
- if (pv->param.rc.vbv_buffer_init > 1.0)
- {
- pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_init / 8);
- }
- else if (pv->param.rc.vbv_buffer_init > 0.0)
- {
- pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_size *
- pv->param.rc.vbv_buffer_init / 8);
- }
- pv->param.videoParam->mfx.BufferSizeInKB = (pv->param.rc.vbv_buffer_size / 8);
- }
- if (pv->param.rc.vbv_max_bitrate > 0)
- {
- pv->param.videoParam->mfx.MaxKbps = pv->param.rc.vbv_max_bitrate;
- }
pv->param.videoParam->mfx.TargetKbps = job->vbitrate;
}
}
return -1;
}
+ // if VBV is enabled but ignored, log it
+ if (pv->param.rc.vbv_max_bitrate > 0 || pv->param.rc.vbv_buffer_size > 0)
+ {
+ switch (pv->param.videoParam->mfx.RateControlMethod)
+ {
+ case MFX_RATECONTROL_LA:
+ case MFX_RATECONTROL_LA_ICQ:
+ hb_log("encqsvInit: LookAhead enabled, ignoring VBV");
+ break;
+ case MFX_RATECONTROL_ICQ:
+ hb_log("encqsvInit: ICQ rate control, ignoring VBV");
+ break;
+ default:
+ break;
+ }
+ }
+
// set B-pyramid
if (pv->param.gop.b_pyramid < 0)
{
pv->param.rc.lookahead ? 60 : 0);
}
- if ((hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID) &&
+ if ((pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID) &&
(pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_BASELINE &&
pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_CONSTRAINED_HIGH &&
pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_CONSTRAINED_BASELINE))
mfxExtCodingOptionSPSPPS sps_pps_buf, *sps_pps = &sps_pps_buf;
version.Major = HB_QSV_MINVERSION_MAJOR;
version.Minor = HB_QSV_MINVERSION_MINOR;
- err = MFXInit(hb_qsv_impl_get_preferred(), &version, &session);
+ err = MFXInit(pv->qsv_info->implementation, &version, &session);
if (err != MFX_ERR_NONE)
{
hb_error("encqsvInit: MFXInit failed (%d)", err);
memset(option2, 0, sizeof(mfxExtCodingOption2));
option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
option2->Header.BufferSz = sizeof(mfxExtCodingOption2);
- if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
{
// attach to get the final output mfxExtCodingOption2 settings
videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)option2;
// let the muxer know whether to expect B-frames or not
job->areBframes = !!pv->bfrm_delay;
// check whether we need to generate DTS ourselves (MSDK API < 1.6 or VFR)
- pv->bfrm_workaround = job->cfr != 1 || !(hb_qsv_info->capabilities &
+ pv->bfrm_workaround = job->cfr != 1 || !(pv->qsv_info->capabilities &
HB_QSV_CAP_MSDK_API_1_6);
if (pv->bfrm_delay && pv->bfrm_workaround)
{
videoParam.mfx.TargetUsage, videoParam.AsyncDepth);
hb_log("encqsvInit: GopRefDist %"PRIu16" GopPicSize %"PRIu16" NumRefFrame %"PRIu16"",
videoParam.mfx.GopRefDist, videoParam.mfx.GopPicSize, videoParam.mfx.NumRefFrame);
- if (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
{
hb_log("encqsvInit: BFrames %s BPyramid %s",
pv->bfrm_delay ? "on" : "off",
{
hb_log("encqsvInit: BFrames %s", pv->bfrm_delay ? "on" : "off");
}
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
+ {
+ if (pv->bfrm_delay > 0)
+ {
+ hb_log("encqsvInit: AdaptiveI %s AdaptiveB %s",
+ hb_qsv_codingoption_get_name(option2->AdaptiveI),
+ hb_qsv_codingoption_get_name(option2->AdaptiveB));
+ }
+ else
+ {
+ hb_log("encqsvInit: AdaptiveI %s",
+ hb_qsv_codingoption_get_name(option2->AdaptiveI));
+ }
+ }
if (videoParam.mfx.RateControlMethod == MFX_RATECONTROL_CQP)
{
char qpi[7], qpp[9], qpb[9];
hb_log("encqsvInit: RateControlMethod LA TargetKbps %"PRIu16" LookAheadDepth %"PRIu16"",
videoParam.mfx.TargetKbps, option2->LookAheadDepth);
break;
+ case MFX_RATECONTROL_LA_ICQ:
+ hb_log("encqsvInit: RateControlMethod LA_ICQ ICQQuality %"PRIu16" LookAheadDepth %"PRIu16"",
+ videoParam.mfx.ICQQuality, option2->LookAheadDepth);
+ break;
+ case MFX_RATECONTROL_ICQ:
+ hb_log("encqsvInit: RateControlMethod ICQ ICQQuality %"PRIu16"",
+ videoParam.mfx.ICQQuality);
+ break;
case MFX_RATECONTROL_CBR:
case MFX_RATECONTROL_VBR:
hb_log("encqsvInit: RateControlMethod %s TargetKbps %"PRIu16" MaxKbps %"PRIu16" BufferSizeInKB %"PRIu16" InitialDelayInKB %"PRIu16"",
return -1;
}
}
+ if ((pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_LA_DOWNS) &&
+ (videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA ||
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA_ICQ))
+ {
+ switch (option2->LookAheadDS)
+ {
+ case MFX_LOOKAHEAD_DS_UNKNOWN:
+ hb_log("encqsvInit: LookAheadDS unknown (auto)");
+ break;
+ case MFX_LOOKAHEAD_DS_OFF:
+ hb_log("encqsvInit: LookAheadDS off");
+ break;
+ case MFX_LOOKAHEAD_DS_2x:
+ hb_log("encqsvInit: LookAheadDS 2x");
+ break;
+ case MFX_LOOKAHEAD_DS_4x:
+ hb_log("encqsvInit: LookAheadDS 4x");
+ break;
+ default:
+ hb_log("encqsvInit: invalid LookAheadDS value 0x%"PRIx16"",
+ option2->LookAheadDS);
+ break;
+ }
+ }
switch (videoParam.mfx.FrameInfo.PicStruct)
{
// quiet, most people don't care
}
hb_log("encqsvInit: CAVLC %s",
hb_qsv_codingoption_get_name(option1->CAVLC));
- if (videoParam.mfx.RateControlMethod != MFX_RATECONTROL_LA &&
+ if (pv->param.rc.lookahead == 0 &&
videoParam.mfx.RateControlMethod != MFX_RATECONTROL_CQP)
{
// LA/CQP and ExtBRC/MBBRC are mutually exclusive
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
{
hb_log("encqsvInit: ExtBRC %s",
hb_qsv_codingoption_get_name(option2->ExtBRC));
}
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
{
hb_log("encqsvInit: MBBRC %s",
hb_qsv_codingoption_get_name(option2->MBBRC));
}
}
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
{
switch (option2->Trellis)
{
buf->s.duration = duration;
if (pv->bfrm_delay)
{
- if ((pv->frames_out == 0) &&
- (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) &&
- (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID))
+ if ((pv->frames_out == 0) &&
+ (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) &&
+ (pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID))
{
// with B-pyramid, the delay may be more than 1 frame,
// so compute the actual delay based on the initial DTS
#ifdef USE_QSV
+#include <stdio.h>
+
#include "hb.h"
#include "ports.h"
#include "common.h"
#include "qsv_common.h"
#include "h264_common.h"
-// for x264_vidformat_names etc.
-#include "x264.h"
-
-// avoids a warning
-#include "libavutil/cpu.h"
-extern void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx);
-
-// make the Intel QSV information available to the UIs
-hb_qsv_info_t *hb_qsv_info = NULL;
-
-// availability and versions
-static mfxIMPL preferred_implementation;
-static mfxVersion qsv_hardware_version;
-static mfxVersion qsv_software_version;
-static mfxVersion qsv_minimum_version;
-static int qsv_hardware_available = 0;
-static int qsv_software_available = 0;
+// QSV info for each codec
+static hb_qsv_info_t *hb_qsv_info_avc = NULL;
+static hb_qsv_info_t *hb_qsv_info_hevc = NULL;
+// API versions
+static mfxVersion qsv_software_version = { .Version = 0, };
+static mfxVersion qsv_hardware_version = { .Version = 0, };
+// AVC implementations
+static hb_qsv_info_t qsv_software_info_avc = { .available = 0, .codec_id = MFX_CODEC_AVC, .implementation = MFX_IMPL_SOFTWARE, };
+static hb_qsv_info_t qsv_hardware_info_avc = { .available = 0, .codec_id = MFX_CODEC_AVC, .implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY, };
+// HEVC implementations
+static mfxPluginUID qsv_encode_plugin_hevc = { .Data = { 0x2F, 0xCA, 0x99, 0x74, 0x9F, 0xDB, 0x49, 0xAE, 0xB1, 0x21, 0xA5, 0xB6, 0x3E, 0xF5, 0x68, 0xF7 } };
+static hb_qsv_info_t qsv_software_info_hevc = { .available = 0, .codec_id = MFX_CODEC_HEVC, .implementation = MFX_IMPL_SOFTWARE, };
+static hb_qsv_info_t qsv_hardware_info_hevc = { .available = 0, .codec_id = MFX_CODEC_HEVC, .implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY, };
// check available Intel Media SDK version against a minimum
#define HB_CHECK_MFX_VERSION(MFX_VERSION, MAJOR, MINOR) \
(MFX_VERSION.Major == MAJOR && MFX_VERSION.Minor >= MINOR)
+/*
+ * Determine the "generation" of QSV hardware based on the CPU microarchitecture.
+ * Anything unknown is assumed to be more recent than the latest known generation.
+ * This avoids having to order the hb_cpu_platform enum depending on QSV hardware.
+ */
+enum
+{
+ QSV_G0, // third party hardware
+ QSV_G1, // Sandy Bridge or equivalent
+ QSV_G2, // Ivy Bridge or equivalent
+ QSV_G3, // Haswell or equivalent
+};
+static int qsv_hardware_generation(int cpu_platform)
+{
+ switch (cpu_platform)
+ {
+ case HB_CPU_PLATFORM_INTEL_BNL:
+ return QSV_G0;
+ case HB_CPU_PLATFORM_INTEL_SNB:
+ return QSV_G1;
+ case HB_CPU_PLATFORM_INTEL_IVB:
+ case HB_CPU_PLATFORM_INTEL_SLM:
+ return QSV_G2;
+ case HB_CPU_PLATFORM_INTEL_HSW:
+ default:
+ return QSV_G3;
+ }
+}
+
+/*
+ * Determine whether a given mfxIMPL is hardware-accelerated.
+ */
+static int qsv_implementation_is_hardware(mfxIMPL implementation)
+{
+ return MFX_IMPL_BASETYPE(implementation) != MFX_IMPL_SOFTWARE;
+}
+
int hb_qsv_available()
{
- return hb_qsv_info != NULL && (qsv_hardware_available ||
- qsv_software_available);
+ return hb_qsv_video_encoder_is_enabled(HB_VCODEC_QSV_H264);
}
-int hb_qsv_info_init()
+int hb_qsv_video_encoder_is_enabled(int encoder)
{
- static int init_done = 0;
- if (init_done)
- return (hb_qsv_info == NULL);
- init_done = 1;
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_qsv_info_avc != NULL && hb_qsv_info_avc->available;
+ default:
+ return 0;
+ }
+}
- hb_qsv_info = calloc(1, sizeof(*hb_qsv_info));
- if (hb_qsv_info == NULL)
+int hb_qsv_audio_encoder_is_enabled(int encoder)
+{
+ switch (encoder)
{
- hb_error("hb_qsv_info_init: alloc failure");
- return -1;
+ default:
+ return 0;
}
+}
- mfxSession session;
- qsv_minimum_version.Major = HB_QSV_MINVERSION_MAJOR;
- qsv_minimum_version.Minor = HB_QSV_MINVERSION_MINOR;
+static void init_video_param(mfxVideoParam *videoParam)
+{
+ if (videoParam == NULL)
+ {
+ return;
+ }
- // check for software fallback
- if (MFXInit(MFX_IMPL_SOFTWARE,
- &qsv_minimum_version, &session) == MFX_ERR_NONE)
+ memset(videoParam, 0, sizeof(mfxVideoParam));
+ videoParam->mfx.CodecId = MFX_CODEC_AVC;
+ videoParam->mfx.CodecLevel = MFX_LEVEL_UNKNOWN;
+ videoParam->mfx.CodecProfile = MFX_PROFILE_UNKNOWN;
+ videoParam->mfx.RateControlMethod = MFX_RATECONTROL_VBR;
+ videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;
+ videoParam->mfx.TargetKbps = 5000;
+ videoParam->mfx.GopOptFlag = MFX_GOP_CLOSED;
+ videoParam->mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
+ videoParam->mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
+ videoParam->mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
+ videoParam->mfx.FrameInfo.FrameRateExtN = 25;
+ videoParam->mfx.FrameInfo.FrameRateExtD = 1;
+ videoParam->mfx.FrameInfo.Width = 1920;
+ videoParam->mfx.FrameInfo.CropW = 1920;
+ videoParam->mfx.FrameInfo.AspectRatioW = 1;
+ videoParam->mfx.FrameInfo.Height = 1088;
+ videoParam->mfx.FrameInfo.CropH = 1080;
+ videoParam->mfx.FrameInfo.AspectRatioH = 1;
+ videoParam->AsyncDepth = AV_QSV_ASYNC_DEPTH_DEFAULT;
+ videoParam->IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
+}
+
+static void init_ext_coding_option2(mfxExtCodingOption2 *extCodingOption2)
+{
+ if (extCodingOption2 == NULL)
{
- qsv_software_available = 1;
- preferred_implementation = MFX_IMPL_SOFTWARE;
- // our minimum is supported, but query the actual version
- MFXQueryVersion(session, &qsv_software_version);
- MFXClose(session);
+ return;
}
- // check for actual hardware support
- if (MFXInit(MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY,
- &qsv_minimum_version, &session) == MFX_ERR_NONE)
+ memset(extCodingOption2, 0, sizeof(mfxExtCodingOption2));
+ extCodingOption2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
+ extCodingOption2->Header.BufferSz = sizeof(mfxExtCodingOption2);
+ extCodingOption2->MBBRC = MFX_CODINGOPTION_ON;
+ extCodingOption2->ExtBRC = MFX_CODINGOPTION_ON;
+ extCodingOption2->Trellis = MFX_TRELLIS_I|MFX_TRELLIS_P|MFX_TRELLIS_B;
+ extCodingOption2->RepeatPPS = MFX_CODINGOPTION_ON;
+ extCodingOption2->BRefType = MFX_B_REF_PYRAMID;
+ extCodingOption2->AdaptiveI = MFX_CODINGOPTION_ON;
+ extCodingOption2->AdaptiveB = MFX_CODINGOPTION_ON;
+ extCodingOption2->LookAheadDS = MFX_LOOKAHEAD_DS_4x;
+ extCodingOption2->NumMbPerSlice = 2040; // 1920x1088/4
+}
+
+static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_info_t *info)
+{
+ /*
+ * MFXVideoENCODE_Query(mfxSession, mfxVideoParam *in, mfxVideoParam *out);
+ *
+ * Mode 1:
+ * - in is NULL
+ * - out has the parameters we want to query set to 1
+ * - out->mfx.CodecId field has to be set (mandatory)
+ * - MFXVideoENCODE_Query should zero out all unsupported parameters
+ *
+ * Mode 2:
+ * - the paramaters we want to query are set for in
+ * - in ->mfx.CodecId field has to be set (mandatory)
+ * - out->mfx.CodecId field has to be set (mandatory)
+ * - MFXVideoENCODE_Query should sanitize all unsupported parameters
+ */
+ mfxStatus status;
+ mfxPluginUID *pluginUID;
+ mfxExtBuffer *videoExtParam[1];
+ mfxVideoParam videoParam, inputParam;
+ mfxExtCodingOption2 extCodingOption2;
+
+ /* Reset capabilities before querying */
+ info->capabilities = 0;
+
+ /* Load optional codec plug-ins */
+ switch (info->codec_id)
+ {
+ case MFX_CODEC_HEVC:
+ pluginUID = &qsv_encode_plugin_hevc;
+ break;
+ default:
+ pluginUID = NULL;
+ break;
+ }
+ if (pluginUID != NULL && HB_CHECK_MFX_VERSION(version, 1, 8) &&
+ MFXVideoUSER_Load(session, pluginUID, 0) < MFX_ERR_NONE)
{
- // Cloverview (Bonnell microarchitecture) supports MSDK via third-party
- // hardware - we don't support this configuration for the time being
- if (hb_get_cpu_platform() != HB_CPU_PLATFORM_INTEL_BNL)
+ // couldn't load plugin successfully
+ return 0;
+ }
+
+ /*
+ * First of all, check availability of an encoder for
+ * this combination of a codec ID and implementation.
+ *
+ * Note: can error out rather than sanitizing
+ * unsupported codec IDs, so don't log errors.
+ */
+ if (HB_CHECK_MFX_VERSION(version, HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR))
+ {
+ if (info->implementation & MFX_IMPL_AUDIO)
{
- qsv_hardware_available = 1;
- preferred_implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY;
- // our minimum is supported, but query the actual version
- MFXQueryVersion(session, &qsv_hardware_version);
+ /* Not yet supported */
+ return 0;
+ }
+ else
+ {
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.CodecId == info->codec_id)
+ {
+ info->available = 1;
+ }
}
- MFXClose(session);
+ }
+ if (!info->available)
+ {
+ /* Don't check capabilities for unavailable encoders */
+ return 0;
}
- // check for version-specific or hardware-specific capabilities
- // we only use software as a fallback, so check hardware first
- if (qsv_hardware_available)
+ if (info->implementation & MFX_IMPL_AUDIO)
+ {
+ /* We don't have any audio capability checks yet */
+ return 0;
+ }
+ else
{
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 6))
+ /* Implementation-specific features that can't be queried */
+ if (qsv_implementation_is_hardware(info->implementation))
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_EXTBRC;
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ {
+ info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
+ }
}
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7))
+ else
{
- // we should really check the driver version, but since that's not
- // available here, checking the API version is the best we can do :-(
- hb_qsv_info->capabilities |= HB_QSV_CAP_CORE_COPYFRAME;
+ if (HB_CHECK_MFX_VERSION(version, 1, 6))
+ {
+ info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
+ }
}
- if (hb_get_cpu_platform() == HB_CPU_PLATFORM_INTEL_HSW)
+
+ /* API-specific features that can't be queried */
+ if (HB_CHECK_MFX_VERSION(version, 1, 6))
{
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 6))
+ // API >= 1.6 (mfxBitstream::DecodeTimeStamp, mfxExtCodingOption2)
+ info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
+ }
+
+ /*
+ * Check availability of optional rate control methods.
+ *
+ * Mode 2 tends to error out, but mode 1 gives false negatives, which
+ * is worse. So use mode 2 and assume an error means it's unsupported.
+ *
+ * Also assume that LA and ICQ combined imply LA_ICQ is
+ * supported, so we don't need to check the latter too.
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 7))
+ {
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+ inputParam.mfx.RateControlMethod = MFX_RATECONTROL_LA;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
+ {
+ info->capabilities |= HB_QSV_CAP_RATECONTROL_LA;
+
+ // also check for LA + interlaced support
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+ inputParam.mfx.RateControlMethod = MFX_RATECONTROL_LA;
+ inputParam.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.FrameInfo.PicStruct == MFX_PICSTRUCT_FIELD_TFF &&
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
+ {
+ info->capabilities |= HB_QSV_CAP_RATECONTROL_LAi;
+ }
+ }
+ }
+ if (HB_CHECK_MFX_VERSION(version, 1, 8))
+ {
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+ inputParam.mfx.RateControlMethod = MFX_RATECONTROL_ICQ;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_ICQ)
+ {
+ info->capabilities |= HB_QSV_CAP_RATECONTROL_ICQ;
+ }
+ }
+
+ /*
+ * Check mfxExtCodingOption2 fields.
+ *
+ * Mode 2 suffers from false negatives with some drivers, whereas mode 1
+ * suffers from false positives instead. The latter is probably easier
+ * and/or safer to sanitize for us, so use mode 1.
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 6))
+ {
+ init_video_param(&videoParam);
+ videoParam.mfx.CodecId = info->codec_id;
+
+ init_ext_coding_option2(&extCodingOption2);
+ videoParam.ExtParam = videoExtParam;
+ videoParam.ExtParam[0] = (mfxExtBuffer*)&extCodingOption2;
+ videoParam.NumExtParam = 1;
+
+ status = MFXVideoENCODE_Query(session, NULL, &videoParam);
+ if (status >= MFX_ERR_NONE)
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_MBBRC;
+#if 0
+ // testing code that could come in handy
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "MBBRC: 0x%02X\n", extCodingOption2.MBBRC);
+ fprintf(stderr, "ExtBRC: 0x%02X\n", extCodingOption2.ExtBRC);
+ fprintf(stderr, "Trellis: 0x%02X\n", extCodingOption2.Trellis);
+ fprintf(stderr, "RepeatPPS: 0x%02X\n", extCodingOption2.RepeatPPS);
+ fprintf(stderr, "BRefType: %4"PRIu16"\n", extCodingOption2.BRefType);
+ fprintf(stderr, "AdaptiveI: 0x%02X\n", extCodingOption2.AdaptiveI);
+ fprintf(stderr, "AdaptiveB: 0x%02X\n", extCodingOption2.AdaptiveB);
+ fprintf(stderr, "LookAheadDS: %4"PRIu16"\n", extCodingOption2.LookAheadDS);
+ fprintf(stderr, "-------------------\n");
+#endif
+
+ /*
+ * Sanitize API 1.6 fields:
+ *
+ * - MBBRC requires G3 hardware (Haswell or equivalent)
+ * - ExtBRC requires G2 hardware (Ivy Bridge or equivalent)
+ */
+ if (qsv_implementation_is_hardware(info->implementation) &&
+ qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ {
+ if (extCodingOption2.MBBRC)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_MBBRC;
+ }
+ }
+ if (qsv_implementation_is_hardware(info->implementation) &&
+ qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G2)
+ {
+ if (extCodingOption2.ExtBRC)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_EXTBRC;
+ }
+ }
+
+ /*
+ * Sanitize API 1.7 fields:
+ *
+ * - Trellis requires G3 hardware (Haswell or equivalent)
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 7))
+ {
+ if (qsv_implementation_is_hardware(info->implementation) &&
+ qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ {
+ if (extCodingOption2.Trellis)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS;
+ }
+ }
+ }
+
+ /*
+ * Sanitize API 1.8 fields:
+ *
+ * - BRefType requires B-pyramid support
+ * - LookAheadDS requires lookahead support
+ * - AdaptiveI, AdaptiveB, NumMbPerSlice unknown (trust Query)
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 8))
+ {
+ if (info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
+ {
+ if (extCodingOption2.BRefType)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_BREFTYPE;
+ }
+ }
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
+ {
+ if (extCodingOption2.LookAheadDS)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_LA_DOWNS;
+ }
+ }
+ if (extCodingOption2.AdaptiveI && extCodingOption2.AdaptiveB)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_IB_ADAPT;
+ }
+ if (extCodingOption2.NumMbPerSlice)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_NMBSLICE;
+ }
+ }
}
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7))
+ else
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS;
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_LOOKAHEAD;
+ fprintf(stderr,
+ "hb_qsv_info_init: mfxExtCodingOption2 check failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
+ info->codec_id, info->implementation, status);
}
- hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID;
}
}
- else if (qsv_software_available)
+
+ /* Unload optional codec plug-ins */
+ if (pluginUID != NULL && HB_CHECK_MFX_VERSION(version, 1, 8))
+ {
+ MFXVideoUSER_UnLoad(session, pluginUID);
+ }
+
+ return 0;
+}
+
+int hb_qsv_info_init()
+{
+ static int init_done = 0;
+ if (init_done)
+ return 0;
+ init_done = 1;
+
+ /*
+ * First, check for any MSDK version to determine whether one or
+ * more implementations are present; then check if we can use them.
+ *
+ * I've had issues using a NULL version with some combinations of
+ * hardware and driver, so use a low version number (1.0) instead.
+ */
+ mfxSession session;
+ mfxVersion version = { .Major = 1, .Minor = 0, };
+
+ // check for software fallback
+ if (MFXInit(MFX_IMPL_SOFTWARE, &version, &session) == MFX_ERR_NONE)
{
- if (HB_CHECK_MFX_VERSION(qsv_software_version, 1, 6))
+ // Media SDK software found, but check that our minimum is supported
+ MFXQueryVersion(session, &qsv_software_version);
+ if (HB_CHECK_MFX_VERSION(qsv_software_version,
+ HB_QSV_MINVERSION_MAJOR,
+ HB_QSV_MINVERSION_MINOR))
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
- hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID;
+ query_capabilities(session, qsv_software_version, &qsv_software_info_avc);
+ query_capabilities(session, qsv_software_version, &qsv_software_info_hevc);
+ // now that we know which hardware encoders are
+ // available, we can set the preferred implementation
+ hb_qsv_impl_set_preferred("software");
}
- hb_qsv_info->capabilities |= HB_QSV_CAP_CORE_COPYFRAME;
+ MFXClose(session);
}
- // note: we pass a pointer to MFXInit but it never gets modified
- // let's make sure of it just to be safe though
- if (qsv_minimum_version.Major != HB_QSV_MINVERSION_MAJOR ||
- qsv_minimum_version.Minor != HB_QSV_MINVERSION_MINOR)
- {
- hb_error("hb_qsv_info_init: minimum version (%d.%d) was modified",
- qsv_minimum_version.Major,
- qsv_minimum_version.Minor);
+ // check for actual hardware support
+ if (MFXInit(MFX_IMPL_HARDWARE_ANY, &version, &session) == MFX_ERR_NONE)
+ {
+ // Media SDK hardware found, but check that our minimum is supported
+ //
+ // Note: this-party hardware (QSV_G0) is unsupported for the time being
+ MFXQueryVersion(session, &qsv_hardware_version);
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G1 &&
+ HB_CHECK_MFX_VERSION(qsv_hardware_version,
+ HB_QSV_MINVERSION_MAJOR,
+ HB_QSV_MINVERSION_MINOR))
+ {
+ query_capabilities(session, qsv_hardware_version, &qsv_hardware_info_avc);
+ query_capabilities(session, qsv_hardware_version, &qsv_hardware_info_hevc);
+ // now that we know which hardware encoders are
+ // available, we can set the preferred implementation
+ hb_qsv_impl_set_preferred("hardware");
+ }
+ MFXClose(session);
}
// success
return 0;
}
-// we don't need it beyond this point
-#undef HB_CHECK_MFX_VERSION
-
-void hb_qsv_info_print()
+static void log_capabilities(int log_level, uint64_t caps, const char *prefix)
{
- if (hb_qsv_info == NULL)
+ if (!caps)
{
- hb_error("hb_qsv_info_print: QSV info not initialized!");
+ hb_deep_log(log_level, "%s none (standard feature set)", prefix);
}
+ else
+ {
+ hb_deep_log(log_level, "%s%s%s%s%s%s%s%s%s%s%s%s%s", prefix,
+ !(caps & HB_QSV_CAP_MSDK_API_1_6) ? "" : " api1.6",
+ !(caps & HB_QSV_CAP_B_REF_PYRAMID) ? "" : " bpyramid",
+ !(caps & HB_QSV_CAP_OPTION2_BREFTYPE) ? "" : " breftype",
+ !(caps & HB_QSV_CAP_RATECONTROL_LA) ? "" : " lookahead",
+ !(caps & HB_QSV_CAP_RATECONTROL_LAi) ? "" : " lookaheadi",
+ !(caps & HB_QSV_CAP_OPTION2_LA_DOWNS) ? "" : " lookaheadds",
+ !(caps & HB_QSV_CAP_RATECONTROL_ICQ) ? "" : " icq",
+ !(caps & HB_QSV_CAP_OPTION2_MBBRC) ? "" : " mbbrc",
+ !(caps & HB_QSV_CAP_OPTION2_EXTBRC) ? "" : " extbrc",
+ !(caps & HB_QSV_CAP_OPTION2_TRELLIS) ? "" : " trellis",
+ !(caps & HB_QSV_CAP_OPTION2_IB_ADAPT) ? "" : " adaptivei adaptiveb",
+ !(caps & HB_QSV_CAP_OPTION2_NMBSLICE) ? "" : " nummbperslice");
+ }
+}
- // is QSV available?
+void hb_qsv_info_print()
+{
+ // is QSV available and usable?
hb_log("Intel Quick Sync Video support: %s",
hb_qsv_available() ? "yes": "no");
- // if we have Quick Sync Video support, also print the details
+ // also print the details
+ if (qsv_hardware_version.Version)
+ {
+ hb_log(" - Intel Media SDK hardware: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
+ qsv_hardware_version.Major, qsv_hardware_version.Minor,
+ HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
+ }
+ if (qsv_software_version.Version)
+ {
+ hb_log(" - Intel Media SDK software: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
+ qsv_software_version.Major, qsv_software_version.Minor,
+ HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
+ }
if (hb_qsv_available())
{
- if (qsv_hardware_available)
+ if (hb_qsv_info_avc != NULL && hb_qsv_info_avc->available)
{
- hb_log(" - Intel Media SDK hardware: API %d.%d (minimum: %d.%d)",
- qsv_hardware_version.Major,
- qsv_hardware_version.Minor,
- qsv_minimum_version.Major,
- qsv_minimum_version.Minor);
+ hb_log(" - H.264 encoder: yes");
+ hb_log(" - preferred implementation: %s",
+ hb_qsv_impl_get_name(hb_qsv_info_avc->implementation));
+ if (qsv_hardware_info_avc.available)
+ {
+ log_capabilities(2, qsv_hardware_info_avc.capabilities,
+ " - capabilities (hardware): ");
+ }
+ if (qsv_software_info_avc.available)
+ {
+ log_capabilities(2, qsv_software_info_avc.capabilities,
+ " - capabilities (software): ");
+ }
}
- if (qsv_software_available)
+ else
{
- hb_log(" - Intel Media SDK software: API %d.%d (minimum: %d.%d)",
- qsv_software_version.Major,
- qsv_software_version.Minor,
- qsv_minimum_version.Major,
- qsv_minimum_version.Minor);
+ hb_log(" - H.264 encoder: no");
+ }
+ if (hb_qsv_info_hevc != NULL && hb_qsv_info_hevc->available)
+ {
+ hb_log(" - H.265 encoder: yes (unsupported)");
+ hb_log(" - preferred implementation: %s",
+ hb_qsv_impl_get_name(hb_qsv_info_hevc->implementation));
+ if (qsv_hardware_info_hevc.available)
+ {
+ log_capabilities(2, qsv_hardware_info_hevc.capabilities,
+ " - capabilities (hardware): ");
+ }
+ if (qsv_software_info_hevc.available)
+ {
+ log_capabilities(2, qsv_software_info_hevc.capabilities,
+ " - capabilities (software): ");
+ }
+ }
+ else
+ {
+ hb_log(" - H.265 encoder: no");
}
- hb_log(" - Preferred implementation: %s",
- hb_qsv_impl_get_name(preferred_implementation));
+ }
+}
+
+hb_qsv_info_t* hb_qsv_info_get(int encoder)
+{
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_qsv_info_avc;
+ default:
+ return NULL;
}
}
(job->title->video_decode_support & HB_DECODE_SUPPORT_QSV));
}
+int hb_qsv_copyframe_is_slow(int encoder)
+{
+ hb_qsv_info_t *info = hb_qsv_info_get(encoder);
+ if (info != NULL && qsv_implementation_is_hardware(info->implementation))
+ {
+ // we should really check the driver version, but since it's not
+ // available, checking the API version is the best we can do :-(
+ return !HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7);
+ }
+ return 0;
+}
+
int hb_qsv_codingoption_xlat(int val)
{
switch (HB_QSV_CLIP3(-1, 2, val))
return v;
}
-int hb_qsv_param_parse(hb_qsv_param_t *param,
- const char *key, const char *value, int vcodec)
+int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info,
+ const char *key, const char *value)
{
float fvalue;
int ivalue, error = 0;
- if (param == NULL)
+ if (param == NULL || info == NULL)
{
return HB_QSV_PARAM_ERROR;
}
}
else if (!strcasecmp(key, "b-pyramid"))
{
- if (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)
+ if (info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
{
- switch (vcodec)
- {
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoi(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
- }
+ ivalue = hb_qsv_atoi(value, &error);
if (!error)
{
param->gop.b_pyramid = HB_QSV_CLIP3(-1, 1, ivalue);
}
}
}
+ else if (!strcasecmp(key, "adaptive-i") ||
+ !strcasecmp(key, "i-adapt"))
+ {
+ if (info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
+ {
+ ivalue = hb_qsv_atobool(value, &error);
+ if (!error)
+ {
+ param->codingOption2.AdaptiveI = hb_qsv_codingoption_xlat(ivalue);
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
+ }
+ }
+ else if (!strcasecmp(key, "adaptive-b") ||
+ !strcasecmp(key, "b-adapt"))
+ {
+ if (info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
+ {
+ ivalue = hb_qsv_atobool(value, &error);
+ if (!error)
+ {
+ param->codingOption2.AdaptiveB = hb_qsv_codingoption_xlat(ivalue);
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
+ }
+ }
+ else if (!strcasecmp(key, "force-cqp"))
+ {
+ ivalue = hb_qsv_atobool(value, &error);
+ if (!error)
+ {
+ param->rc.icq = !ivalue;
+ }
+ }
else if (!strcasecmp(key, "cqp-offset-i"))
{
ivalue = hb_qsv_atoi(value, &error);
}
else if (!strcasecmp(key, "cavlc") || !strcasecmp(key, "cabac"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
+ case MFX_CODEC_AVC:
ivalue = hb_qsv_atobool(value, &error);
break;
default:
}
else if (!strcasecmp(key, "videoformat"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_vidformat_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_vidformat_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
}
else if (!strcasecmp(key, "fullrange"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_fullrange_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_fullrange_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
}
else if (!strcasecmp(key, "colorprim"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_colorprim_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_colorprim_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
}
else if (!strcasecmp(key, "transfer"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_transfer_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_transfer_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
}
else if (!strcasecmp(key, "colormatrix"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_colmatrix_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_colmatrix_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
else if (!strcasecmp(key, "tff") ||
!strcasecmp(key, "interlaced"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
+ case MFX_CODEC_AVC:
ivalue = hb_qsv_atobool(value, &error);
break;
default:
}
else if (!strcasecmp(key, "bff"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
+ case MFX_CODEC_AVC:
ivalue = hb_qsv_atobool(value, &error);
break;
default:
}
else if (!strcasecmp(key, "mbbrc"))
{
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
+ if (info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
{
ivalue = hb_qsv_atobool(value, &error);
if (!error)
}
else if (!strcasecmp(key, "extbrc"))
{
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
+ if (info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
{
ivalue = hb_qsv_atobool(value, &error);
if (!error)
else if (!strcasecmp(key, "lookahead") ||
!strcasecmp(key, "la"))
{
- switch (vcodec)
- {
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atobool(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
- }
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
{
+ ivalue = hb_qsv_atobool(value, &error);
if (!error)
{
param->rc.lookahead = ivalue;
else if (!strcasecmp(key, "lookahead-depth") ||
!strcasecmp(key, "la-depth"))
{
- switch (vcodec)
- {
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoi(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
- }
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
{
+ ivalue = hb_qsv_atoi(value, &error);
if (!error)
{
// LookAheadDepth 10 will cause a hang with some driver versions
return HB_QSV_PARAM_UNSUPPORTED;
}
}
- else if (!strcasecmp(key, "trellis"))
+ else if (!strcasecmp(key, "lookahead-ds") ||
+ !strcasecmp(key, "la-ds"))
{
- switch (vcodec)
+ if (info->capabilities & HB_QSV_CAP_OPTION2_LA_DOWNS)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoi(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
+ ivalue = hb_qsv_atoi(value, &error);
+ if (!error)
+ {
+ param->codingOption2.LookAheadDS = HB_QSV_CLIP3(MFX_LOOKAHEAD_DS_UNKNOWN,
+ MFX_LOOKAHEAD_DS_4x,
+ ivalue);
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
}
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
+ }
+ else if (!strcasecmp(key, "trellis"))
+ {
+ if (info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
{
+ ivalue = hb_qsv_atoi(value, &error);
if (!error)
{
param->codingOption2.Trellis = hb_qsv_trellisvalue_xlat(ivalue);
{
/*
* TODO:
- * - slice count control
+ * - slice count (num-slice/slices, num-mb-per-slice/slice-max-mbs)
* - open-gop
* - fake-interlaced (mfxExtCodingOption.FramePicture???)
* - intra-refresh
return error ? HB_QSV_PARAM_BAD_VALUE : HB_QSV_PARAM_OK;
}
+#ifdef HB_API_OLD_PRESET_GETTERS
+const char* const* hb_qsv_presets()
+{
+ return hb_qsv_preset_get_names();
+}
+#endif
+
const char* const* hb_qsv_preset_get_names()
{
- if (hb_get_cpu_platform() >= HB_CPU_PLATFORM_INTEL_HSW)
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
{
return hb_qsv_preset_names2;
}
else
{
- return hb_qsv_preset_names1;
+ return hb_qsv_preset_names2;
}
}
-#ifdef HB_API_OLD_PRESET_GETTERS
-const char* const* hb_qsv_presets()
+const char* const* hb_qsv_profile_get_names(int encoder)
{
- return hb_qsv_preset_get_names();
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_h264_profile_names;
+ default:
+ return NULL;
+ }
+}
+
+const char* const* hb_qsv_level_get_names(int encoder)
+{
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_h264_level_names;
+ default:
+ return NULL;
+ }
+}
+
+const char* hb_qsv_video_quality_get_name(uint32_t codec)
+{
+ uint64_t caps;
+ switch (codec)
+ {
+ case HB_VCODEC_QSV_H264:
+ caps = hb_qsv_info_avc != NULL ? hb_qsv_info_avc->capabilities : 0;
+ return (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? "ICQ" : "QP";
+
+ default:
+ return "QP";
+ }
+}
+
+void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high,
+ float *granularity, int *direction)
+{
+ uint64_t caps;
+ switch (codec)
+ {
+ case HB_VCODEC_QSV_H264:
+ caps = hb_qsv_info_avc != NULL ? hb_qsv_info_avc->capabilities : 0;
+ *direction = 1;
+ *granularity = 1.;
+ *low = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
+ *high = 51.;
+ break;
+
+ default:
+ *direction = 1;
+ *granularity = 1.;
+ *low = 0.;
+ *high = 51.;
+ break;
+ }
}
-#endif
int hb_qsv_param_default_preset(hb_qsv_param_t *param,
- mfxVideoParam *videoParam, const char *preset)
+ mfxVideoParam *videoParam,
+ hb_qsv_info_t *info, const char *preset)
{
- if (param != NULL && videoParam != NULL)
+ if (param != NULL && videoParam != NULL && info != NULL)
{
- int ret = hb_qsv_param_default(param, videoParam);
+ int ret = hb_qsv_param_default(param, videoParam, info);
if (ret)
{
return ret;
* LookAhead: 0 (off)
* LookAheadDepth: Not Applicable
*/
- if (hb_get_cpu_platform() >= HB_CPU_PLATFORM_INTEL_HSW)
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
{
param->rc.lookahead = 0;
param->videoParam->mfx.NumRefFrame = 1;
}
else if (!strcasecmp(preset, "speed"))
{
- if (hb_get_cpu_platform() >= HB_CPU_PLATFORM_INTEL_HSW)
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
{
/*
* HSW TargetUsage: 6
return 0;
}
-int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam)
+int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam,
+ hb_qsv_info_t *info)
{
- if (param != NULL && videoParam != NULL)
+ if (param != NULL && videoParam != NULL && info != NULL)
{
// introduced in API 1.0
memset(¶m->codingOption, 0, sizeof(mfxExtCodingOption));
// introduced in API 1.7
param->codingOption2.LookAheadDepth = 40;
param->codingOption2.Trellis = MFX_TRELLIS_OFF;
+ // introduced in API 1.8
+ param->codingOption2.RepeatPPS = MFX_CODINGOPTION_ON;
+ param->codingOption2.BRefType = MFX_B_REF_UNKNOWN; // controlled via gop.b_pyramid
+ param->codingOption2.AdaptiveI = MFX_CODINGOPTION_ON;
+ param->codingOption2.AdaptiveB = MFX_CODINGOPTION_ON;
+ param->codingOption2.LookAheadDS = MFX_LOOKAHEAD_DS_OFF;
+ param->codingOption2.NumMbPerSlice = 0;
// GOP & rate control
param->gop.b_pyramid = -1; // set automatically
param->gop.gop_pic_size = -1; // set automatically
param->gop.gop_ref_dist = -1; // set automatically
param->gop.int_ref_cycle_size = -1; // set automatically
- param->rc.lookahead = 1;
+ param->rc.icq = 1; // enabled by default (if supported)
+ param->rc.lookahead = 1; // enabled by default (if supported)
param->rc.cqp_offsets[0] = 0;
param->rc.cqp_offsets[1] = 2;
param->rc.cqp_offsets[2] = 4;
param->videoParam->ExtParam = param->ExtParamArray;
param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption;
param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->videoSignalInfo;
- if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
+ if (info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
{
param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption2;
}
return frametype;
}
-mfxIMPL hb_qsv_impl_get_preferred()
+int hb_qsv_impl_set_preferred(const char *name)
{
- return preferred_implementation;
+ if (name == NULL)
+ {
+ return -1;
+ }
+ if (!strcasecmp(name, "software"))
+ {
+ if (qsv_software_info_avc.available)
+ {
+ hb_qsv_info_avc = &qsv_software_info_avc;
+ }
+ if (qsv_software_info_hevc.available)
+ {
+ hb_qsv_info_hevc = &qsv_software_info_hevc;
+ }
+ return 0;
+ }
+ if (!strcasecmp(name, "hardware"))
+ {
+ if (qsv_hardware_info_avc.available)
+ {
+ hb_qsv_info_avc = &qsv_hardware_info_avc;
+ }
+ if (qsv_hardware_info_hevc.available)
+ {
+ hb_qsv_info_hevc = &qsv_hardware_info_hevc;
+ }
+ return 0;
+ }
+ return -1;
}
const char* hb_qsv_impl_get_name(int impl)
}
}
+void hb_qsv_force_workarounds()
+{
+ qsv_software_info_avc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+ qsv_hardware_info_avc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+ qsv_software_info_hevc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+ qsv_hardware_info_hevc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+}
+
#endif // USE_QSV