mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-09-21 12:49:40 +08:00
obs-qsv11: Add HEVC
Co-authored-by: jpark37 <jpark37@users.noreply.github.com> Co-authored-by: Jim <obs.jim@gmail.com>
This commit is contained in:
committed by
Jim
co-authored by
jpark37
Jim
parent
37a8835895
commit
fceee90aa9
@@ -363,3 +363,13 @@ enum qsv_cpu_platform qsv_get_cpu_platform()
|
||||
//assume newer revisions are at least as capable as Haswell
|
||||
return QSV_CPU_PLATFORM_INTEL;
|
||||
}
|
||||
|
||||
int qsv_hevc_encoder_headers(qsv_t *pContext, uint8_t **pVPS, uint8_t **pSPS,
|
||||
uint8_t **pPPS, uint16_t *pnVPS, uint16_t *pnSPS,
|
||||
uint16_t *pnPPS)
|
||||
{
|
||||
QSV_Encoder_Internal *pEncoder = (QSV_Encoder_Internal *)pContext;
|
||||
pEncoder->GetVpsSpsPps(pVPS, pSPS, pPPS, pnVPS, pnSPS, pnPPS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ static const struct qsv_rate_control_info qsv_av1_ratecontrols[] =
|
||||
|
||||
static const char *const qsv_profile_names[] = {"high", "main", "baseline", 0};
|
||||
static const char *const qsv_profile_names_av1[] = {"main", 0};
|
||||
static const char *const qsv_profile_names_hevc[] = {"main", "main10", 0};
|
||||
static const char *const qsv_usage_names[] = {"quality", "balanced", "speed",
|
||||
"veryslow", "slower", "slow",
|
||||
"medium", "fast", "faster",
|
||||
@@ -92,11 +93,13 @@ struct adapter_info {
|
||||
bool is_intel;
|
||||
bool is_dgpu;
|
||||
bool supports_av1;
|
||||
bool supports_hevc;
|
||||
};
|
||||
|
||||
enum qsv_codec {
|
||||
QSV_CODEC_AVC,
|
||||
QSV_CODEC_AV1,
|
||||
QSV_CODEC_HEVC,
|
||||
};
|
||||
|
||||
#define MAX_ADAPTERS 10
|
||||
@@ -179,6 +182,10 @@ int qsv_encoder_headers(qsv_t *, uint8_t **pSPS, uint8_t **pPPS,
|
||||
enum qsv_cpu_platform qsv_get_cpu_platform();
|
||||
bool prefer_igpu_enc(int *iGPUIndex);
|
||||
|
||||
int qsv_hevc_encoder_headers(qsv_t *pContext, uint8_t **vVPS, uint8_t **pSPS,
|
||||
uint8_t **pPPS, uint16_t *pnVPS, uint16_t *pnSPS,
|
||||
uint16_t *pnPPS);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -180,7 +180,7 @@ mfxStatus QSV_Encoder_Internal::Open(qsv_param_t *pParams, enum qsv_codec codec)
|
||||
sts = m_pmfxENC->Init(&m_mfxEncParams);
|
||||
MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
|
||||
|
||||
sts = GetVideoParam();
|
||||
sts = GetVideoParam(codec);
|
||||
MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
|
||||
|
||||
sts = InitBitstream();
|
||||
@@ -201,9 +201,16 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
|
||||
m_mfxEncParams.mfx.CodecId = MFX_CODEC_AVC;
|
||||
else if (codec == QSV_CODEC_AV1)
|
||||
m_mfxEncParams.mfx.CodecId = MFX_CODEC_AV1;
|
||||
else if (codec == QSV_CODEC_HEVC)
|
||||
m_mfxEncParams.mfx.CodecId = MFX_CODEC_HEVC;
|
||||
|
||||
m_mfxEncParams.mfx.GopOptFlag = MFX_GOP_STRICT;
|
||||
m_mfxEncParams.mfx.NumSlice = 1;
|
||||
if (codec == QSV_CODEC_HEVC) {
|
||||
m_mfxEncParams.mfx.NumSlice = 0;
|
||||
m_mfxEncParams.mfx.IdrInterval = 1;
|
||||
} else {
|
||||
m_mfxEncParams.mfx.NumSlice = 1;
|
||||
}
|
||||
m_mfxEncParams.mfx.TargetUsage = pParams->nTargetUsage;
|
||||
m_mfxEncParams.mfx.CodecProfile = pParams->nCodecProfile;
|
||||
m_mfxEncParams.mfx.FrameInfo.FrameRateExtN = pParams->nFpsNum;
|
||||
@@ -227,6 +234,9 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
|
||||
else
|
||||
m_mfxEncParams.mfx.GopRefDist = pParams->nbFrames + 1;
|
||||
|
||||
if (codec == QSV_CODEC_HEVC)
|
||||
m_mfxEncParams.mfx.LowPower = MFX_CODINGOPTION_OFF;
|
||||
|
||||
enum qsv_cpu_platform qsv_platform = qsv_get_cpu_platform();
|
||||
if ((qsv_platform >= QSV_CPU_PLATFORM_ICL ||
|
||||
qsv_platform == QSV_CPU_PLATFORM_UNKNOWN) &&
|
||||
@@ -329,6 +339,19 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
|
||||
m_mfxEncParams.NumExtParam = (mfxU16)iBuffers;
|
||||
}
|
||||
|
||||
if (codec == QSV_CODEC_HEVC) {
|
||||
if ((pParams->nWidth & 15) || (pParams->nHeight & 15)) {
|
||||
memset(&m_ExtHEVCParam, 0, sizeof(m_ExtHEVCParam));
|
||||
m_ExtHEVCParam.Header.BufferId = MFX_EXTBUFF_HEVC_PARAM;
|
||||
m_ExtHEVCParam.Header.BufferSz = sizeof(m_ExtHEVCParam);
|
||||
m_ExtHEVCParam.PicWidthInLumaSamples = pParams->nWidth;
|
||||
m_ExtHEVCParam.PicHeightInLumaSamples =
|
||||
pParams->nHeight;
|
||||
extendedBuffers[iBuffers++] =
|
||||
(mfxExtBuffer *)&m_ExtHEVCParam;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&m_ExtVideoSignalInfo, 0, sizeof(m_ExtVideoSignalInfo));
|
||||
m_ExtVideoSignalInfo.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
|
||||
m_ExtVideoSignalInfo.Header.BufferSz = sizeof(m_ExtVideoSignalInfo);
|
||||
@@ -502,7 +525,7 @@ mfxStatus QSV_Encoder_Internal::AllocateSurfaces()
|
||||
return sts;
|
||||
}
|
||||
|
||||
mfxStatus QSV_Encoder_Internal::GetVideoParam()
|
||||
mfxStatus QSV_Encoder_Internal::GetVideoParam(enum qsv_codec codec)
|
||||
{
|
||||
memset(&m_parameter, 0, sizeof(m_parameter));
|
||||
mfxExtCodingOptionSPSPPS opt;
|
||||
@@ -511,18 +534,33 @@ mfxStatus QSV_Encoder_Internal::GetVideoParam()
|
||||
opt.Header.BufferSz = sizeof(mfxExtCodingOptionSPSPPS);
|
||||
|
||||
static mfxExtBuffer *extendedBuffers[1];
|
||||
extendedBuffers[0] = (mfxExtBuffer *)&opt;
|
||||
m_parameter.ExtParam = extendedBuffers;
|
||||
m_parameter.NumExtParam = 1;
|
||||
|
||||
opt.SPSBuffer = m_SPSBuffer;
|
||||
opt.PPSBuffer = m_PPSBuffer;
|
||||
opt.SPSBufSize = 1024; // m_nSPSBufferSize;
|
||||
opt.PPSBufSize = 1024; // m_nPPSBufferSize;
|
||||
|
||||
mfxExtCodingOptionVPS opt_vps{};
|
||||
if (codec == QSV_CODEC_HEVC) {
|
||||
opt_vps.Header.BufferId = MFX_EXTBUFF_CODING_OPTION_VPS;
|
||||
opt_vps.Header.BufferSz = sizeof(mfxExtCodingOptionVPS);
|
||||
opt_vps.VPSBuffer = m_VPSBuffer;
|
||||
opt_vps.VPSBufSize = 1024;
|
||||
|
||||
extendedBuffers[0] = (mfxExtBuffer *)&opt_vps;
|
||||
extendedBuffers[1] = (mfxExtBuffer *)&opt;
|
||||
m_parameter.NumExtParam = 2;
|
||||
} else {
|
||||
extendedBuffers[0] = (mfxExtBuffer *)&opt;
|
||||
m_parameter.NumExtParam = 1;
|
||||
}
|
||||
|
||||
mfxStatus sts = m_pmfxENC->GetVideoParam(&m_parameter);
|
||||
MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
|
||||
|
||||
if (codec == QSV_CODEC_HEVC)
|
||||
m_nVPSBufferSize = opt_vps.VPSBufSize;
|
||||
m_nSPSBufferSize = opt.SPSBufSize;
|
||||
m_nPPSBufferSize = opt.PPSBufSize;
|
||||
|
||||
@@ -538,6 +576,20 @@ void QSV_Encoder_Internal::GetSPSPPS(mfxU8 **pSPSBuf, mfxU8 **pPPSBuf,
|
||||
*pnPPSBuf = m_nPPSBufferSize;
|
||||
}
|
||||
|
||||
void QSV_Encoder_Internal::GetVpsSpsPps(mfxU8 **pVPSBuf, mfxU8 **pSPSBuf,
|
||||
mfxU8 **pPPSBuf, mfxU16 *pnVPSBuf,
|
||||
mfxU16 *pnSPSBuf, mfxU16 *pnPPSBuf)
|
||||
{
|
||||
*pVPSBuf = m_VPSBuffer;
|
||||
*pnVPSBuf = m_nVPSBufferSize;
|
||||
|
||||
*pSPSBuf = m_SPSBuffer;
|
||||
*pnSPSBuf = m_nSPSBufferSize;
|
||||
|
||||
*pPPSBuf = m_PPSBuffer;
|
||||
*pnPPSBuf = m_nPPSBufferSize;
|
||||
}
|
||||
|
||||
mfxStatus QSV_Encoder_Internal::InitBitstream()
|
||||
{
|
||||
m_nTaskPool = m_parameter.AsyncDepth;
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
mfxStatus Open(qsv_param_t *pParams, enum qsv_codec codec);
|
||||
void GetSPSPPS(mfxU8 **pSPSBuf, mfxU8 **pPPSBuf, mfxU16 *pnSPSBuf,
|
||||
mfxU16 *pnPPSBuf);
|
||||
void GetVpsSpsPps(mfxU8 **pVPSBuf, mfxU8 **pSPSBuf, mfxU8 **pPPSBuf,
|
||||
mfxU16 *pnVPSBuf, mfxU16 *pnSPSBuf, mfxU16 *pnPPSBuf);
|
||||
mfxStatus Encode(uint64_t ts, uint8_t *pDataY, uint8_t *pDataUV,
|
||||
uint32_t strideY, uint32_t strideUV,
|
||||
mfxBitstream **pBS);
|
||||
@@ -81,7 +83,7 @@ public:
|
||||
protected:
|
||||
mfxStatus InitParams(qsv_param_t *pParams, enum qsv_codec codec);
|
||||
mfxStatus AllocateSurfaces();
|
||||
mfxStatus GetVideoParam();
|
||||
mfxStatus GetVideoParam(enum qsv_codec codec);
|
||||
mfxStatus InitBitstream();
|
||||
mfxStatus LoadNV12(mfxFrameSurface1 *pSurface, uint8_t *pDataY,
|
||||
uint8_t *pDataUV, uint32_t strideY,
|
||||
@@ -102,14 +104,17 @@ private:
|
||||
mfxFrameSurface1 **m_pmfxSurfaces;
|
||||
mfxU16 m_nSurfNum;
|
||||
MFXVideoENCODE *m_pmfxENC;
|
||||
mfxU8 m_VPSBuffer[1024];
|
||||
mfxU8 m_SPSBuffer[1024];
|
||||
mfxU8 m_PPSBuffer[1024];
|
||||
mfxU16 m_nVPSBufferSize;
|
||||
mfxU16 m_nSPSBufferSize;
|
||||
mfxU16 m_nPPSBufferSize;
|
||||
mfxVideoParam m_parameter;
|
||||
mfxExtCodingOption3 m_co3;
|
||||
mfxExtCodingOption2 m_co2;
|
||||
mfxExtCodingOption m_co;
|
||||
mfxExtHEVCParam m_ExtHEVCParam{};
|
||||
mfxExtVideoSignalInfo m_ExtVideoSignalInfo{};
|
||||
mfxExtChromaLocInfo m_ExtChromaLocInfo{};
|
||||
mfxExtMasteringDisplayColourVolume m_ExtMasteringDisplayColourVolume{};
|
||||
|
||||
@@ -23,6 +23,7 @@ struct adapter_caps {
|
||||
bool is_intel = false;
|
||||
bool is_dgpu = false;
|
||||
bool supports_av1 = false;
|
||||
bool supports_hevc = false;
|
||||
};
|
||||
|
||||
static std::map<uint32_t, adapter_caps> adapter_info;
|
||||
@@ -72,6 +73,9 @@ static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
|
||||
caps.is_intel = true;
|
||||
caps.is_dgpu = dgpu;
|
||||
caps.supports_av1 = has_encoder(impl, MFX_CODEC_AV1);
|
||||
#if ENABLE_HEVC
|
||||
caps.supports_hevc = has_encoder(impl, MFX_CODEC_HEVC);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -80,7 +84,7 @@ DWORD WINAPI TimeoutThread(LPVOID param)
|
||||
{
|
||||
HANDLE hMainThread = (HANDLE)param;
|
||||
|
||||
DWORD ret = WaitForSingleObject(hMainThread, 5000);
|
||||
DWORD ret = WaitForSingleObject(hMainThread, 8000);
|
||||
if (ret == WAIT_TIMEOUT)
|
||||
TerminateProcess(GetCurrentProcess(), STATUS_TIMEOUT);
|
||||
|
||||
@@ -121,6 +125,8 @@ try {
|
||||
printf("is_dgpu=%s\n", caps.is_dgpu ? "true" : "false");
|
||||
printf("supports_av1=%s\n",
|
||||
caps.supports_av1 ? "true" : "false");
|
||||
printf("supports_hevc=%s\n",
|
||||
caps.supports_hevc ? "true" : "false");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -73,6 +73,8 @@ extern struct obs_encoder_info obs_qsv_encoder_tex;
|
||||
extern struct obs_encoder_info obs_qsv_encoder_tex_v2;
|
||||
extern struct obs_encoder_info obs_qsv_av1_encoder_tex;
|
||||
extern struct obs_encoder_info obs_qsv_av1_encoder;
|
||||
extern struct obs_encoder_info obs_qsv_hevc_encoder_tex;
|
||||
extern struct obs_encoder_info obs_qsv_hevc_encoder;
|
||||
|
||||
extern bool av1_supported(mfxIMPL impl);
|
||||
|
||||
@@ -123,6 +125,7 @@ bool obs_module_load(void)
|
||||
adapter_count = config_num_sections(config);
|
||||
bool avc_supported = false;
|
||||
bool av1_supported = false;
|
||||
bool hevc_supported = false;
|
||||
|
||||
if (adapter_count > MAX_ADAPTERS)
|
||||
adapter_count = MAX_ADAPTERS;
|
||||
@@ -137,9 +140,12 @@ bool obs_module_load(void)
|
||||
adapter->is_dgpu = config_get_bool(config, section, "is_dgpu");
|
||||
adapter->supports_av1 =
|
||||
config_get_bool(config, section, "supports_av1");
|
||||
adapter->supports_hevc =
|
||||
config_get_bool(config, section, "supports_hevc");
|
||||
|
||||
avc_supported |= adapter->is_intel;
|
||||
av1_supported |= adapter->supports_av1;
|
||||
hevc_supported |= adapter->supports_hevc;
|
||||
}
|
||||
|
||||
if (avc_supported) {
|
||||
@@ -152,6 +158,12 @@ bool obs_module_load(void)
|
||||
obs_register_encoder(&obs_qsv_av1_encoder_tex);
|
||||
obs_register_encoder(&obs_qsv_av1_encoder);
|
||||
}
|
||||
#if ENABLE_HEVC
|
||||
if (hevc_supported) {
|
||||
obs_register_encoder(&obs_qsv_hevc_encoder_tex);
|
||||
obs_register_encoder(&obs_qsv_hevc_encoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
fail:
|
||||
config_close(config);
|
||||
|
||||
@@ -59,6 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <util/darray.h>
|
||||
#include <util/platform.h>
|
||||
#include <obs-module.h>
|
||||
#include <obs-hevc.h>
|
||||
#include <obs-avc.h>
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
@@ -127,6 +128,12 @@ static const char *obs_qsv_getname_av1(void *type_data)
|
||||
return "QuickSync AV1";
|
||||
}
|
||||
|
||||
static const char *obs_qsv_getname_hevc(void *type_data)
|
||||
{
|
||||
UNUSED_PARAMETER(type_data);
|
||||
return "QuickSync HEVC";
|
||||
}
|
||||
|
||||
static void obs_qsv_stop(void *data);
|
||||
|
||||
static void clear_data(struct obs_qsv *obsqsv)
|
||||
@@ -198,6 +205,11 @@ static void obs_qsv_defaults_av1(obs_data_t *settings)
|
||||
obs_qsv_defaults(settings, 2, QSV_CODEC_AV1);
|
||||
}
|
||||
|
||||
static void obs_qsv_defaults_hevc(obs_data_t *settings)
|
||||
{
|
||||
obs_qsv_defaults(settings, 2, QSV_CODEC_HEVC);
|
||||
}
|
||||
|
||||
static inline void add_strings(obs_property_t *list, const char *const *strings)
|
||||
{
|
||||
while (*strings) {
|
||||
@@ -386,7 +398,8 @@ static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused,
|
||||
prop = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL,
|
||||
OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_STRING);
|
||||
if (codec == QSV_CODEC_AVC)
|
||||
|
||||
if (codec == QSV_CODEC_AVC || codec == QSV_CODEC_HEVC)
|
||||
add_rate_controls(prop, qsv_ratecontrols);
|
||||
else if (codec == QSV_CODEC_AV1)
|
||||
add_rate_controls(prop, qsv_av1_ratecontrols);
|
||||
@@ -426,6 +439,8 @@ static obs_properties_t *obs_qsv_props(enum qsv_codec codec, void *unused,
|
||||
add_strings(prop, qsv_profile_names);
|
||||
else if (codec == QSV_CODEC_AV1)
|
||||
add_strings(prop, qsv_profile_names_av1);
|
||||
else if (codec == QSV_CODEC_HEVC)
|
||||
add_strings(prop, qsv_profile_names_hevc);
|
||||
|
||||
obs_property_set_modified_callback(prop, profile_modified);
|
||||
|
||||
@@ -470,6 +485,12 @@ static obs_properties_t *obs_qsv_props_av1(void *unused)
|
||||
return obs_qsv_props(QSV_CODEC_AV1, unused, 2);
|
||||
}
|
||||
|
||||
static obs_properties_t *obs_qsv_props_hevc(void *unused)
|
||||
{
|
||||
UNUSED_PARAMETER(unused);
|
||||
return obs_qsv_props(QSV_CODEC_HEVC, unused, 2);
|
||||
}
|
||||
|
||||
static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
||||
{
|
||||
video_t *video = obs_encoder_video(obsqsv->encoder);
|
||||
@@ -537,6 +558,20 @@ static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings)
|
||||
else if (astrcmpi(profile, "high") == 0)
|
||||
obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_HIGH;
|
||||
|
||||
} else if (obsqsv->codec == QSV_CODEC_HEVC) {
|
||||
if (astrcmpi(profile, "main") == 0) {
|
||||
obsqsv->params.nCodecProfile = MFX_PROFILE_HEVC_MAIN;
|
||||
if (obs_p010_tex_active()) {
|
||||
blog(LOG_WARNING,
|
||||
"[qsv encoder] Forcing main10 for P010");
|
||||
obsqsv->params.nCodecProfile =
|
||||
MFX_PROFILE_HEVC_MAIN10;
|
||||
}
|
||||
|
||||
} else if (astrcmpi(profile, "main10") == 0) {
|
||||
obsqsv->params.nCodecProfile = MFX_PROFILE_HEVC_MAIN10;
|
||||
}
|
||||
|
||||
} else if (obsqsv->codec == QSV_CODEC_AV1) {
|
||||
obsqsv->params.nCodecProfile = MFX_PROFILE_AV1_MAIN;
|
||||
}
|
||||
@@ -733,6 +768,28 @@ static bool update_settings(struct obs_qsv *obsqsv, obs_data_t *settings)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void load_hevc_headers(struct obs_qsv *obsqsv)
|
||||
{
|
||||
DARRAY(uint8_t) header;
|
||||
DARRAY(uint8_t) sei;
|
||||
|
||||
da_init(header);
|
||||
da_init(sei);
|
||||
|
||||
uint8_t *pVPS, *pSPS, *pPPS;
|
||||
uint16_t nVPS, nSPS, nPPS;
|
||||
qsv_hevc_encoder_headers(obsqsv->context, &pVPS, &pSPS, &pPPS, &nVPS,
|
||||
&nSPS, &nPPS);
|
||||
da_push_back_array(header, pVPS, nVPS);
|
||||
da_push_back_array(header, pSPS, nSPS);
|
||||
da_push_back_array(header, pPPS, nPPS);
|
||||
|
||||
obsqsv->extra_data = header.array;
|
||||
obsqsv->extra_data_size = header.num;
|
||||
obsqsv->sei = sei.array;
|
||||
obsqsv->sei_size = sei.num;
|
||||
}
|
||||
|
||||
static void load_headers(struct obs_qsv *obsqsv)
|
||||
{
|
||||
DARRAY(uint8_t) header;
|
||||
@@ -819,6 +876,8 @@ static void *obs_qsv_create(enum qsv_codec codec, obs_data_t *settings,
|
||||
|
||||
if (obsqsv->context == NULL)
|
||||
warn("qsv failed to load");
|
||||
else if (obsqsv->codec == QSV_CODEC_HEVC)
|
||||
load_hevc_headers(obsqsv);
|
||||
else
|
||||
load_headers(obsqsv);
|
||||
} else {
|
||||
@@ -873,6 +932,11 @@ static void *obs_qsv_create_av1(obs_data_t *settings, obs_encoder_t *encoder)
|
||||
return obs_qsv_create(QSV_CODEC_AV1, settings, encoder);
|
||||
}
|
||||
|
||||
static void *obs_qsv_create_hevc(obs_data_t *settings, obs_encoder_t *encoder)
|
||||
{
|
||||
return obs_qsv_create(QSV_CODEC_HEVC, settings, encoder);
|
||||
}
|
||||
|
||||
static HANDLE get_lib(const char *lib)
|
||||
{
|
||||
HMODULE mod = GetModuleHandleA(lib);
|
||||
@@ -909,7 +973,7 @@ static void *obs_qsv_create_tex(enum qsv_codec codec, obs_data_t *settings,
|
||||
|
||||
bool gpu_texture_active = obs_nv12_tex_active();
|
||||
|
||||
if (codec == QSV_CODEC_AV1)
|
||||
if (codec != QSV_CODEC_AVC)
|
||||
gpu_texture_active = gpu_texture_active ||
|
||||
obs_p010_tex_active();
|
||||
|
||||
@@ -952,6 +1016,13 @@ static void *obs_qsv_create_tex_av1(obs_data_t *settings,
|
||||
"obs_qsv11_av1_soft");
|
||||
}
|
||||
|
||||
static void *obs_qsv_create_tex_hevc(obs_data_t *settings,
|
||||
obs_encoder_t *encoder)
|
||||
{
|
||||
return obs_qsv_create_tex(QSV_CODEC_HEVC, settings, encoder,
|
||||
"obs_qsv11_hevc_soft");
|
||||
}
|
||||
|
||||
static bool obs_qsv_extra_data(void *data, uint8_t **extra_data, size_t *size)
|
||||
{
|
||||
struct obs_qsv *obsqsv = data;
|
||||
@@ -1024,7 +1095,8 @@ static void obs_qsv_video_info(void *data, struct video_scale_info *info)
|
||||
cap_resolution(obsqsv->encoder, info);
|
||||
}
|
||||
|
||||
static void obs_qsv_av1_video_info(void *data, struct video_scale_info *info)
|
||||
static void obs_qsv_video_plus_hdr_info(void *data,
|
||||
struct video_scale_info *info)
|
||||
{
|
||||
struct obs_qsv *obsqsv = data;
|
||||
enum video_format pref_format;
|
||||
@@ -1204,6 +1276,77 @@ static void parse_packet_av1(struct obs_qsv *obsqsv,
|
||||
g_bFirst = false;
|
||||
}
|
||||
|
||||
static void parse_packet_hevc(struct obs_qsv *obsqsv,
|
||||
struct encoder_packet *packet, mfxBitstream *pBS,
|
||||
const struct video_output_info *voi,
|
||||
bool *received_packet)
|
||||
{
|
||||
bool is_vcl_packet = false;
|
||||
|
||||
if (pBS == NULL || pBS->DataLength == 0) {
|
||||
*received_packet = false;
|
||||
return;
|
||||
}
|
||||
|
||||
da_resize(obsqsv->packet_data, 0);
|
||||
da_push_back_array(obsqsv->packet_data, &pBS->Data[pBS->DataOffset],
|
||||
pBS->DataLength);
|
||||
|
||||
packet->data = obsqsv->packet_data.array;
|
||||
packet->size = obsqsv->packet_data.num;
|
||||
packet->type = OBS_ENCODER_VIDEO;
|
||||
packet->pts = ts_mfx_to_obs((mfxI64)pBS->TimeStamp, voi);
|
||||
packet->keyframe = (pBS->FrameType & MFX_FRAMETYPE_IDR);
|
||||
|
||||
uint16_t frameType = pBS->FrameType;
|
||||
uint8_t priority = OBS_NAL_PRIORITY_DISPOSABLE;
|
||||
|
||||
if (frameType & MFX_FRAMETYPE_I)
|
||||
priority = OBS_NAL_PRIORITY_HIGHEST;
|
||||
else if ((frameType & MFX_FRAMETYPE_P) ||
|
||||
(frameType & MFX_FRAMETYPE_REF))
|
||||
priority = OBS_NAL_PRIORITY_HIGH;
|
||||
|
||||
packet->priority = priority;
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
//bool iFrame = pBS->FrameType & MFX_FRAMETYPE_I;
|
||||
//bool bFrame = pBS->FrameType & MFX_FRAMETYPE_B;
|
||||
bool pFrame = pBS->FrameType & MFX_FRAMETYPE_P;
|
||||
|
||||
// In case MSDK doesn't support automatic DecodeTimeStamp, do manual
|
||||
// calculation
|
||||
if (g_pts2dtsShift >= 0) {
|
||||
if (g_bFirst) {
|
||||
packet->dts = packet->pts - 3 * obsqsv->params.nFpsDen;
|
||||
} else if (pFrame) {
|
||||
packet->dts = packet->pts - 10 * obsqsv->params.nFpsDen;
|
||||
g_prevDts = packet->dts;
|
||||
} else {
|
||||
packet->dts = g_prevDts + obsqsv->params.nFpsDen;
|
||||
g_prevDts = packet->dts;
|
||||
}
|
||||
} else {
|
||||
packet->dts = ts_mfx_to_obs(pBS->DecodeTimeStamp, voi);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int iType = iFrame ? 0 : (bFrame ? 1 : (pFrame ? 2 : -1));
|
||||
int64_t interval = obsqsv->params.nbFrames + 1;
|
||||
|
||||
info("parse packet:\n"
|
||||
"\tFrameType: %d\n"
|
||||
"\tpts: %d\n"
|
||||
"\tdts: %d",
|
||||
iType, packet->pts, packet->dts);
|
||||
#endif
|
||||
*received_packet = true;
|
||||
pBS->DataLength = 0;
|
||||
|
||||
g_bFirst = false;
|
||||
}
|
||||
|
||||
static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
||||
struct encoder_packet *packet, bool *received_packet)
|
||||
{
|
||||
@@ -1244,6 +1387,8 @@ static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
||||
parse_packet(obsqsv, packet, pBS, voi, received_packet);
|
||||
else if (obsqsv->codec == QSV_CODEC_AV1)
|
||||
parse_packet_av1(obsqsv, packet, pBS, voi, received_packet);
|
||||
else if (obsqsv->codec == QSV_CODEC_HEVC)
|
||||
parse_packet_hevc(obsqsv, packet, pBS, voi, received_packet);
|
||||
|
||||
ReleaseSRWLockExclusive(&g_QsvLock);
|
||||
|
||||
@@ -1290,6 +1435,8 @@ static bool obs_qsv_encode_tex(void *data, uint32_t handle, int64_t pts,
|
||||
parse_packet(obsqsv, packet, pBS, voi, received_packet);
|
||||
else if (obsqsv->codec == QSV_CODEC_AV1)
|
||||
parse_packet_av1(obsqsv, packet, pBS, voi, received_packet);
|
||||
else if (obsqsv->codec == QSV_CODEC_HEVC)
|
||||
parse_packet_hevc(obsqsv, packet, pBS, voi, received_packet);
|
||||
|
||||
ReleaseSRWLockExclusive(&g_QsvLock);
|
||||
|
||||
@@ -1379,7 +1526,7 @@ struct obs_encoder_info obs_qsv_av1_encoder_tex = {
|
||||
.get_properties = obs_qsv_props_av1,
|
||||
.get_defaults = obs_qsv_defaults_av1,
|
||||
.get_extra_data = obs_qsv_extra_data,
|
||||
.get_video_info = obs_qsv_av1_video_info,
|
||||
.get_video_info = obs_qsv_video_plus_hdr_info,
|
||||
};
|
||||
|
||||
struct obs_encoder_info obs_qsv_av1_encoder = {
|
||||
@@ -1394,6 +1541,38 @@ struct obs_encoder_info obs_qsv_av1_encoder = {
|
||||
.get_properties = obs_qsv_props_av1,
|
||||
.get_defaults = obs_qsv_defaults_av1,
|
||||
.get_extra_data = obs_qsv_extra_data,
|
||||
.get_video_info = obs_qsv_av1_video_info,
|
||||
.get_video_info = obs_qsv_video_plus_hdr_info,
|
||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL,
|
||||
};
|
||||
|
||||
struct obs_encoder_info obs_qsv_hevc_encoder_tex = {
|
||||
.id = "obs_qsv11_hevc",
|
||||
.type = OBS_ENCODER_VIDEO,
|
||||
.codec = "hevc",
|
||||
.get_name = obs_qsv_getname_hevc,
|
||||
.create = obs_qsv_create_tex_hevc,
|
||||
.destroy = obs_qsv_destroy,
|
||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE,
|
||||
.encode_texture = obs_qsv_encode_tex,
|
||||
.update = obs_qsv_update,
|
||||
.get_properties = obs_qsv_props_hevc,
|
||||
.get_defaults = obs_qsv_defaults_hevc,
|
||||
.get_extra_data = obs_qsv_extra_data,
|
||||
.get_video_info = obs_qsv_video_plus_hdr_info,
|
||||
};
|
||||
|
||||
struct obs_encoder_info obs_qsv_hevc_encoder = {
|
||||
.id = "obs_qsv11_hevc_soft",
|
||||
.type = OBS_ENCODER_VIDEO,
|
||||
.codec = "hevc",
|
||||
.get_name = obs_qsv_getname_hevc,
|
||||
.create = obs_qsv_create_hevc,
|
||||
.destroy = obs_qsv_destroy,
|
||||
.encode = obs_qsv_encode,
|
||||
.update = obs_qsv_update,
|
||||
.get_properties = obs_qsv_props_hevc,
|
||||
.get_defaults = obs_qsv_defaults_hevc,
|
||||
.get_extra_data = obs_qsv_extra_data,
|
||||
.get_video_info = obs_qsv_video_plus_hdr_info,
|
||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user