diff --git a/plugins/obs-qsv11/QSV_Encoder.cpp b/plugins/obs-qsv11/QSV_Encoder.cpp index bbaf70954..3c79d4864 100644 --- a/plugins/obs-qsv11/QSV_Encoder.cpp +++ b/plugins/obs-qsv11/QSV_Encoder.cpp @@ -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; +} diff --git a/plugins/obs-qsv11/QSV_Encoder.h b/plugins/obs-qsv11/QSV_Encoder.h index c1a9e9b8d..997da0869 100644 --- a/plugins/obs-qsv11/QSV_Encoder.h +++ b/plugins/obs-qsv11/QSV_Encoder.h @@ -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 diff --git a/plugins/obs-qsv11/QSV_Encoder_Internal.cpp b/plugins/obs-qsv11/QSV_Encoder_Internal.cpp index c65990fe3..42bd30129 100644 --- a/plugins/obs-qsv11/QSV_Encoder_Internal.cpp +++ b/plugins/obs-qsv11/QSV_Encoder_Internal.cpp @@ -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; diff --git a/plugins/obs-qsv11/QSV_Encoder_Internal.h b/plugins/obs-qsv11/QSV_Encoder_Internal.h index 9f98493d5..01c25763d 100644 --- a/plugins/obs-qsv11/QSV_Encoder_Internal.h +++ b/plugins/obs-qsv11/QSV_Encoder_Internal.h @@ -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{}; diff --git a/plugins/obs-qsv11/obs-qsv-test/obs-qsv-test.cpp b/plugins/obs-qsv11/obs-qsv-test/obs-qsv-test.cpp index 83f2b4a82..e3187fb51 100644 --- a/plugins/obs-qsv11/obs-qsv-test/obs-qsv-test.cpp +++ b/plugins/obs-qsv11/obs-qsv-test/obs-qsv-test.cpp @@ -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 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; diff --git a/plugins/obs-qsv11/obs-qsv11-plugin-main.c b/plugins/obs-qsv11/obs-qsv11-plugin-main.c index 93f19a94f..1adf05382 100644 --- a/plugins/obs-qsv11/obs-qsv11-plugin-main.c +++ b/plugins/obs-qsv11/obs-qsv11-plugin-main.c @@ -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); diff --git a/plugins/obs-qsv11/obs-qsv11.c b/plugins/obs-qsv11/obs-qsv11.c index 1005f0b01..5d1be3d71 100644 --- a/plugins/obs-qsv11/obs-qsv11.c +++ b/plugins/obs-qsv11/obs-qsv11.c @@ -59,6 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include @@ -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, };