diff --git a/contrib/ffmpeg/A18-libavcodec-qsvenc-update-has_b_frames-value.patch b/contrib/ffmpeg/A18-libavcodec-qsvenc-update-has_b_frames-value.patch new file mode 100644 index 0000000000000..42c7ad4e7fca2 --- /dev/null +++ b/contrib/ffmpeg/A18-libavcodec-qsvenc-update-has_b_frames-value.patch @@ -0,0 +1,31 @@ +From 95676fcc5c7141124a10bab0498110aed88680ce Mon Sep 17 00:00:00 2001 +From: galinart +Date: Thu, 17 Oct 2024 16:17:36 +0100 +Subject: [PATCH] libavcodec/qsvenc.c: update has_b_frames value after + initialization of encoder + +--- + libavcodec/qsvenc.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c +index 8200a14..c2bb5e5 100644 +--- a/libavcodec/qsvenc.c ++++ b/libavcodec/qsvenc.c +@@ -1842,6 +1842,13 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) + return ret; + } + ++ // Update AVCodecContext with actual encoding parameters ++ mfxInfoMFX *info = &q->param.mfx; ++ avctx->has_b_frames = 0; ++ if (info->GopRefDist > 1) { ++ avctx->has_b_frames = info->GopRefDist - 1; ++ } ++ + q->avctx = avctx; + + return 0; +-- +2.25.1 + diff --git a/contrib/ffmpeg/A19-libavcodec-qsv-enable-av1-scc.patch b/contrib/ffmpeg/A19-libavcodec-qsv-enable-av1-scc.patch new file mode 100644 index 0000000000000..f5bc8f9ee119c --- /dev/null +++ b/contrib/ffmpeg/A19-libavcodec-qsv-enable-av1-scc.patch @@ -0,0 +1,144 @@ +From 71b77865d4955440106015bd08172b876abed1f5 Mon Sep 17 00:00:00 2001 +From: galinart +Date: Tue, 12 Nov 2024 15:50:06 +0000 +Subject: [PATCH] qsv: enable av1 scc + +--- + libavcodec/qsvenc.c | 42 +++++++++++++++++++++++++++++++++++++++++ + libavcodec/qsvenc.h | 8 +++++++- + libavcodec/qsvenc_av1.c | 4 ++++ + 3 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c +index c2bb5e5..284b608 100644 +--- a/libavcodec/qsvenc.c ++++ b/libavcodec/qsvenc.c +@@ -494,6 +494,9 @@ static void dump_video_av1_param(AVCodecContext *avctx, QSVEncContext *q, + mfxExtAV1BitstreamParam *av1_bs_param = (mfxExtAV1BitstreamParam *)coding_opts[1]; + mfxExtCodingOption2 *co2 = (mfxExtCodingOption2*)coding_opts[2]; + mfxExtCodingOption3 *co3 = (mfxExtCodingOption3*)coding_opts[3]; ++#if QSV_HAVE_EXT_AV1_SCC ++ mfxExtAV1ScreenContentTools *scc = (mfxExtAV1ScreenContentTools*)coding_opts[4]; ++#endif + + av_log(avctx, AV_LOG_VERBOSE, "profile: %s; level: %"PRIu16"\n", + print_profile(avctx->codec_id, info->CodecProfile), info->CodecLevel); +@@ -566,6 +569,13 @@ static void dump_video_av1_param(AVCodecContext *avctx, QSVEncContext *q, + print_threestate(av1_bs_param->WriteIVFHeaders)); + av_log(avctx, AV_LOG_VERBOSE, "LowDelayBRC: %s\n", print_threestate(co3->LowDelayBRC)); + av_log(avctx, AV_LOG_VERBOSE, "MaxFrameSize: %d;\n", co2->MaxFrameSize); ++#if QSV_HAVE_EXT_AV1_SCC ++ if (scc) { ++ av_log(avctx, AV_LOG_VERBOSE, ++ "Palette: %s; IntraBlockCopy: %s\n", ++ print_threestate(scc->Palette), print_threestate(scc->IntraBlockCopy)); ++ } ++#endif + } + #endif + +@@ -1282,6 +1292,28 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) + } + #endif + ++#if QSV_HAVE_EXT_AV1_SCC ++ if (q->palette_mode || q->intrabc) { ++ if (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 2, 13)) { ++ if (q->param.mfx.CodecId != MFX_CODEC_AV1) { ++ av_log(avctx, AV_LOG_ERROR, "Not supported encoder for Screen Content Tool Encode. " ++ "Supported: av1_qsv \n"); ++ return AVERROR_UNKNOWN; ++ } ++ ++ q->extsccparam.Header.BufferId = MFX_EXTBUFF_AV1_SCREEN_CONTENT_TOOLS; ++ q->extsccparam.Header.BufferSz = sizeof(q->extsccparam); ++ q->extsccparam.Palette = q->palette_mode ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; ++ q->extsccparam.IntraBlockCopy = q->intrabc ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; ++ q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extsccparam; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, ++ "This version of runtime doesn't support Screen Content Tool Encode\n"); ++ return AVERROR_UNKNOWN; ++ } ++ } ++#endif ++ + if (!check_enc_param(avctx,q)) { + av_log(avctx, AV_LOG_ERROR, + "some encoding parameters are not supported by the QSV " +@@ -1389,11 +1421,21 @@ static int qsv_retrieve_enc_av1_params(AVCodecContext *avctx, QSVEncContext *q) + .Header.BufferSz = sizeof(co3), + }; + ++#if QSV_HAVE_EXT_AV1_SCC ++ mfxExtAV1ScreenContentTools scc_buf = { ++ .Header.BufferId = MFX_EXTBUFF_AV1_SCREEN_CONTENT_TOOLS, ++ .Header.BufferSz = sizeof(scc_buf), ++ }; ++#endif ++ + mfxExtBuffer *ext_buffers[] = { + (mfxExtBuffer*)&av1_extend_tile_buf, + (mfxExtBuffer*)&av1_bs_param, + (mfxExtBuffer*)&co2, + (mfxExtBuffer*)&co3, ++#if QSV_HAVE_EXT_AV1_SCC ++ (mfxExtBuffer*)&scc_buf, ++#endif + }; + + if (!QSV_RUNTIME_VERSION_ATLEAST(q->ver, 2, 5)) { +diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h +index 4bc77f2..2e0a19b 100644 +--- a/libavcodec/qsvenc.h ++++ b/libavcodec/qsvenc.h +@@ -38,6 +38,7 @@ + + #define QSV_HAVE_EXT_VP9_TILES QSV_VERSION_ATLEAST(1, 29) + #define QSV_HAVE_EXT_AV1_PARAM QSV_VERSION_ATLEAST(2, 5) ++#define QSV_HAVE_EXT_AV1_SCC QSV_VERSION_ATLEAST(2, 13) + + #if defined(_WIN32) || defined(__CYGWIN__) + #define QSV_HAVE_AVBR 1 +@@ -188,10 +189,13 @@ typedef struct QSVEncContext { + mfxFrameSurface1 **opaque_surfaces; + AVBufferRef *opaque_alloc_buf; + #endif ++#if QSV_HAVE_EXT_AV1_SCC ++ mfxExtAV1ScreenContentTools extsccparam; ++#endif + + mfxExtVideoSignalInfo extvsi; + +- mfxExtBuffer *extparam_internal[5 + (QSV_HAVE_MF * 2) + (QSV_HAVE_EXT_AV1_PARAM * 2) + QSV_HAVE_HE]; ++ mfxExtBuffer *extparam_internal[5 + (QSV_HAVE_MF * 2) + (QSV_HAVE_EXT_AV1_PARAM * 2) + QSV_HAVE_HE + QSV_HAVE_EXT_AV1_SCC]; + int nb_extparam_internal; + + mfxExtBuffer **extparam_str; +@@ -319,6 +323,8 @@ typedef struct QSVEncContext { + int dual_gfx; + + AVDictionary *qsv_params; ++ int palette_mode; ++ int intrabc; + } QSVEncContext; + + int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q); +diff --git a/libavcodec/qsvenc_av1.c b/libavcodec/qsvenc_av1.c +index a86b409..4f035f3 100644 +--- a/libavcodec/qsvenc_av1.c ++++ b/libavcodec/qsvenc_av1.c +@@ -189,6 +189,10 @@ static const AVOption options[] = { + { "tile_cols", "Number of columns for tiled encoding", OFFSET(qsv.tile_cols), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT16_MAX, VE }, + { "tile_rows", "Number of rows for tiled encoding", OFFSET(qsv.tile_rows), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT16_MAX, VE }, + { "look_ahead_depth", "Depth of look ahead in number frames, available when extbrc option is enabled", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE }, ++#if QSV_HAVE_EXT_AV1_SCC ++ { "palette_mode", "Enable palette mode of Screen Content Tool for encoding", OFFSET(qsv.palette_mode), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, VE}, ++ { "intrabc", "Enable intra block copy of Screen Content Tool for encoding", OFFSET(qsv.intrabc), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, VE}, ++#endif + { NULL }, + }; + +-- +2.25.1 + diff --git a/contrib/ffmpeg/A18-Revert-avcodec-amfenc-GPU-driver-version-check.patch b/contrib/ffmpeg/A20-Revert-avcodec-amfenc-GPU-driver-version-check.patch similarity index 100% rename from contrib/ffmpeg/A18-Revert-avcodec-amfenc-GPU-driver-version-check.patch rename to contrib/ffmpeg/A20-Revert-avcodec-amfenc-GPU-driver-version-check.patch diff --git a/contrib/ffmpeg/A19-lavc-pgssubdec-Add-graphic-plane-and-cropping.patch b/contrib/ffmpeg/A21-lavc-pgssubdec-Add-graphic-plane-and-cropping.patch similarity index 100% rename from contrib/ffmpeg/A19-lavc-pgssubdec-Add-graphic-plane-and-cropping.patch rename to contrib/ffmpeg/A21-lavc-pgssubdec-Add-graphic-plane-and-cropping.patch diff --git a/contrib/ffmpeg/module.defs b/contrib/ffmpeg/module.defs index 776018732bf12..2d9e297fc9596 100644 --- a/contrib/ffmpeg/module.defs +++ b/contrib/ffmpeg/module.defs @@ -167,6 +167,9 @@ endif ifeq (1,$(FEATURE.qsv)) FFMPEG.CONFIGURE.extra += --enable-libvpl FFMPEG.CONFIGURE.extra += --enable-filter=vpp_qsv + FFMPEG.CONFIGURE.extra += --enable-encoder=hevc_qsv + FFMPEG.CONFIGURE.extra += --enable-encoder=h264_qsv + FFMPEG.CONFIGURE.extra += --enable-encoder=av1_qsv endif ifeq (1,$(FEATURE.vce)) diff --git a/libhb/avfilter.c b/libhb/avfilter.c index 11cbf2ea3da75..54179fdb80b4a 100644 --- a/libhb/avfilter.c +++ b/libhb/avfilter.c @@ -238,22 +238,6 @@ static hb_buffer_t* filterFrame( hb_filter_private_t * pv, hb_buffer_t ** buf_in hb_buffer_list_t list; hb_buffer_t * buf = NULL, * next = NULL; -#if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) - mfxFrameSurface1 *surface = NULL; - HBQSVFramesContext *frames_ctx = NULL; - if (hb_qsv_hw_filters_via_video_memory_are_enabled(pv->input.job) && buf_in != NULL) - { - hb_buffer_t *in = *buf_in; - AVFrame *frame = (AVFrame *)in->storage; - if (frame) - { - // We need to keep surface pointer because hb_avfilter_add_buf set it to 0 after in ffmpeg call - surface = (mfxFrameSurface1 *)frame->data[3]; - frames_ctx = in->qsv_details.qsv_frames_ctx; - } - } -#endif - hb_avfilter_add_buf(pv->graph, buf_in); buf = hb_avfilter_get_buf(pv->graph); @@ -262,12 +246,6 @@ static hb_buffer_t* filterFrame( hb_filter_private_t * pv, hb_buffer_t ** buf_in hb_buffer_list_append(&pv->list, buf); buf = hb_avfilter_get_buf(pv->graph); } -#if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) - if (hb_qsv_hw_filters_via_video_memory_are_enabled(pv->input.job) && surface) - { - hb_qsv_release_surface_from_pool_by_surface_pointer(frames_ctx, surface); - } -#endif // Delay one frame so we can set the stop time of the output buffer hb_buffer_list_clear(&list); while (hb_buffer_list_count(&pv->list) > 1) diff --git a/libhb/common.c b/libhb/common.c index 6dcd94f3b821a..c7aa7f7bf4569 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -285,8 +285,8 @@ hb_encoder_internal_t hb_video_encoders[] = // actual encoders { { "AV1 (SVT)", "svt_av1", "AV1 (SVT)", HB_VCODEC_SVT_AV1, HB_MUX_MASK_MP4|HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_SVT, }, { { "AV1 10-bit (SVT)", "svt_av1_10bit", "AV1 10-bit (SVT)", HB_VCODEC_SVT_AV1_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_SVT, }, - { { "AV1 (Intel QSV)", "qsv_av1", "AV1 (Intel Media SDK)", HB_VCODEC_QSV_AV1, HB_MUX_MASK_MP4|HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_QSV, }, - { { "AV1 10-bit (Intel QSV)", "qsv_av1_10bit", "AV1 10-bit (Intel Media SDK)", HB_VCODEC_QSV_AV1_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_QSV, }, + { { "AV1 (Intel QSV)", "qsv_av1", "AV1 (Intel Media SDK)", HB_VCODEC_FFMPEG_QSV_AV1, HB_MUX_MASK_MP4|HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_QSV, }, + { { "AV1 10-bit (Intel QSV)", "qsv_av1_10bit", "AV1 10-bit (Intel Media SDK)", HB_VCODEC_FFMPEG_QSV_AV1_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_WEBM|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_QSV, }, { { "AV1 (NVEnc)", "nvenc_av1", "AV1 (NVEnc)", HB_VCODEC_FFMPEG_NVENC_AV1, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_NVENC, }, { { "AV1 10-bit (NVEnc)", "nvenc_av1_10bit", "AV1 10-bit (NVEnc)", HB_VCODEC_FFMPEG_NVENC_AV1_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_NVENC, }, { { "AV1 (AMD VCE)", "vce_av1", "AV1 (AMD VCE)", HB_VCODEC_FFMPEG_VCE_AV1, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_AV1_VCE, }, @@ -294,7 +294,7 @@ hb_encoder_internal_t hb_video_encoders[] = { { "FFV1", "ffv1", "FFV1 (libavcodec)", HB_VCODEC_FFMPEG_FFV1, HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_FFV1, }, { { "H.264 (x264)", "x264", "H.264 (libx264)", HB_VCODEC_X264_8BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_X264, }, { { "H.264 10-bit (x264)", "x264_10bit", "H.264 10-bit (libx264)", HB_VCODEC_X264_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_X264, }, - { { "H.264 (Intel QSV)", "qsv_h264", "H.264 (Intel Media SDK)", HB_VCODEC_QSV_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_QSV, }, + { { "H.264 (Intel QSV)", "qsv_h264", "H.264 (Intel Media SDK)", HB_VCODEC_FFMPEG_QSV_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_QSV, }, { { "H.264 (AMD VCE)", "vce_h264", "H.264 (AMD VCE)", HB_VCODEC_FFMPEG_VCE_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_VCE, }, { { "H.264 (NVEnc)", "nvenc_h264", "H.264 (NVEnc)", HB_VCODEC_FFMPEG_NVENC_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_NVENC, }, { { "H.264 (MediaFoundation)", "mf_h264", "H.264 (MediaFoundation)", HB_VCODEC_FFMPEG_MF_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H264_MF, }, @@ -303,8 +303,8 @@ hb_encoder_internal_t hb_video_encoders[] = { { "H.265 10-bit (x265)", "x265_10bit", "H.265 10-bit (libx265)", HB_VCODEC_X265_10BIT, HB_MUX_AV_MP4|HB_MUX_AV_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_X265, }, { { "H.265 12-bit (x265)", "x265_12bit", "H.265 12-bit (libx265)", HB_VCODEC_X265_12BIT, HB_MUX_AV_MP4|HB_MUX_AV_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_X265, }, { { "H.265 16-bit (x265)", "x265_16bit", "H.265 16-bit (libx265)", HB_VCODEC_X265_16BIT, HB_MUX_AV_MP4|HB_MUX_AV_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_X265, }, - { { "H.265 (Intel QSV)", "qsv_h265", "H.265 (Intel Media SDK)", HB_VCODEC_QSV_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_QSV, }, - { { "H.265 10-bit (Intel QSV)", "qsv_h265_10bit", "H.265 10-bit (Intel Media SDK)", HB_VCODEC_QSV_H265_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_QSV, }, + { { "H.265 (Intel QSV)", "qsv_h265", "H.265 (Intel Media SDK)", HB_VCODEC_FFMPEG_QSV_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_QSV, }, + { { "H.265 10-bit (Intel QSV)", "qsv_h265_10bit", "H.265 10-bit (Intel Media SDK)", HB_VCODEC_FFMPEG_QSV_H265_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_QSV, }, { { "H.265 (AMD VCE)", "vce_h265", "H.265 (AMD VCE)", HB_VCODEC_FFMPEG_VCE_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_VCE, }, { { "H.265 10-bit (AMD VCE)", "vce_h265_10bit", "H.265 10-bit (AMD VCE)", HB_VCODEC_FFMPEG_VCE_H265_10BIT, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_VCE, }, { { "H.265 (NVEnc)", "nvenc_h265", "H.265 (NVEnc)", HB_VCODEC_FFMPEG_NVENC_H265, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, 1, HB_GID_VCODEC_H265_NVENC, }, @@ -1690,11 +1690,11 @@ int hb_video_multipass_is_supported(uint32_t codec, int constant_quality) case HB_VCODEC_FFMPEG_NVENC_H265_10BIT: case HB_VCODEC_FFMPEG_NVENC_AV1: case HB_VCODEC_FFMPEG_NVENC_AV1_10BIT: - case HB_VCODEC_QSV_H264: - case HB_VCODEC_QSV_H265: - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_AV1: - case HB_VCODEC_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: return 0; case HB_VCODEC_FFMPEG_VP9: @@ -1748,8 +1748,8 @@ int hb_video_encoder_get_depth(int encoder) switch (encoder) { #if HB_PROJECT_FEATURE_QSV - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: #endif #ifdef __APPLE__ case HB_VCODEC_VT_H265_10BIT: @@ -1773,13 +1773,6 @@ int hb_video_encoder_get_depth(int encoder) const char* const* hb_video_encoder_get_presets(int encoder) { -#if HB_PROJECT_FEATURE_QSV - if (encoder & HB_VCODEC_QSV_MASK) - { - return hb_qsv_preset_get_names(); - } -#endif - if (encoder & HB_VCODEC_FFMPEG_MASK) { return hb_av_preset_get_names(encoder); @@ -2001,13 +1994,6 @@ static const enum AVPixelFormat standard_444_12bit_pix_fmts[] = const int* hb_video_encoder_get_pix_fmts(int encoder, const char *profile) { -#if HB_PROJECT_FEATURE_QSV - if (encoder & HB_VCODEC_QSV_MASK) - { - return hb_qsv_get_pix_fmts(encoder); - } -#endif - if (encoder & HB_VCODEC_FFMPEG_MASK) { return hb_av_get_pix_fmts(encoder); @@ -6735,11 +6721,7 @@ static int pix_fmt_is_supported(hb_job_t *job, int pix_fmt) if (planes_count == 2) { - if (hb_hwaccel_decode_is_enabled(job) == 0 -#if HB_PROJECT_FEATURE_QSV - && hb_qsv_full_path_is_enabled(job) == 0 -#endif - ) + if (hb_hwaccel_decode_is_enabled(job) == 0) { return 0; } diff --git a/libhb/cropscale.c b/libhb/cropscale.c index 06dcca2e91c58..f85a62b752e04 100644 --- a/libhb/cropscale.c +++ b/libhb/cropscale.c @@ -12,8 +12,6 @@ #include "handbrake/hbffmpeg.h" #if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) #include "handbrake/qsv_common.h" -#include "libavutil/hwcontext_qsv.h" -#include "libavutil/hwcontext.h" #endif static int crop_scale_init(hb_filter_object_t * filter, @@ -99,18 +97,8 @@ static int crop_scale_init(hb_filter_object_t * filter, hb_filter_init_t * init) hb_dict_t * avsettings = hb_dict_init(); #if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) - if (hb_qsv_hw_filters_via_video_memory_are_enabled(init->job) || hb_qsv_hw_filters_via_system_memory_are_enabled(init->job)) + if(init->hw_pix_fmt == AV_PIX_FMT_QSV) { - if (hb_qsv_hw_filters_via_video_memory_are_enabled(init->job)) - { - int result = hb_qsv_create_ffmpeg_vpp_pool(init, width, height); - if (result < 0) - { - hb_error("hb_create_ffmpeg_pool vpp allocation failed"); - return result; - } - } - if (top > 0 || bottom > 0 || left > 0 || right > 0) { hb_dict_set_int(avsettings, "cx", left); diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 811d64e48b8fe..b21b422a9da8e 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -53,7 +53,6 @@ #include "handbrake/extradata.h" #if HB_PROJECT_FEATURE_QSV -#include "libavutil/hwcontext_qsv.h" #include "handbrake/qsv_common.h" #include "handbrake/qsv_libav.h" #endif @@ -592,7 +591,6 @@ static void closePrivData( hb_work_private_t ** ppv ) * form of communication between the two libmfx sessions). */ //if (!(pv->qsv.decode && pv->job != NULL && (pv->job->vcodec & HB_VCODEC_QSV_MASK))) - hb_qsv_uninit_dec(pv->context); #endif hb_avcodec_free_context(&pv->context); } @@ -1193,17 +1191,7 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv ) reordered_data_t * reordered = NULL; hb_buffer_t * out; -#if HB_PROJECT_FEATURE_QSV - // no need to copy the frame data when decoding with QSV to opaque memory - if (hb_qsv_full_path_is_enabled(pv->job) && hb_qsv_get_memory_type(pv->job) == MFX_IOPATTERN_OUT_VIDEO_MEMORY) - { - out = hb_qsv_copy_avframe_to_video_buffer(pv->job, pv->frame, (AVRational){1,1}, 0); - } - else -#endif - { - out = hb_avframe_to_video_buffer(pv->frame, (AVRational){1,1}); - } + out = hb_avframe_to_video_buffer(pv->frame, (AVRational){1,1}); if (pv->frame->pts != AV_NOPTS_VALUE) { @@ -1871,7 +1859,8 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) hb_buffer_list_clear(&pv->list); #if HB_PROJECT_FEATURE_QSV - if ((pv->qsv.decode = hb_qsv_decode_is_enabled(job))) + pv->qsv.decode = hb_qsv_decode_is_enabled(job); + if (pv->qsv.decode) { pv->qsv.codec_name = hb_qsv_decode_get_codec_name(w->codec_param); pv->qsv.config.io_pattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; @@ -1968,18 +1957,6 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) avcodec_parameters_to_context(pv->context, ic->streams[pv->title->video_id]->codecpar); -#if HB_PROJECT_FEATURE_QSV - if (pv->qsv.decode && - pv->qsv.config.io_pattern == MFX_IOPATTERN_OUT_VIDEO_MEMORY) - { - // assign callbacks and job to have access to qsv context from ffmpeg - pv->context->get_format = hb_qsv_get_format; - pv->context->get_buffer2 = hb_qsv_get_buffer; - pv->context->opaque = pv->job; - pv->context->hwaccel_context = 0; - } -#endif - // Set decoder opts AVDictionary * av_opts = NULL; if (pv->title->flags & HBTF_NO_IDR) @@ -1990,17 +1967,13 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) #if HB_PROJECT_FEATURE_QSV if (pv->qsv.decode) { - if (pv->context->codec_id == AV_CODEC_ID_HEVC) - av_dict_set( &av_opts, "load_plugin", "hevc_hw", 0 ); -#if defined(_WIN32) || defined(__MINGW32__) - if (hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_SYSTEM_MEMORY) + if (hb_hwaccel_is_full_hardware_pipeline_enabled(pv->job)) { - hb_qsv_device_init(job); - pv->context->hw_device_ctx = av_buffer_ref(job->qsv.ctx->hb_hw_device_ctx); - pv->context->get_format = hb_qsv_get_format; - pv->context->opaque = pv->job; + hb_hwaccel_hwframes_ctx_init(pv->context, job); + job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx = av_buffer_ref(pv->context->hw_frames_ctx); } -#endif + if (pv->context->codec_id == AV_CODEC_ID_HEVC) + av_dict_set( &av_opts, "load_plugin", "hevc_hw", 0 ); } #endif @@ -2190,15 +2163,6 @@ static int decodePacket( hb_work_object_t * w ) } } -#if HB_PROJECT_FEATURE_QSV - if (pv->qsv.decode && - pv->qsv.config.io_pattern == MFX_IOPATTERN_OUT_VIDEO_MEMORY) - { - // set the QSV configuration before opening the decoder - pv->context->hwaccel_context = &pv->qsv.config; - } -#endif - AVDictionary * av_opts = NULL; if (pv->title->flags & HBTF_NO_IDR) { diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c deleted file mode 100644 index 7f1ff82481193..0000000000000 --- a/libhb/enc_qsv.c +++ /dev/null @@ -1,2505 +0,0 @@ - -/* ********************************************************************* *\ - -Copyright (C) 2013 Intel Corporation. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -- Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. -- Neither the name of Intel Corporation nor the names of its contributors -may be used to endorse or promote products derived from this software -without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -\* ********************************************************************* */ - -#include "handbrake/project.h" - -#if HB_PROJECT_FEATURE_QSV - -#include "handbrake/handbrake.h" -#include "handbrake/nal_units.h" -#include "handbrake/hbffmpeg.h" -#include "handbrake/qsv_common.h" -#include "handbrake/qsv_memory.h" -#include "handbrake/h264_common.h" -#include "handbrake/h265_common.h" -#include "handbrake/extradata.h" - -#include "libavutil/hwcontext_qsv.h" -#include "libavutil/hwcontext.h" -#include "vpl/mfxvideo.h" - -/* - * The frame info struct remembers information about each frame across calls to - * the encoder. Since frames are uniquely identified by their timestamp, we use - * some bits of the timestamp as an index. The LSB is chosen so that two - * successive frames will have different values in the bits over any plausible - * range of frame rates (starting with bit 8 allows any frame rate slower than - * 352fps). The MSB determines the size of the array. It is chosen so that two - * frames can't use the same slot during the encoder's max frame delay so that, - * up to some minimum frame rate, frames are guaranteed to map to different - * slots (an MSB of 17 which is 2^(17-8+1) = 1024 slots guarantees no collisions - * down to a rate of 0.7 fps). - */ -#define FRAME_INFO_MAX2 (8) // 2^8 = 256; 90000/256 = 352 frames/sec -#define FRAME_INFO_MIN2 (17) // 2^17 = 128K; 90000/131072 = 0.7 frames/sec -#define FRAME_INFO_SIZE (1 << (FRAME_INFO_MIN2 - FRAME_INFO_MAX2 + 1)) -#define FRAME_INFO_MASK (FRAME_INFO_SIZE - 1) - -int encqsvInit (hb_work_object_t*, hb_job_t*); -int encqsvWork (hb_work_object_t*, hb_buffer_t**, hb_buffer_t**); -void encqsvClose(hb_work_object_t*); - -hb_work_object_t hb_encqsv = -{ - WORK_ENCQSV, - "Quick Sync Video encoder (Intel Media SDK)", - encqsvInit, - encqsvWork, - encqsvClose -}; - -struct hb_work_private_s -{ - hb_job_t * job; - uint32_t frames_in; - uint32_t frames_out; - int64_t last_start; - - hb_qsv_param_t param; - hb_qsv_space enc_space; - hb_qsv_info_t * qsv_info; - - hb_chapter_queue_t * chapter_queue; - -#define BFRM_DELAY_MAX 16 - int * init_delay; - int bfrm_delay; - int64_t init_pts[BFRM_DELAY_MAX + 1]; - hb_list_t * list_dts; - - int64_t frame_duration[FRAME_INFO_SIZE]; - - int async_depth; - int max_async_depth; - - // if encode-only, system memory used - int is_sys_mem; - mfxSession mfx_session; - - // whether the encoder is initialized - int init_done; - - hb_list_t * delayed_processing; - hb_buffer_list_t encoded_frames; - - hb_list_t * loaded_plugins; -}; - -static void hb_qsv_add_new_dts(hb_list_t *list, int64_t new_dts) -{ - if (list != NULL) - { - int64_t *item = malloc(sizeof(int64_t)); - if (item != NULL) - { - *item = new_dts; - hb_list_add(list, item); - } - } -} - -static int64_t hb_qsv_pop_next_dts(hb_list_t *list) -{ - int64_t next_dts = INT64_MIN; - if (list != NULL && hb_list_count(list) > 0) - { - int64_t *item = hb_list_item(list, 0); - if (item != NULL) - { - next_dts = *item; - hb_list_rem(list, item); - free(item); - } - } - return next_dts; -} - -static void save_frame_duration(hb_work_private_t *pv, hb_buffer_t *buf) -{ - int i = (buf->s.start >> FRAME_INFO_MAX2) & FRAME_INFO_MASK; - pv->frame_duration[i] = buf->s.stop - buf->s.start; -} - -static int64_t get_frame_duration(hb_work_private_t *pv, hb_buffer_t *buf) -{ - int i = (buf->s.start >> FRAME_INFO_MAX2) & FRAME_INFO_MASK; - return pv->frame_duration[i]; -} - -static const char* hyper_encode_name(const int hyper_encode_mode) -{ - switch (hyper_encode_mode) - { - case MFX_HYPERMODE_OFF: - return "(HyperEncode Off)"; - - case MFX_HYPERMODE_ON: - return "(HyperEncode On)"; - - case MFX_HYPERMODE_ADAPTIVE: - return "(HyperEncode Adaptive)"; - - default: - return NULL; - } -} - -static int log_encoder_params(const hb_work_private_t *pv, const mfxVideoParam *videoParam) -{ - const mfxExtCodingOption *option1 = NULL; - const mfxExtCodingOption2 *option2 = NULL; - const mfxExtAV1ScreenContentTools *extScreenContentCoding = NULL; - const mfxExtHyperModeParam *extHyperModeOption = NULL; - - for (int i = 0; i < videoParam->NumExtParam; i++) - { - mfxExtCodingOption *option = (mfxExtCodingOption*)videoParam->ExtParam[i]; - if (option->Header.BufferId == MFX_EXTBUFF_CODING_OPTION) - { - option1 = (mfxExtCodingOption*)videoParam->ExtParam[i]; - } - else if (option->Header.BufferId == MFX_EXTBUFF_CODING_OPTION2) - { - option2 = (mfxExtCodingOption2*)videoParam->ExtParam[i]; - } - else if (option->Header.BufferId == MFX_EXTBUFF_AV1_SCREEN_CONTENT_TOOLS) - { - extScreenContentCoding = (mfxExtAV1ScreenContentTools*)videoParam->ExtParam[i]; - } - else if (option->Header.BufferId == MFX_EXTBUFF_HYPER_MODE_PARAM) - { - extHyperModeOption = (mfxExtHyperModeParam*)videoParam->ExtParam[i]; - } - else if (option->Header.BufferId != MFX_EXTBUFF_VIDEO_SIGNAL_INFO && - option->Header.BufferId != MFX_EXTBUFF_CHROMA_LOC_INFO && - option->Header.BufferId != MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME && - option->Header.BufferId != MFX_EXTBUFF_CONTENT_LIGHT_LEVEL_INFO && - option->Header.BufferId != MFX_EXTBUFF_AV1_BITSTREAM_PARAM) - { - hb_log("Unknown Header.BufferId=%d", option->Header.BufferId); - } - } - - // log code path and main output settings - hb_log("encqsvInit: using%s%s%s%s path", - hb_qsv_full_path_is_enabled(pv->job) ? " full QSV" : " encode-only", - hb_qsv_get_memory_type(pv->job) == MFX_IOPATTERN_OUT_VIDEO_MEMORY ? " via video memory" : " via system memory", - videoParam->mfx.LowPower == MFX_CODINGOPTION_ON ? " (LowPower)" : "", - extHyperModeOption != NULL ? hyper_encode_name(extHyperModeOption->Mode) : ""); - hb_log("encqsvInit: %s %s profile @ level %s", - hb_qsv_codec_name (videoParam->mfx.CodecId), - hb_qsv_profile_name(videoParam->mfx.CodecId, videoParam->mfx.CodecProfile), - hb_qsv_level_name (videoParam->mfx.CodecId, videoParam->mfx.CodecLevel)); - hb_log("encqsvInit: TargetUsage %"PRIu16" AsyncDepth %"PRIu16"", - videoParam->mfx.TargetUsage, videoParam->AsyncDepth); - hb_log("encqsvInit: GopRefDist %"PRIu16" GopPicSize %"PRIu16" NumRefFrame %"PRIu16" IdrInterval %"PRIu16"", - videoParam->mfx.GopRefDist, videoParam->mfx.GopPicSize, videoParam->mfx.NumRefFrame, videoParam->mfx.IdrInterval); - - if (extScreenContentCoding && ((extScreenContentCoding->IntraBlockCopy == MFX_CODINGOPTION_ON) || (extScreenContentCoding->Palette == MFX_CODINGOPTION_ON))) - { - hb_log("encqsvInit: ScreenContentCoding is enabled IBC %s, Palette %s", - (extScreenContentCoding->IntraBlockCopy == MFX_CODINGOPTION_ON) ? "on" : "off", - (extScreenContentCoding->Palette == MFX_CODINGOPTION_ON) ? "on" : "off"); - } - - if (pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID) - { - hb_log("encqsvInit: BFramesMax %d BRefType %s", - videoParam->mfx.GopRefDist > 1 ? - videoParam->mfx.GopRefDist - 1 : 0, - pv->param.gop.b_pyramid ? "pyramid" : "off"); - } - else - { - hb_log("encqsvInit: BFramesMax %d", - videoParam->mfx.GopRefDist > 1 ? - videoParam->mfx.GopRefDist - 1 : 0); - } - - if (option2 && (option2->AdaptiveI != MFX_CODINGOPTION_OFF || - option2->AdaptiveB != MFX_CODINGOPTION_OFF)) - { - if (videoParam->mfx.GopRefDist > 1) - { - 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]; - snprintf(qpi, sizeof(qpi), "QPI %"PRIu16"", videoParam->mfx.QPI); - snprintf(qpp, sizeof(qpp), " QPP %"PRIu16"", videoParam->mfx.QPP); - snprintf(qpb, sizeof(qpb), " QPB %"PRIu16"", videoParam->mfx.QPB); - hb_log("encqsvInit: RateControlMethod CQP with %s%s%s", qpi, - videoParam->mfx.GopPicSize > 1 ? qpp : "", - videoParam->mfx.GopRefDist > 1 ? qpb : ""); - } - else - { - switch (videoParam->mfx.RateControlMethod) - { - case MFX_RATECONTROL_LA: - hb_log("encqsvInit: RateControlMethod LA TargetKbps %"PRIu16" BRCParamMultiplier %"PRIu16" LookAheadDepth %"PRIu16"", - videoParam->mfx.TargetKbps, videoParam->mfx.BRCParamMultiplier, (option2 != NULL) ? option2->LookAheadDepth : 0); - break; - case MFX_RATECONTROL_LA_ICQ: - hb_log("encqsvInit: RateControlMethod LA_ICQ ICQQuality %"PRIu16" LookAheadDepth %"PRIu16"", - videoParam->mfx.ICQQuality, (option2 != NULL) ? option2->LookAheadDepth : 0); - 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" BRCParamMultiplier %"PRIu16"", - videoParam->mfx.RateControlMethod == MFX_RATECONTROL_CBR ? "CBR" : "VBR", - videoParam->mfx.TargetKbps, videoParam->mfx.MaxKbps, - videoParam->mfx.BufferSizeInKB, videoParam->mfx.InitialDelayInKB, videoParam->mfx.BRCParamMultiplier); - break; - default: - hb_log("encqsvInit: invalid rate control method %"PRIu16"", - videoParam->mfx.RateControlMethod); - return -1; - } - } - - if (option2 && (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: // default - 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) - { - case MFX_PICSTRUCT_PROGRESSIVE: // default - break; - case MFX_PICSTRUCT_FIELD_TFF: - hb_log("encqsvInit: PicStruct top field first"); - break; - case MFX_PICSTRUCT_FIELD_BFF: - hb_log("encqsvInit: PicStruct bottom field first"); - break; - default: - hb_error("encqsvInit: invalid PicStruct value 0x%"PRIx16"", - videoParam->mfx.FrameInfo.PicStruct); - return -1; - } - - if (videoParam->mfx.CodecId == MFX_CODEC_AVC) - { - if (option1 && (option1->CAVLC != MFX_CODINGOPTION_OFF)) - { - hb_log("encqsvInit: CAVLC %s", - hb_qsv_codingoption_get_name(option1->CAVLC)); - } - } - - if (option2 && (option2->ExtBRC != MFX_CODINGOPTION_OFF)) - { - hb_log("encqsvInit: ExtBRC %s", - hb_qsv_codingoption_get_name(option2->ExtBRC)); - } - - if (option2 && (option2->MBBRC != MFX_CODINGOPTION_OFF)) - { - hb_log("encqsvInit: MBBRC %s", - hb_qsv_codingoption_get_name(option2->MBBRC)); - } - - if (option2) - { - switch (option2->Trellis) - { - case MFX_TRELLIS_OFF: // default - break; - case MFX_TRELLIS_UNKNOWN: - hb_log("encqsvInit: Trellis unknown (auto)"); - break; - default: - hb_log("encqsvInit: Trellis on (%s%s%s)", - (option2->Trellis & MFX_TRELLIS_I) ? "I" : "", - (option2->Trellis & MFX_TRELLIS_P) && - (videoParam->mfx.GopPicSize > 1) ? "P" : "", - (option2->Trellis & MFX_TRELLIS_B) && - (videoParam->mfx.GopRefDist > 1) ? "B" : ""); - break; - } - } - - if (option2 && (option2->RepeatPPS != MFX_CODINGOPTION_OFF)) - { - hb_log("encqsvInit: RepeatPPS %s", - hb_qsv_codingoption_get_name(option2->RepeatPPS)); - } - return 0; -} - -static void qsv_handle_breftype(hb_work_private_t *pv) -{ - /* - * If B-pyramid is not possible (not supported, incompatible profile, etc.) - * we don't need to adjust any settings, just sanitize it to off and return. - */ - if (!(pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)) - { - /* B-pyramid support not implemented */ - goto unsupported; - } - else if (pv->param.videoParam->mfx.GopPicSize && - pv->param.videoParam->mfx.GopPicSize <= 3) - { - /* GOP size must be at least 4 for B-pyramid */ - goto unsupported; - } - else if (pv->param.videoParam->mfx.GopRefDist && - pv->param.videoParam->mfx.GopRefDist <= 2) - { - /* We need 2 consecutive B-frames for B-pyramid (GopRefDist >= 3) */ - goto unsupported; - } - else if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_AVC) - { - switch (pv->param.videoParam->mfx.CodecProfile) - { - case MFX_PROFILE_AVC_BASELINE: - case MFX_PROFILE_AVC_CONSTRAINED_HIGH: - case MFX_PROFILE_AVC_CONSTRAINED_BASELINE: - goto unsupported; // B-frames not allowed by profile - default: - break; - } - } - else if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_HEVC) - { - switch (pv->param.videoParam->mfx.CodecProfile) - { - case MFX_PROFILE_HEVC_MAINSP: - goto unsupported; // B-frames not allowed by profile - default: - break; - } - } - - /* Handle B-pyramid auto (on for CQP, off otherwise) */ - if (pv->param.gop.b_pyramid < 0) - { - pv->param.gop.b_pyramid = pv->param.videoParam->mfx.RateControlMethod == MFX_RATECONTROL_CQP; - } - - if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_BREFTYPE) - { - /* B-pyramid can be controlled directly */ - if (pv->param.gop.b_pyramid) - { - pv->param.codingOption2.BRefType = MFX_B_REF_PYRAMID; - } - else - { - pv->param.codingOption2.BRefType = MFX_B_REF_OFF; - } - } - else - { - /* - * We can't control B-pyramid directly, do it indirectly by - * adjusting GopRefDist, GopPicSize and NumRefFrame instead. - */ - pv->param.codingOption2.BRefType = MFX_B_REF_UNKNOWN; - - /* - * pyramid_ref_dist is the closest B-pyramid compatible - * value (multiple of 2, >= 4) to the requested GopRefDist. - */ - int pyramid_ref_dist = 4; - while (pv->param.videoParam->mfx.GopRefDist > pyramid_ref_dist) - { - pyramid_ref_dist *= 2; - } - - if (pv->param.gop.b_pyramid) - { - /* GopRefDist must be B-pyramid compatible */ - pv->param.videoParam->mfx.GopRefDist = pyramid_ref_dist; - - /* - * GopPicSize must be a multiple of GopRefDist. - * - * Note: GopPicSize == 0 should always result in a value - * that doesn't cause Media SDK to disable B-pyramid. - */ - if (pv->param.videoParam->mfx.GopPicSize) - { - pv->param.videoParam->mfx.GopPicSize = FFALIGN(pv->param.videoParam->mfx.GopPicSize, - pv->param.videoParam->mfx.GopRefDist); - } - - /* - * NumRefFrame must be greater than 3 and than half of GopRefDist. - * Otherwise, Media SDK may sometimes decide to disable B-pyramid - * (whereas sometimes it will simply sanitize NumRefFrame instead). - * - * Note: Media SDK handles the NumRefFrame == 0 case for us. - */ - if (pv->param.videoParam->mfx.NumRefFrame) - { - pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame, - pv->param.videoParam->mfx.GopRefDist / 2); - pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame, 3); - } - } - else if (pv->param.videoParam->mfx.GopRefDist == 0 || - pv->param.videoParam->mfx.GopRefDist == pyramid_ref_dist) - { - /* - * GopRefDist is either B-pyramid compatible or unknown (and thus - * potentially compatible), so adjust it to force-disable B-pyramid. - */ - pv->param.videoParam->mfx.GopRefDist = pyramid_ref_dist - 1; - } - } - - return; - -unsupported: - pv->param.gop.b_pyramid = 0; - pv->param.codingOption2.BRefType = MFX_B_REF_OFF; -} - -static int qsv_hevc_make_header(hb_work_object_t *w, mfxSession session, const mfxVideoParam *videoParam) -{ - size_t len; - int ret = 0; - uint8_t *buf, *end; - mfxBitstream bitstream; - mfxStatus status; - mfxSyncPoint syncPoint; - mfxFrameSurface1 frameSurface1; - hb_work_private_t *pv = w->private_data; - - memset(&bitstream, 0, sizeof(mfxBitstream)); - memset(&syncPoint, 0, sizeof(mfxSyncPoint)); - memset(&frameSurface1, 0, sizeof(mfxFrameSurface1)); - - if (videoParam == NULL) - { - hb_log("qsv_hevc_make_header: videoParam is NULL"); - ret = -1; - goto end; - } - /* The bitstream buffer should be able to hold any encoded frame */ - size_t buf_max_size = videoParam->mfx.BufferSizeInKB * 1000 * ( 0 == videoParam->mfx.BRCParamMultiplier ? 1 : videoParam->mfx.BRCParamMultiplier); - bitstream.Data = av_mallocz(sizeof(uint8_t) * buf_max_size); - bitstream.MaxLength = buf_max_size; - if (bitstream.Data == NULL) - { - hb_log("qsv_hevc_make_header: bitstream.Data allocation failed"); - ret = -1; - goto end; - } - - /* We only need to encode one frame, so we only need one surface */ - int bpp12 = (pv->param.videoParam->mfx.FrameInfo.FourCC == MFX_FOURCC_P010) ? 6 : 3; - mfxU16 Height = pv->param.videoParam->mfx.FrameInfo.Height; - mfxU16 Width = pv->param.videoParam->mfx.FrameInfo.Width; - frameSurface1.Info = pv->param.videoParam->mfx.FrameInfo; - frameSurface1.Data.Y = av_mallocz(Width * Height * (bpp12 / 2.0)); - frameSurface1.Data.VU = frameSurface1.Data.Y + Width * Height * (bpp12 == 6 ? 2 : 1); - frameSurface1.Data.Pitch = Width * (bpp12 == 6 ? 2 : 1); - - /* Encode a single blank frame */ - do - { - status = MFXVideoENCODE_EncodeFrameAsync(session, NULL, - &frameSurface1, - &bitstream, - &syncPoint); - - if (status == MFX_ERR_MORE_DATA) - { - break; // more input needed, but we don't have any - } - if (status < MFX_ERR_NONE) - { - hb_log("qsv_hevc_make_header: MFXVideoENCODE_EncodeFrameAsync failed (%d)", status); - status = log_encoder_params(pv, pv->param.videoParam); - if (status < 0) - { - hb_error("qsv_hevc_make_header: log_encoder_params failed (%d)", status); - } - ret = -1; - goto end; - } - if (syncPoint) - { - break; // we have output - } - if (status == MFX_WRN_DEVICE_BUSY) - { - hb_qsv_sleep(1); - } - } - while (status >= MFX_ERR_NONE); - - /* If we don't have any output yet, flush the encoder */ - if (!syncPoint) - { - do - { - status = MFXVideoENCODE_EncodeFrameAsync(session, NULL, NULL, - &bitstream, - &syncPoint); - - if (status == MFX_ERR_MORE_DATA) - { - break; // done flushing - } - if (status < MFX_ERR_NONE) - { - hb_log("qsv_hevc_make_header: MFXVideoENCODE_EncodeFrameAsync failed (%d)", status); - ret = -1; - goto end; - } - if (syncPoint) - { - break; // we have output - } - if (status == MFX_WRN_DEVICE_BUSY) - { - hb_qsv_sleep(1); - } - } - while (status >= MFX_ERR_NONE); - } - - /* Still no data at this point, we can't proceed */ - if (!syncPoint) - { - hb_log("qsv_hevc_make_header: no sync point"); - ret = -1; - goto end; - } - - do - { - status = MFXVideoCORE_SyncOperation(session, syncPoint, 100); - } - while (status == MFX_WRN_IN_EXECUTION); - - if (status != MFX_ERR_NONE) - { - hb_log("qsv_hevc_make_header: MFXVideoCORE_SyncOperation failed (%d)", status); - ret = -1; - goto end; - } - - if (!bitstream.DataLength) - { - hb_log("qsv_hevc_make_header: no bitstream data"); - ret = -1; - goto end; - } - - /* Include any parameter sets and SEI NAL units in the headers. */ - len = bitstream.DataLength; - buf = bitstream.Data + bitstream.DataOffset; - end = bitstream.Data + bitstream.DataOffset + bitstream.DataLength; - - size_t extradata_size = 0; - uint8_t extradata[HB_CONFIG_MAX_SIZE]; - - while ((buf = hb_annexb_find_next_nalu(buf, &len)) != NULL) - { - switch ((buf[0] >> 1) & 0x3f) - { - case 32: // VPS_NUT - case 33: // SPS_NUT - case 34: // PPS_NUT - case 39: // PREFIX_SEI_NUT - case 40: // SUFFIX_SEI_NUT - break; - default: - len = end - buf; - continue; - } - - size_t size = hb_nal_unit_write_annexb(NULL, buf, len) + extradata_size; - if (sizeof(extradata) < size) - { - /* Will never happen in practice */ - hb_log("qsv_hevc_make_header: header too large (size: %lu, max: %lu)", - size, sizeof(extradata)); - } - - extradata_size += hb_nal_unit_write_annexb(extradata + extradata_size, buf, len); - len = end - buf; - } - - hb_set_extradata(w->extradata, extradata, extradata_size); - -end: - if (bitstream.Data) - av_free(bitstream.Data); - av_free(frameSurface1.Data.Y); - return ret; -} - -static void mids_buf_free(void *opaque, uint8_t *data) -{ - AVBufferRef *hw_frames_ref = opaque; - av_buffer_unref(&hw_frames_ref); - av_freep(&data); -} - -static enum AVPixelFormat qsv_map_fourcc(uint32_t fourcc) -{ - switch (fourcc) { - case MFX_FOURCC_NV12: return AV_PIX_FMT_NV12; - case MFX_FOURCC_P010: return AV_PIX_FMT_P010; - case MFX_FOURCC_P8: return AV_PIX_FMT_PAL8; - } - return AV_PIX_FMT_NONE; -} - -AVBufferRef *hb_qsv_create_mids(AVBufferRef *hw_frames_ref) -{ - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - int nb_surfaces = frames_hwctx->nb_surfaces; - - AVBufferRef *mids_buf, *hw_frames_ref1; - QSVMid *mids; - int i; - - hw_frames_ref1 = av_buffer_ref(hw_frames_ref); - if (!hw_frames_ref1) - return NULL; - - mids = av_calloc(nb_surfaces, sizeof(*mids)); - if (!mids) { - av_buffer_unref(&hw_frames_ref1); - return NULL; - } - - mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids), - mids_buf_free, hw_frames_ref1, 0); - if (!mids_buf) { - av_buffer_unref(&hw_frames_ref1); - av_freep(&mids); - return NULL; - } - - for (i = 0; i < nb_surfaces; i++) { - QSVMid *mid = &mids[i]; - mid->handle_pair = (mfxHDLPair*)frames_hwctx->surfaces[i].Data.MemId; - mid->hw_frames_ref = hw_frames_ref1; - } - - return mids_buf; -} - -static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref, - AVBufferRef *mids_buf) -{ - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - QSVMid *mids = (QSVMid*)mids_buf->data; - int nb_surfaces = frames_hwctx->nb_surfaces; - int i; - - // the allocated size of the array is two larger than the number of - // surfaces, we store the references to the frames context and the - // QSVMid array there - resp->mids = av_calloc(nb_surfaces + 2, sizeof(*resp->mids)); - if (!resp->mids) - return AVERROR(ENOMEM); - - for (i = 0; i < nb_surfaces; i++) - resp->mids[i] = &mids[i]; - resp->NumFrameActual = nb_surfaces; - - resp->mids[resp->NumFrameActual] = (mfxMemId)av_buffer_ref(hw_frames_ref); - if (!resp->mids[resp->NumFrameActual]) { - av_freep(&resp->mids); - return AVERROR(ENOMEM); - } - - resp->mids[resp->NumFrameActual + 1] = av_buffer_ref(mids_buf); - if (!resp->mids[resp->NumFrameActual + 1]) { - av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); - av_freep(&resp->mids); - return AVERROR(ENOMEM); - } - - return 0; -} - -static mfxStatus hb_qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, - mfxFrameAllocResponse *resp) -{ - HBQSVFramesContext *ctx = pthis; - int ret; - - /* this should only be called from an encoder or decoder and - * only allocates video memory frames */ - if (!(req->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | - MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)) || - !(req->Type & (MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_ENCODE))) - return MFX_ERR_UNSUPPORTED; - - if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) { - /* external frames -- fill from the caller-supplied frames context */ - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - mfxFrameInfo *i = &req->Info; - mfxFrameInfo *i1 = &frames_hwctx->surfaces[0].Info; - - if (i->Width > i1->Width || i->Height > i1->Height || - i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) { - hb_error("Mismatching surface properties in an " - "allocation request: %dx%d %d %d vs %dx%d %d %d\n", - i->Width, i->Height, i->FourCC, i->ChromaFormat, - i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat); - return MFX_ERR_UNSUPPORTED; - } - - ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf); - if (ret < 0) { - hb_error("Error filling an external frame allocation request\n"); - return MFX_ERR_MEMORY_ALLOC; - } - } else if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME) { - /* internal frames -- allocate a new hw frames context */ - AVHWFramesContext *ext_frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; - mfxFrameInfo *i = &req->Info; - - AVBufferRef *frames_ref, *mids_buf; - AVHWFramesContext *frames_ctx; - AVQSVFramesContext *frames_hwctx; - - frames_ref = av_hwframe_ctx_alloc(ext_frames_ctx->device_ref); - if (!frames_ref) - return MFX_ERR_MEMORY_ALLOC; - - frames_ctx = (AVHWFramesContext*)frames_ref->data; - frames_hwctx = frames_ctx->hwctx; - - frames_ctx->format = AV_PIX_FMT_QSV; - frames_ctx->sw_format = qsv_map_fourcc(i->FourCC); - frames_ctx->width = i->Width; - frames_ctx->height = i->Height; - frames_ctx->initial_pool_size = req->NumFrameSuggested; - - frames_hwctx->frame_type = req->Type; - - ret = av_hwframe_ctx_init(frames_ref); - if (ret < 0) { - hb_error("Error initializing a frames context for an internal frame " - "allocation request\n"); - av_buffer_unref(&frames_ref); - return MFX_ERR_MEMORY_ALLOC; - } - - mids_buf = hb_qsv_create_mids(frames_ref); - if (!mids_buf) { - av_buffer_unref(&frames_ref); - return MFX_ERR_MEMORY_ALLOC; - } - - ret = qsv_setup_mids(resp, frames_ref, mids_buf); - av_buffer_unref(&mids_buf); - av_buffer_unref(&frames_ref); - if (ret < 0) { - hb_error("Error filling an internal frame allocation request\n"); - return MFX_ERR_MEMORY_ALLOC; - } - } else { - return MFX_ERR_UNSUPPORTED; - } - - return MFX_ERR_NONE; -} - -static mfxStatus hb_qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) -{ - av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); - av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]); - av_freep(&resp->mids); - return MFX_ERR_NONE; -} - -static mfxStatus hb_qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) -{ - QSVMid *qsv_mid = mid; - AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)qsv_mid->hw_frames_ref->data; - AVQSVFramesContext *hw_frames_hwctx = hw_frames_ctx->hwctx; - int ret; - - if (qsv_mid->locked_frame) - return MFX_ERR_UNDEFINED_BEHAVIOR; - - /* Allocate a system memory frame that will hold the mapped data. */ - qsv_mid->locked_frame = av_frame_alloc(); - if (!qsv_mid->locked_frame) - return MFX_ERR_MEMORY_ALLOC; - qsv_mid->locked_frame->format = hw_frames_ctx->sw_format; - - /* wrap the provided handle in a hwaccel AVFrame */ - qsv_mid->hw_frame = av_frame_alloc(); - if (!qsv_mid->hw_frame) - goto fail; - - qsv_mid->hw_frame->data[3] = (uint8_t*)&qsv_mid->surf; - qsv_mid->hw_frame->format = AV_PIX_FMT_QSV; - - // doesn't really matter what buffer is used here - qsv_mid->hw_frame->buf[0] = av_buffer_alloc(1); - if (!qsv_mid->hw_frame->buf[0]) - goto fail; - - qsv_mid->hw_frame->width = hw_frames_ctx->width; - qsv_mid->hw_frame->height = hw_frames_ctx->height; - - qsv_mid->hw_frame->hw_frames_ctx = av_buffer_ref(qsv_mid->hw_frames_ref); - if (!qsv_mid->hw_frame->hw_frames_ctx) - goto fail; - - qsv_mid->surf.Info = hw_frames_hwctx->surfaces[0].Info; - qsv_mid->surf.Data.MemId = qsv_mid->handle_pair; - - /* map the data to the system memory */ - ret = av_hwframe_map(qsv_mid->locked_frame, qsv_mid->hw_frame, - AV_HWFRAME_MAP_DIRECT); - if (ret < 0) - goto fail; - - ptr->Pitch = qsv_mid->locked_frame->linesize[0]; - ptr->Y = qsv_mid->locked_frame->data[0]; - ptr->U = qsv_mid->locked_frame->data[1]; - ptr->V = qsv_mid->locked_frame->data[1] + 1; - - return MFX_ERR_NONE; -fail: - av_frame_free(&qsv_mid->hw_frame); - av_frame_free(&qsv_mid->locked_frame); - return MFX_ERR_MEMORY_ALLOC; -} - -static mfxStatus hb_qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) -{ - QSVMid *qsv_mid = mid; - - av_frame_free(&qsv_mid->locked_frame); - av_frame_free(&qsv_mid->hw_frame); - - return MFX_ERR_NONE; -} - -static mfxStatus hb_qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) -{ - QSVMid *qsv_mid = (QSVMid*)mid; - mfxHDLPair *pair_dst = (mfxHDLPair*)hdl; - mfxHDLPair *pair_src = (mfxHDLPair*)qsv_mid->handle_pair; - - pair_dst->first = pair_src->first; - if (pair_src->second != (mfxMemId)MFX_INFINITE) - pair_dst->second = pair_src->second; - - return MFX_ERR_NONE; -} - -#define QSV_RUNTIME_VERSION_ATLEAST(MFX_VERSION, MAJOR, MINOR) \ - (MFX_VERSION.Major > (MAJOR)) || \ - (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR)) - -int qsv_enc_init(hb_work_private_t *pv) -{ - hb_qsv_context *qsv = pv->job->qsv.ctx; - hb_job_t *job = pv->job; - mfxVersion version; - mfxStatus sts; - mfxIMPL impl; - int i; - - if (pv->init_done) - { - return 0; - } - - if (qsv == NULL) - { - hb_error("qsv_enc_init: no context!"); - return 3; - } - - hb_qsv_space *qsv_encode = qsv->enc_space; - if (qsv_encode == NULL) - { - // if only for encode - if (pv->is_sys_mem) - { - // re-use the session from encqsvInit - qsv->mfx_session = pv->mfx_session; - } - else - { - mfxStatus err; - - mfxVersion ver; - mfxIMPL impl; - - AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)qsv->hb_hw_device_ctx->data; - AVQSVDeviceContext *device_hwctx = device_ctx->hwctx; - mfxSession parent_session = device_hwctx->session; - - err = MFXQueryIMPL(parent_session, &impl); - if (err != MFX_ERR_NONE) - { - hb_error("Error querying the session attributes"); - return -1; - } - - err = MFXQueryVersion(parent_session, &ver); - if (err != MFX_ERR_NONE) - { - hb_error("Error querying the session attributes"); - return -1; - } - - // reuse parent session - qsv->mfx_session = parent_session; - mfxFrameAllocator frame_allocator = { - .pthis = pv->job->qsv.ctx->hb_dec_qsv_frames_ctx, - .Alloc = hb_qsv_frame_alloc, - .Lock = hb_qsv_frame_lock, - .Unlock = hb_qsv_frame_unlock, - .GetHDL = hb_qsv_frame_get_hdl, - .Free = hb_qsv_frame_free, - }; - - if (hb_qsv_hw_filters_via_video_memory_are_enabled(pv->job) || hb_qsv_hw_filters_via_system_memory_are_enabled(pv->job)) - { - frame_allocator.pthis = pv->job->qsv.ctx->hb_vpp_qsv_frames_ctx; - } - - err = MFXVideoCORE_SetFrameAllocator(qsv->mfx_session, &frame_allocator); - if (err != MFX_ERR_NONE) - { - hb_log("encqsvInit: MFXVideoCORE_SetFrameAllocator error %d", err); - return -1; - } - } - qsv->enc_space = qsv_encode = &pv->enc_space; - } - - if (!pv->is_sys_mem) - { - hb_qsv_space *dec_space = qsv->dec_space; - if (dec_space == NULL || !dec_space->is_init_done) - { - return 2; - } - } - - // allocate tasks - qsv_encode->p_buf_max_size = pv->param.videoParam->mfx.BufferSizeInKB * 1000 * ( 0 == pv->param.videoParam->mfx.BRCParamMultiplier ? 1 : pv->param.videoParam->mfx.BRCParamMultiplier); - qsv_encode->tasks = hb_qsv_list_init(HAVE_THREADS); - for (i = 0; i < pv->max_async_depth; i++) - { - hb_qsv_task *task = av_mallocz(sizeof(hb_qsv_task)); - task->bs = av_mallocz(sizeof(mfxBitstream)); - task->bs->Data = av_mallocz(sizeof(uint8_t) * qsv_encode->p_buf_max_size); - task->bs->MaxLength = qsv_encode->p_buf_max_size; - task->bs->DataLength = 0; - task->bs->DataOffset = 0; - hb_qsv_list_add(qsv_encode->tasks, task); - } - - // setup surface allocation - pv->param.videoParam->IOPattern = (pv->is_sys_mem ? - MFX_IOPATTERN_IN_SYSTEM_MEMORY : - MFX_IOPATTERN_IN_VIDEO_MEMORY); - memset(&qsv_encode->request, 0, sizeof(mfxFrameAllocRequest) * 2); - sts = MFXVideoENCODE_QueryIOSurf(qsv->mfx_session, - pv->param.videoParam, - &qsv_encode->request[0]); - if (sts < MFX_ERR_NONE) // ignore warnings - { - hb_error("qsv_enc_init: MFXVideoENCODE_QueryIOSurf failed (%d)", sts); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return -1; - } - - // allocate surfaces - if (pv->is_sys_mem) - { - qsv_encode->surface_num = FFMIN(qsv_encode->request[0].NumFrameSuggested + - pv->max_async_depth, HB_QSV_SURFACE_NUM); - if (qsv_encode->surface_num <= 0) - { - qsv_encode->surface_num = HB_QSV_SURFACE_NUM; - } - - /* should have 15bpp/AV_PIX_FMT_YUV420P10LE (almost x2) instead of 12bpp/AV_PIX_FMT_NV12 */ - int bpp12 = (pv->param.videoParam->mfx.CodecProfile == (MFX_PROFILE_HEVC_MAIN10) || (job->vcodec == HB_VCODEC_QSV_AV1_10BIT)) ? 6 : 3; - for (i = 0; i < qsv_encode->surface_num; i++) - { - mfxFrameSurface1 *surface = av_mallocz(sizeof(mfxFrameSurface1)); - mfxFrameInfo info = pv->param.videoParam->mfx.FrameInfo; - surface->Info = info; - surface->Data.Pitch = info.Width * (bpp12 == 6 ? 2 : 1); - surface->Data.Y = av_mallocz(info.Width * info.Height * (bpp12 / 2.0)); - surface->Data.VU = surface->Data.Y + info.Width * info.Height * (bpp12 == 6 ? 2 : 1); - qsv_encode->p_surfaces[i] = surface; - } - } - else - { - qsv_encode->surface_num = FFMIN(qsv_encode->request[0].NumFrameSuggested + - pv->max_async_depth, HB_QSV_SURFACE_NUM); - if (qsv_encode->surface_num <= 0) - { - qsv_encode->surface_num = HB_QSV_SURFACE_NUM; - } - } - - // allocate sync points - qsv_encode->sync_num = (qsv_encode->surface_num ? - FFMIN(qsv_encode->surface_num, HB_QSV_SYNC_NUM) : - HB_QSV_SYNC_NUM); - - for (i = 0; i < qsv_encode->sync_num; i++) - { - qsv_encode->p_syncp[i] = av_mallocz(sizeof(hb_qsv_sync)); - HB_QSV_CHECK_POINTER(qsv_encode->p_syncp[i], MFX_ERR_MEMORY_ALLOC); - qsv_encode->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint)); - HB_QSV_CHECK_POINTER(qsv_encode->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC); - } - - // initialize the encoder - sts = MFXVideoENCODE_Init(qsv->mfx_session, pv->param.videoParam); - if (sts < MFX_ERR_NONE) // ignore warnings - { - hb_error("qsv_enc_init: MFXVideoENCODE_Init failed (%d)", sts); - *job->done_error = HB_ERROR_INIT; - *job->die = 1; - return -1; - } - - // query and log actual implementation details - if ((MFXQueryIMPL (qsv->mfx_session, &impl) == MFX_ERR_NONE) && - (MFXQueryVersion(qsv->mfx_session, &version) == MFX_ERR_NONE)) - { - hb_log("qsv_enc_init: using '%s %s' implementation, API: %"PRIu16".%"PRIu16"", - hb_qsv_impl_get_name(impl), hb_qsv_impl_get_via_name(impl), version.Major, version.Minor); - } - else - { - hb_log("qsv_enc_init: MFXQueryIMPL/MFXQueryVersion failure"); - } - - qsv_encode->is_init_done = 1; - pv->init_done = 1; - return 0; -} - -/*********************************************************************** - * encqsvInit - *********************************************************************** - * - **********************************************************************/ -int encqsvInit(hb_work_object_t *w, hb_job_t *job) -{ - if (!hb_qsv_available()) - { - hb_error("encqsvInit: qsv is not available on the system"); - return -1; - } - - int brc_param_multiplier; - hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); - w->private_data = pv; - - pv->is_sys_mem = (hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_SYSTEM_MEMORY); - pv->job = job; - pv->qsv_info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec); - pv->delayed_processing = hb_list_init(); - pv->last_start = INT64_MIN; - hb_buffer_list_clear(&pv->encoded_frames); - - pv->chapter_queue = hb_chapter_queue_init(); - - if (!pv->qsv_info) - { - hb_error("encqsvInit: %s codec is not supported by this GPU adapter", hb_video_encoder_get_long_name(job->vcodec)); - return -1; - } - - // default encoding parameters - if (hb_qsv_param_default_preset(&pv->param, &pv->enc_space.m_mfxVideoParam, - pv->qsv_info, job->encoder_preset)) - { - hb_error("encqsvInit: hb_qsv_param_default_preset failed"); - return -1; - } - - // set AsyncDepth to match that of decode and VPP - pv->param.videoParam->AsyncDepth = job->qsv.async_depth; - - // set and enable colorimetry (video signal information) - pv->param.videoSignalInfo.VideoFullRange = (pv->job->color_range == AVCOL_RANGE_JPEG); - - pv->param.videoSignalInfo.ColourPrimaries = hb_output_color_prim(job); - pv->param.videoSignalInfo.TransferCharacteristics = hb_output_color_transfer(job); - pv->param.videoSignalInfo.MatrixCoefficients = hb_output_color_matrix(job); - pv->param.videoSignalInfo.ColourDescriptionPresent = 1; - - if (job->chroma_location != AVCHROMA_LOC_UNSPECIFIED) - { - pv->param.chromaLocInfo.ChromaSampleLocTypeBottomField = - pv->param.chromaLocInfo.ChromaSampleLocTypeTopField = job->chroma_location - 1; - pv->param.chromaLocInfo.ChromaLocInfoPresentFlag = 1; - } - - /* HDR10 Static metadata */ - if (job->color_transfer == HB_COLR_TRA_SMPTEST2084) - { - if (pv->qsv_info->codec_id == MFX_CODEC_HEVC) - { - const int masteringChromaDen = 50000; - const int masteringLumaDen = 10000; - - /* Mastering display metadata */ - if (job->mastering.has_primaries && job->mastering.has_luminance) - { - pv->param.masteringDisplayColourVolume.InsertPayloadToggle = MFX_PAYLOAD_IDR; - pv->param.masteringDisplayColourVolume.DisplayPrimariesX[0] = FFMIN(hb_rescale_rational(job->mastering.display_primaries[1][0], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesY[0] = FFMIN(hb_rescale_rational(job->mastering.display_primaries[1][1], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesX[1] = FFMIN(hb_rescale_rational(job->mastering.display_primaries[2][0], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesY[1] = FFMIN(hb_rescale_rational(job->mastering.display_primaries[2][1], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesX[2] = FFMIN(hb_rescale_rational(job->mastering.display_primaries[0][0], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesY[2] = FFMIN(hb_rescale_rational(job->mastering.display_primaries[0][1], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.WhitePointX = FFMIN(hb_rescale_rational(job->mastering.white_point[0], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.WhitePointY = FFMIN(hb_rescale_rational(job->mastering.white_point[1], masteringChromaDen), masteringChromaDen); - pv->param.masteringDisplayColourVolume.MaxDisplayMasteringLuminance = hb_rescale_rational(job->mastering.max_luminance, masteringLumaDen); - pv->param.masteringDisplayColourVolume.MinDisplayMasteringLuminance = FFMIN(hb_rescale_rational(job->mastering.min_luminance, masteringLumaDen), - pv->param.masteringDisplayColourVolume.MaxDisplayMasteringLuminance); - } - - /* Content light level */ - if (job->coll.max_cll && job->coll.max_fall) - { - pv->param.contentLightLevelInfo.InsertPayloadToggle = MFX_PAYLOAD_IDR; - pv->param.contentLightLevelInfo.MaxContentLightLevel = FFMIN(job->coll.max_cll, 65535); - pv->param.contentLightLevelInfo.MaxPicAverageLightLevel = FFMIN(job->coll.max_fall, 65535); - } - } - else if (pv->qsv_info->codec_id == MFX_CODEC_AV1) - { - const int masteringChromaDen = 1 << 16; - const int max_luma_den = 1 << 8; - const int min_luma_den = 1 << 14; - - /* Mastering display metadata */ - if (job->mastering.has_primaries && job->mastering.has_luminance) - { - pv->param.masteringDisplayColourVolume.InsertPayloadToggle = MFX_PAYLOAD_IDR; - pv->param.masteringDisplayColourVolume.DisplayPrimariesX[0] = hb_rescale_rational(job->mastering.display_primaries[0][0], masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesY[0] = hb_rescale_rational(job->mastering.display_primaries[0][1], masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesX[1] = hb_rescale_rational(job->mastering.display_primaries[1][0], masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesY[1] = hb_rescale_rational(job->mastering.display_primaries[1][1], masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesX[2] = hb_rescale_rational(job->mastering.display_primaries[2][0], masteringChromaDen); - pv->param.masteringDisplayColourVolume.DisplayPrimariesY[2] = hb_rescale_rational(job->mastering.display_primaries[2][1], masteringChromaDen); - pv->param.masteringDisplayColourVolume.WhitePointX = hb_rescale_rational(job->mastering.white_point[0], masteringChromaDen); - pv->param.masteringDisplayColourVolume.WhitePointY = hb_rescale_rational(job->mastering.white_point[1], masteringChromaDen); - pv->param.masteringDisplayColourVolume.MaxDisplayMasteringLuminance = hb_rescale_rational(job->mastering.max_luminance, max_luma_den); - pv->param.masteringDisplayColourVolume.MinDisplayMasteringLuminance = hb_rescale_rational(job->mastering.min_luminance, min_luma_den); - } - - /* Content light level */ - if (job->coll.max_cll && job->coll.max_fall) - { - pv->param.contentLightLevelInfo.InsertPayloadToggle = MFX_PAYLOAD_IDR; - pv->param.contentLightLevelInfo.MaxContentLightLevel = job->coll.max_cll; - pv->param.contentLightLevelInfo.MaxPicAverageLightLevel = job->coll.max_fall; - } - } - } - - // parse user-specified encoder options, if present - if (job->encoder_options != NULL && *job->encoder_options) - { - hb_dict_t *options_list; - options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec); - - hb_dict_iter_t iter; - for (iter = hb_dict_iter_init(options_list); - iter != HB_DICT_ITER_DONE; - iter = hb_dict_iter_next(options_list, iter)) - { - const char *key = hb_dict_iter_key(iter); - hb_value_t *value = hb_dict_iter_value(iter); - char *str = hb_value_get_string_xform(value); - - switch (hb_qsv_param_parse(&pv->param, pv->qsv_info, pv->job, key, str)) - { - case HB_QSV_PARAM_OK: - break; - - case HB_QSV_PARAM_BAD_NAME: - hb_log("encqsvInit: hb_qsv_param_parse: bad key %s", key); - break; - case HB_QSV_PARAM_BAD_VALUE: - hb_log("encqsvInit: hb_qsv_param_parse: bad value %s for key %s", - str, key); - break; - case HB_QSV_PARAM_UNSUPPORTED: - hb_log("encqsvInit: hb_qsv_param_parse: unsupported option %s", - key); - break; - - case HB_QSV_PARAM_ERROR: - default: - hb_log("encqsvInit: hb_qsv_param_parse: unknown error"); - break; - } - free(str); - } - hb_dict_free(&options_list); - } -#if defined(_WIN32) || defined(__MINGW32__) - if (pv->is_sys_mem && hb_qsv_implementation_is_hardware(pv->qsv_info->implementation)) - { - mfxIMPL hw_preference = MFX_IMPL_VIA_D3D11; - pv->qsv_info->implementation = hb_qsv_dx_index_to_impl(job->qsv.ctx->dx_index) | hw_preference; - } -#endif - // reload colorimetry in case values were set in encoder_options - if (pv->param.videoSignalInfo.ColourDescriptionPresent) - { - job->color_prim_override = pv->param.videoSignalInfo.ColourPrimaries; - job->color_transfer_override = pv->param.videoSignalInfo.TransferCharacteristics; - job->color_matrix_override = pv->param.videoSignalInfo.MatrixCoefficients; - } - - // sanitize values that may exceed the Media SDK variable size - hb_rational_t par; - hb_limit_rational(&par.num, &par.den, - job->par.num, job->par.den, UINT16_MAX); - - // some encoding parameters are used by filters to configure their output - int align_width = 0, align_height = 0; - - switch (pv->qsv_info->codec_id) - { - case MFX_CODEC_HEVC: - case MFX_CODEC_AV1: - align_width = HB_QSV_ALIGN32(job->width); - align_height = HB_QSV_ALIGN32(job->height); - break; - - case MFX_CODEC_AVC: - default: - align_width = HB_QSV_ALIGN16(job->width); - align_height = HB_QSV_ALIGN16(job->height); - break; - } - if (pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE) - { - // additional alignment may be required - switch (pv->qsv_info->codec_id) - { - case MFX_CODEC_AVC: - align_height = HB_QSV_ALIGN32(align_height); - break; - - default: - break; - } - } - - // set codec, profile/level and FrameInfo - pv->param.videoParam->mfx.CodecId = pv->qsv_info->codec_id; - pv->param.videoParam->mfx.CodecLevel = MFX_LEVEL_UNKNOWN; - pv->param.videoParam->mfx.CodecProfile = MFX_PROFILE_UNKNOWN; - pv->param.videoParam->mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; - pv->param.videoParam->mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; - pv->param.videoParam->mfx.FrameInfo.FrameRateExtN = job->vrate.num; - pv->param.videoParam->mfx.FrameInfo.FrameRateExtD = job->vrate.den; - pv->param.videoParam->mfx.FrameInfo.AspectRatioW = par.num; - pv->param.videoParam->mfx.FrameInfo.AspectRatioH = par.den; - pv->param.videoParam->mfx.FrameInfo.CropX = 0; - pv->param.videoParam->mfx.FrameInfo.CropY = 0; - pv->param.videoParam->mfx.FrameInfo.CropW = job->width; - pv->param.videoParam->mfx.FrameInfo.CropH = job->height; - pv->param.videoParam->mfx.FrameInfo.Width = align_width; - pv->param.videoParam->mfx.FrameInfo.Height = align_height; - - // parse user-specified codec profile and level - if (hb_qsv_profile_parse(&pv->param, pv->qsv_info, job->encoder_profile, job->vcodec)) - { - hb_error("encqsvInit: bad profile %s", job->encoder_profile); - return -1; - } - - if (hb_qsv_level_parse(&pv->param, pv->qsv_info, job->encoder_level)) - { - hb_error("encqsvInit: bad level %s", job->encoder_level); - return -1; - } - - if ((pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_HEVC_MAIN10) || (job->vcodec == HB_VCODEC_QSV_AV1_10BIT)) - { - pv->param.videoParam->mfx.FrameInfo.FourCC = MFX_FOURCC_P010; - pv->param.videoParam->mfx.FrameInfo.BitDepthLuma = 10; - pv->param.videoParam->mfx.FrameInfo.BitDepthChroma = 10; - pv->param.videoParam->mfx.FrameInfo.Shift = 1; - } - - // interlaced encoding is not always possible - if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_AVC && - pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE) - { - if (pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_AVC_CONSTRAINED_BASELINE || - pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_AVC_BASELINE || - pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_AVC_PROGRESSIVE_HIGH) - { - hb_error("encqsvInit: profile %s doesn't support interlaced encoding", - hb_qsv_profile_name(MFX_CODEC_AVC, - pv->param.videoParam->mfx.CodecProfile)); - return -1; - } - if ((pv->param.videoParam->mfx.CodecLevel >= MFX_LEVEL_AVC_1b && - pv->param.videoParam->mfx.CodecLevel <= MFX_LEVEL_AVC_2) || - (pv->param.videoParam->mfx.CodecLevel >= MFX_LEVEL_AVC_42)) - { - hb_error("encqsvInit: level %s doesn't support interlaced encoding", - hb_qsv_level_name(MFX_CODEC_AVC, - pv->param.videoParam->mfx.CodecLevel)); - return -1; - } - } - - int hw_generation = hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())); - // sanitize ICQ - // workaround for MediaSDK platforms below TGL to disable ICQ if incorrectly detected - if (!(pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_ICQ) || - ((pv->param.videoParam->mfx.LowPower == MFX_CODINGOPTION_ON) && (hw_generation < QSV_G8))) - { - // ICQ not supported - pv->param.rc.icq = 0; - } - else - { - pv->param.rc.icq = pv->param.rc.icq && job->vquality > HB_INVALID_VIDEO_QUALITY; - } - - // 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)) - { - // 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 && (pv->param.rc.icq || job->vquality <= HB_INVALID_VIDEO_QUALITY); - } - - if (pv->job->qsv.ctx != NULL) - { - job->qsv.ctx->la_is_enabled = pv->param.rc.lookahead ? 1 : 0; - } - - // libmfx BRC parameters are 16 bits thus maybe overflow, then BRCParamMultiplier is needed - // Comparison vbitrate in Kbps (kilobit) with vbv_max_bitrate, vbv_buffer_size, vbv_buffer_init in KB (kilobyte) - brc_param_multiplier = (FFMAX(FFMAX3(job->vbitrate, pv->param.rc.vbv_max_bitrate, pv->param.rc.vbv_buffer_size), - pv->param.rc.vbv_buffer_init) + 0x10000) / 0x10000; - // set VBV here (this will be overridden for CQP and ignored for LA) - // only set BufferSizeInKB, InitialDelayInKB and MaxKbps if we have - // them - otherwise 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) / brc_param_multiplier; - } - 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) / brc_param_multiplier; - } - pv->param.videoParam->mfx.BufferSizeInKB = (pv->param.rc.vbv_buffer_size / 8) / brc_param_multiplier; - pv->param.videoParam->mfx.BRCParamMultiplier = brc_param_multiplier; - } - if (pv->param.rc.vbv_max_bitrate > 0) - { - pv->param.videoParam->mfx.MaxKbps = pv->param.rc.vbv_max_bitrate / brc_param_multiplier; - pv->param.videoParam->mfx.BRCParamMultiplier = brc_param_multiplier; - } - - // set rate control parameters - if (job->vquality > HB_INVALID_VIDEO_QUALITY) - { - unsigned int upper_limit = 51; - - if (pv->param.rc.icq) - { - // 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, upper_limit, job->vquality); - } - else - { - // introduced in API 1.1 - // HEVC 10b has QP range as [-12;51] - // with shift +12 needed to be in QSV's U16 range - if (pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_HEVC_MAIN10) - { - upper_limit = 63; - } - if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_AV1) - { - upper_limit = 255; - } - - pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CQP; - pv->param.videoParam->mfx.QPI = HB_QSV_CLIP3(0, upper_limit, job->vquality + pv->param.rc.cqp_offsets[0]); - pv->param.videoParam->mfx.QPP = HB_QSV_CLIP3(0, upper_limit, job->vquality + pv->param.rc.cqp_offsets[1]); - pv->param.videoParam->mfx.QPB = HB_QSV_CLIP3(0, upper_limit, 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 / brc_param_multiplier; - pv->param.videoParam->mfx.BRCParamMultiplier = brc_param_multiplier; - // ignored, but some drivers will change AsyncDepth because of it - pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF; - } - else - { - // introduced in API 1.0 - if (job->vbitrate == pv->param.rc.vbv_max_bitrate) - { - pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CBR; - } - else - { - pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_VBR; - } - pv->param.videoParam->mfx.TargetKbps = job->vbitrate / brc_param_multiplier; - pv->param.videoParam->mfx.BRCParamMultiplier = brc_param_multiplier; - } - } - else - { - hb_error("encqsvInit: invalid rate control (%f, %d)", - job->vquality, 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 the GOP structure - if (pv->param.gop.gop_ref_dist < 0) - { - if ((hw_generation >= QSV_G8) && - (pv->param.videoParam->mfx.CodecId == MFX_CODEC_HEVC || - pv->param.videoParam->mfx.CodecId == MFX_CODEC_AV1)) - { - pv->param.gop.gop_ref_dist = 8; - } - else - { - pv->param.gop.gop_ref_dist = 4; - } - } - pv->param.videoParam->mfx.GopRefDist = pv->param.gop.gop_ref_dist; - - // set the keyframe interval - if (pv->param.gop.gop_pic_size < 0) - { - double rate = (double)job->orig_vrate.num / job->orig_vrate.den + 0.5; - // set the keyframe interval based on the framerate - pv->param.gop.gop_pic_size = (int)(FFMIN(rate * 2, 120)); - } - pv->param.videoParam->mfx.GopPicSize = pv->param.gop.gop_pic_size; - - // set the Hyper Encode structure - if (pv->param.hyperEncodeParam.Mode != MFX_HYPERMODE_OFF) - { - if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_HEVC) - { - pv->param.videoParam->mfx.IdrInterval = 1; - } - else if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_AVC) - { - pv->param.videoParam->mfx.IdrInterval = 0; - } - // sanitize some of the encoding parameters - pv->param.videoParam->mfx.GopPicSize = (int)(FFMIN(pv->param.gop.gop_pic_size, 60)); - pv->param.videoParam->AsyncDepth = (int)(FFMAX(pv->param.videoParam->AsyncDepth, 30)); - } - // sanitize some settings that affect memory consumption - if (!pv->is_sys_mem) - { - // limit these to avoid running out of resources (causes hang) - pv->param.videoParam->mfx.GopRefDist = FFMIN(pv->param.videoParam->mfx.GopRefDist, - pv->param.rc.lookahead ? 8 : 16); - pv->param.codingOption2.LookAheadDepth = FFMIN(pv->param.codingOption2.LookAheadDepth, - pv->param.rc.lookahead ? (48 - pv->param.videoParam->mfx.GopRefDist - - 3 * !pv->param.videoParam->mfx.GopRefDist) : 0); - } - else - { - // encode-only is a bit less sensitive to memory issues - pv->param.videoParam->mfx.GopRefDist = FFMIN(pv->param.videoParam->mfx.GopRefDist, 16); - pv->param.codingOption2.LookAheadDepth = FFMIN(pv->param.codingOption2.LookAheadDepth, - pv->param.rc.lookahead ? 100 : 0); - } - if (pv->param.rc.lookahead) - { - // LookAheadDepth 10 will cause a hang with some driver versions - pv->param.codingOption2.LookAheadDepth = FFMAX(pv->param.codingOption2.LookAheadDepth, 11); - } - /* - * We may need to adjust GopRefDist, GopPicSize and - * NumRefFrame to enable or disable B-pyramid, so do it last. - */ - qsv_handle_breftype(pv); - - /* - * init a dummy encode-only session to get the SPS/PPS - * and the final output settings sanitized by Media SDK - * this is fine since the actual encode will use the same - * values for all parameters relevant to the output bitstream - */ - int err; - mfxStatus sts; - mfxVersion version; - mfxVideoParam videoParam; - mfxExtBuffer *extParamArray[HB_QSV_ENC_NUM_EXT_PARAM_MAX]; - mfxSession session = (mfxSession)0; - mfxExtCodingOption option1_buf, *option1 = &option1_buf; - mfxExtCodingOption2 option2_buf, *option2 = &option2_buf; - mfxExtAV1ScreenContentTools screencont_coding_buf, *screencont_coding = &screencont_coding_buf; - mfxExtCodingOptionSPSPPS sps_pps_buf, *sps_pps = &sps_pps_buf; - mfxExtAV1BitstreamParam av1_bitstream_buf, *av1_bitstream = &av1_bitstream_buf; - mfxExtChromaLocInfo chroma_loc_info_buf, *chroma_loc_info = &chroma_loc_info_buf; - mfxExtMasteringDisplayColourVolume mastering_display_color_volume_buf, *mastering_display_color_volume = &mastering_display_color_volume_buf; - mfxExtContentLightLevelInfo content_light_level_info_buf, *content_light_level_info = &content_light_level_info_buf; - mfxExtHyperModeParam hyper_encode_buf, *hyper_encode = &hyper_encode_buf; - version.Major = HB_QSV_MINVERSION_MAJOR; - version.Minor = HB_QSV_MINVERSION_MINOR; - uint32_t render_node = hb_qsv_get_adapter_render_node(hb_qsv_get_adapter_index()); - sts = hb_qsv_create_mfx_session(pv->qsv_info->implementation, render_node, &version, &session); - if (sts != MFX_ERR_NONE) - { - hb_error("encqsvInit: MFXInit failed (%d) with implementation %d", sts, pv->qsv_info->implementation); - return -1; - } - - if (pv->qsv_info->implementation & MFX_IMPL_HARDWARE_ANY) - { - // On linux, the handle to the VA display must be set. - // This code is essentially a NOP other platforms. - job->qsv.ctx->display = hb_qsv_display_init(render_node); - if (job->qsv.ctx->display != NULL) - { - MFXVideoCORE_SetHandle(session, job->qsv.ctx->display->mfxType, - (mfxHDL)job->qsv.ctx->display->handle); - } - } - - /* Query the API version for hb_qsv_load_plugins */ - sts = MFXQueryVersion(session, &version); - if (sts != MFX_ERR_NONE) - { - hb_error("encqsvInit: MFXQueryVersion failed (%d)", sts); - MFXClose(session); - return -1; - } - - /* MFXVideoENCODE_Init with desired encoding parameters */ - sts = MFXVideoENCODE_Init(session, pv->param.videoParam); - if (sts < MFX_ERR_NONE) // ignore warnings - { - hb_error("encqsvInit: MFXVideoENCODE_Init failed (%d)", sts); - err = log_encoder_params(pv, pv->param.videoParam); - if (err < 0) - { - hb_error("encqsvInit: log_encoder_params failed (%d)", err); - } - MFXClose(session); - return -1; - } - /* Prepare the structures for query */ - memset(&videoParam, 0, sizeof(mfxVideoParam)); - videoParam.ExtParam = extParamArray; - videoParam.NumExtParam = 0; - - uint8_t sps[HB_CONFIG_MAX_SIZE]; - uint8_t pps[HB_CONFIG_MAX_SIZE]; - - // introduced in API 1.3 - memset(sps_pps, 0, sizeof(mfxExtCodingOptionSPSPPS)); - sps_pps->Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS; - sps_pps->Header.BufferSz = sizeof(mfxExtCodingOptionSPSPPS); - sps_pps->SPSId = 0; - sps_pps->SPSBuffer = sps; - sps_pps->SPSBufSize = sizeof(sps); - sps_pps->PPSId = 0; - sps_pps->PPSBuffer = pps; - sps_pps->PPSBufSize = sizeof(pps); - if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_AVC) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)sps_pps; - } - // introduced in API 1.0 - memset(option1, 0, sizeof(mfxExtCodingOption)); - option1->Header.BufferId = MFX_EXTBUFF_CODING_OPTION; - option1->Header.BufferSz = sizeof(mfxExtCodingOption); - if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION1) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)option1; - } - // introduced in API 1.6 - memset(option2, 0, sizeof(mfxExtCodingOption2)); - option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; - option2->Header.BufferSz = sizeof(mfxExtCodingOption2); - if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)option2; - } - // introduced in API 2.5 - memset(av1_bitstream, 0, sizeof(mfxExtAV1BitstreamParam)); - av1_bitstream->Header.BufferId = MFX_EXTBUFF_AV1_BITSTREAM_PARAM; - av1_bitstream->Header.BufferSz = sizeof(mfxExtAV1BitstreamParam); - if (pv->qsv_info->capabilities & HB_QSV_CAP_AV1_BITSTREAM) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)av1_bitstream; - } - memset(chroma_loc_info, 0, sizeof(mfxExtChromaLocInfo)); - chroma_loc_info->Header.BufferId = MFX_EXTBUFF_CHROMA_LOC_INFO; - chroma_loc_info->Header.BufferSz = sizeof(mfxExtChromaLocInfo); - if (pv->qsv_info->capabilities & HB_QSV_CAP_VUI_CHROMALOCINFO) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)chroma_loc_info; - } - memset(mastering_display_color_volume, 0, sizeof(mfxExtMasteringDisplayColourVolume)); - mastering_display_color_volume->Header.BufferId = MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME; - mastering_display_color_volume->Header.BufferSz = sizeof(mfxExtMasteringDisplayColourVolume); - if (pv->qsv_info->capabilities & HB_QSV_CAP_VUI_MASTERINGINFO) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)mastering_display_color_volume; - } - memset(content_light_level_info, 0, sizeof(mfxExtContentLightLevelInfo)); - content_light_level_info->Header.BufferId = MFX_EXTBUFF_CONTENT_LIGHT_LEVEL_INFO; - content_light_level_info->Header.BufferSz = sizeof(mfxExtContentLightLevelInfo); - if (pv->qsv_info->capabilities & HB_QSV_CAP_VUI_CLLINFO) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)content_light_level_info; - } - memset(hyper_encode, 0, sizeof(mfxExtHyperModeParam)); - hyper_encode->Header.BufferId = MFX_EXTBUFF_HYPER_MODE_PARAM; - hyper_encode->Header.BufferSz = sizeof(mfxExtHyperModeParam); - if (pv->qsv_info->capabilities & HB_QSV_CAP_HYPERENCODE) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)hyper_encode; - } - memset(screencont_coding, 0, sizeof(mfxExtAV1ScreenContentTools)); - screencont_coding->Header.BufferId = MFX_EXTBUFF_AV1_SCREEN_CONTENT_TOOLS; - screencont_coding->Header.BufferSz = sizeof(mfxExtAV1ScreenContentTools); - if (pv->qsv_info->capabilities & HB_QSV_CAP_AV1_SCREENCONTENT) - { - videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)screencont_coding; - } - /* Query actual encoding parameters after MFXVideoENCODE_Init, some of them could be overridden */ - sts = MFXVideoENCODE_GetVideoParam(session, &videoParam); - if (sts != MFX_ERR_NONE) - { - hb_error("encqsvInit: MFXVideoENCODE_GetVideoParam failed (%d)", sts); - MFXClose(session); - return -1; - } - - /* We have the final encoding parameters, now get the headers for muxing */ - if (videoParam.mfx.CodecId == MFX_CODEC_AVC) - { - // remove 4-byte Annex B NAL unit prefix (0x00 0x00 0x00 0x01) - hb_set_h264_extradata(w->extradata, - sps + 4, sps_pps->SPSBufSize - 4, - pps + 4, sps_pps->PPSBufSize - 4); - } - else if (videoParam.mfx.CodecId == MFX_CODEC_HEVC) - { - if (qsv_hevc_make_header(w, session, &videoParam) < 0) - { - hb_error("encqsvInit: qsv_hevc_make_header failed"); - MFXVideoENCODE_Close(session); - MFXClose(session); - return -1; - } - } - - /* We don't need this encode session once we have the header */ - MFXVideoENCODE_Close(session); - - // when using system memory, we re-use this same session - if (pv->is_sys_mem) - { - pv->mfx_session = session; - } - else - { - MFXClose(session); - } - - /* B-frame related setup */ - if (videoParam.mfx.GopRefDist > 1) - { - /* the muxer needs to know to the init_delay */ - switch (videoParam.mfx.CodecId) - { - case MFX_CODEC_AVC: - case MFX_CODEC_HEVC: - pv->init_delay = w->init_delay; - break; - default: - break; - } - - /* let the muxer know that it should expect B-frames */ - job->areBframes = 1; - - /* holds the PTS sequence in display order, used to generate DTS */ - pv->list_dts = hb_list_init(); - } - - err = log_encoder_params(pv, &videoParam); - if (err < 0) - { - hb_error("encqsvInit: log_encoder_params failed (%d)", err); - return -1; - } - pv->param.videoParam->mfx = videoParam.mfx; - // AsyncDepth has now been set and/or modified by Media SDK - // fall back to default if zero - pv->max_async_depth = videoParam.AsyncDepth ? videoParam.AsyncDepth : hb_qsv_param_default_async_depth(); - pv->async_depth = 0; - - return 0; -} - -void encqsvClose(hb_work_object_t *w) -{ - hb_work_private_t *pv = w->private_data; - int i; - - if (pv != NULL && pv->job != NULL && pv->job->qsv.ctx != NULL && - pv->job->qsv.ctx->is_context_active) - { - - hb_qsv_context *qsv_ctx = pv->job->qsv.ctx; - hb_qsv_space *qsv_enc_space = pv->job->qsv.ctx->enc_space; - - if (qsv_ctx != NULL) - { - hb_qsv_uninit_enc(pv->job); - if (qsv_enc_space != NULL) - { - if (qsv_enc_space->is_init_done) - { - for (i = hb_qsv_list_count(qsv_enc_space->tasks); i >= 1; i--) - { - hb_qsv_task *task = hb_qsv_list_item(qsv_enc_space->tasks, - i - 1); - if (task != NULL) - { - if (task->bs != NULL) - { - av_freep(&task->bs->Data); - } - hb_qsv_list_rem(qsv_enc_space->tasks, task); - av_freep(&task->bs); - av_freep(&task); - } - } - hb_qsv_list_close(&qsv_enc_space->tasks); - - for (i = 0; i < qsv_enc_space->surface_num; i++) - { - if (pv->is_sys_mem) - { - av_freep(&qsv_enc_space->p_surfaces[i]->Data.Y); - } - av_freep(&qsv_enc_space->p_surfaces[i]); - } - qsv_enc_space->surface_num = 0; - - for (i = 0; i < qsv_enc_space->sync_num; i++) - { - av_freep(&qsv_enc_space->p_syncp[i]->p_sync); - av_freep(&qsv_enc_space->p_syncp[i]); - } - qsv_enc_space->sync_num = 0; - } - qsv_enc_space->is_init_done = 0; - } - } - } - - if (pv != NULL) - { - hb_chapter_queue_close(&pv->chapter_queue); - if (pv->delayed_processing != NULL) - { - /* the list is already empty */ - hb_list_close(&pv->delayed_processing); - } - if (pv->list_dts != NULL) - { - int64_t *item; - while ((item = hb_list_item(pv->list_dts, 0)) != NULL) - { - hb_list_rem(pv->list_dts, item); - free(item); - } - hb_list_close(&pv->list_dts); - } - hb_buffer_list_close(&pv->encoded_frames); - } - - free(pv); - w->private_data = NULL; -} - -static void compute_init_delay(hb_work_private_t *pv, mfxBitstream *bs) -{ - if (pv->init_delay == NULL) - { - return; // not needed or already set - } - - /* - * In the MP4 container, DT(0) = STTS(0) = 0. - * - * Which gives us: - * CT(0) = CTTS(0) + STTS(0) = CTTS(0) = PTS(0) - DTS(0) - * When DTS(0) < PTS(0), we then have: - * CT(0) > 0 for video, but not audio (breaks A/V sync). - * - * This is typically solved by writing an edit list shifting - * video samples by the initial delay, PTS(0) - DTS(0). - * - * See: - * ISO/IEC 14496-12:2008(E), ISO base media file format - * - 8.6.1.2 Decoding Time to Sample Box - */ - if (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) - { - /* compute init_delay (in ticks) based on the DTS provided by MSDK. */ - int64_t init_delay = bs->TimeStamp - bs->DecodeTimeStamp; - - /* - * we also need to know the delay in frames to generate DTS. - * - * compute it based on the init_delay and average frame duration, - * and account for potential rounding errors due to the timebase. - */ - double avg_frame_dur = ((double)pv->job->vrate.den / - (double)pv->job->vrate.num * 90000.); - - pv->bfrm_delay = (init_delay + (avg_frame_dur / 2)) / avg_frame_dur; - - if (pv->bfrm_delay < 1 || pv->bfrm_delay > BFRM_DELAY_MAX) - { - hb_log("compute_init_delay: " - "invalid delay %d (PTS: %llu, DTS: %lld)", - pv->bfrm_delay, bs->TimeStamp, bs->DecodeTimeStamp); - - /* we have B-frames, the frame delay should be at least 1 */ - if (pv->bfrm_delay < 1) - { - mfxStatus sts; - mfxVideoParam videoParam; - mfxSession session = pv->job->qsv.ctx->mfx_session; - - memset(&videoParam, 0, sizeof(mfxVideoParam)); - - sts = MFXVideoENCODE_GetVideoParam(session, &videoParam); - if (sts != MFX_ERR_NONE) - { - hb_log("compute_init_delay: " - "MFXVideoENCODE_GetVideoParam failed (%d)", sts); - pv->bfrm_delay = 1; - } - else - { - /* usually too large, but should cover all cases */ - pv->bfrm_delay = FFMIN(pv->frames_in - 1, - videoParam.mfx.GopRefDist - 1); - } - } - - pv->bfrm_delay = FFMIN(BFRM_DELAY_MAX, pv->bfrm_delay); - } - - pv->init_delay[0] = pv->init_pts[pv->bfrm_delay] - pv->init_pts[0]; - } - else - { - /* - * we can't get the DTS from MSDK, so we need to generate our own. - * - * B-pyramid not possible here, so the delay in frames is always 1. - */ - pv->bfrm_delay = 1; - pv->init_delay[0] = pv->init_pts[1] - pv->init_pts[0]; - } - - /* This can come in handy */ - hb_deep_log(2, "compute_init_delay: %d (%d frames)", pv->init_delay[0], pv->bfrm_delay); - - /* The delay only needs to be set once. */ - pv->init_delay = NULL; -} - -static void qsv_bitstream_slurp(hb_work_private_t *pv, mfxBitstream *bs) -{ - hb_buffer_t *buf; - - if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_AVC) - { - /* - * We provided the muxer with the parameter sets in an MP4-compatible - * format (ISO/IEC 14496-15). We need to convert the bitstream to the - * same format to match the extradata. - */ - if ((buf = hb_nal_bitstream_annexb_to_mp4(bs->Data + bs->DataOffset, - bs->DataLength)) == NULL) - { - hb_error("encqsv: hb_nal_bitstream_annexb_to_mp4 failed"); - goto fail; - } - } - else - { - /* Both extradata and bitstream are in Annex B format. */ - if ((buf = hb_buffer_init(bs->DataLength)) == NULL) - { - hb_error("encqsv: hb_buffer_init failed"); - goto fail; - } - memcpy(buf->data, bs->Data + bs->DataOffset, bs->DataLength); - } - bs->DataLength = bs->DataOffset = 0; - bs->MaxLength = pv->job->qsv.ctx->enc_space->p_buf_max_size; - - buf->s.frametype = hb_qsv_frametype_xlat(bs->FrameType, &buf->s.flags); - if (pv->param.videoParam->mfx.CodecId == MFX_CODEC_HEVC) - { - size_t len = buf->size; - uint8_t *pos = buf->data; - uint8_t *end = pos + len; - while ((pos = hb_annexb_find_next_nalu(pos, &len)) != NULL) - { - if (HB_HEVC_NALU_KEYFRAME((pos[0] >> 1) & 0x3f)) - { - buf->s.flags |= HB_FLAG_FRAMETYPE_KEY; - break; - } - len = end - pos; - continue; - } - } - buf->s.start = buf->s.renderOffset = bs->TimeStamp; - buf->s.stop = buf->s.start + get_frame_duration(pv, buf); - buf->s.duration = buf->s.stop - buf->s.start; - - /* compute the init_delay before setting the DTS */ - compute_init_delay(pv, bs); - - /* - * Generate VFR-compatible output DTS based on input PTS. - * - * Depends on the B-frame delay: - * - * 0: ipts0, ipts1, ipts2... - * 1: ipts0 - ipts1, ipts1 - ipts1, ipts1, ipts2... - * 2: ipts0 - ipts2, ipts1 - ipts2, ipts2 - ipts2, ipts1... - * ...and so on. - */ - if (pv->bfrm_delay) - { - if (pv->frames_out <= pv->bfrm_delay) - { - buf->s.renderOffset = (pv->init_pts[pv->frames_out] - - pv->init_pts[pv->bfrm_delay]); - } - else - { - buf->s.renderOffset = hb_qsv_pop_next_dts(pv->list_dts); - } - } - - /* check if B-pyramid is used even though it's disabled */ - if ((pv->param.gop.b_pyramid == 0) && - (bs->FrameType & MFX_FRAMETYPE_B) && - (bs->FrameType & MFX_FRAMETYPE_REF)) - { - hb_log("encqsv: BPyramid off not respected (delay: %d)", pv->bfrm_delay); - - /* don't pollute the log unnecessarily */ - pv->param.gop.b_pyramid = 1; - } - - /* check for PTS < DTS */ - if (buf->s.start < buf->s.renderOffset) - { - hb_log("encqsv: PTS %"PRId64" < DTS %"PRId64" for frame %d with type '%s'", - buf->s.start, buf->s.renderOffset, pv->frames_out + 1, - hb_qsv_frametype_name(bs->FrameType)); - } - - /* - * If we have a chapter marker pending and this frame's PTS - * is at or after the marker's PTS, use it as the chapter start. - */ - if (buf->s.flags & HB_FLAG_FRAMETYPE_KEY) - { - hb_chapter_dequeue(pv->chapter_queue, buf); - } - - hb_buffer_list_append(&pv->encoded_frames, buf); - pv->frames_out++; - return; - -fail: - *pv->job->done_error = HB_ERROR_UNKNOWN; - *pv->job->die = 1; -} - -static int qsv_enc_work(hb_work_private_t *pv, - hb_qsv_list *qsv_atom, - mfxFrameSurface1 *surface, - HBQSVFramesContext *frames_ctx) -{ - int err; - mfxStatus sts; - hb_qsv_context *qsv_ctx = pv->job->qsv.ctx; - hb_qsv_space *qsv_enc_space = pv->job->qsv.ctx->enc_space; - - do - { - int sync_idx = hb_qsv_get_free_sync(qsv_enc_space, qsv_ctx); - if (sync_idx == -1) - { - hb_error("encqsv: hb_qsv_get_free_sync failed"); - return -1; - } - hb_qsv_task *task = hb_qsv_list_item(qsv_enc_space->tasks, - pv->async_depth); - - do - { - sts = MFXVideoENCODE_EncodeFrameAsync(qsv_ctx->mfx_session, - NULL, surface, task->bs, - qsv_enc_space->p_syncp[sync_idx]->p_sync); - - if (sts == MFX_ERR_MORE_DATA) - { - if(!pv->is_sys_mem && surface) - { - hb_qsv_release_surface_from_pool_by_surface_pointer(frames_ctx, surface); - } - - if (qsv_atom != NULL) - { - hb_list_add(pv->delayed_processing, qsv_atom); - } - ff_qsv_atomic_dec(&qsv_enc_space->p_syncp[sync_idx]->in_use); - break; - } - else if (sts < MFX_ERR_NONE) - { - hb_error("encqsv: MFXVideoENCODE_EncodeFrameAsync failed (%d)", sts); - return -1; - } - else if (sts == MFX_WRN_DEVICE_BUSY) - { - hb_qsv_sleep(10); // device is busy, wait then repeat the call - continue; - } - else - { - hb_qsv_stage *new_stage = hb_qsv_stage_init(); - new_stage->type = HB_QSV_ENCODE; - new_stage->in.p_surface = surface; - new_stage->in.p_frames_ctx = frames_ctx; - new_stage->out.sync = qsv_enc_space->p_syncp[sync_idx]; - new_stage->out.p_bs = task->bs; - task->stage = new_stage; - pv->async_depth++; - - if(!pv->is_sys_mem && surface) - { - hb_qsv_release_surface_from_pool_by_surface_pointer(frames_ctx, surface); - } - - if (qsv_atom != NULL) - { - hb_qsv_add_stagee(&qsv_atom, new_stage, HAVE_THREADS); - } - else - { - /* encode-only or flushing */ - hb_qsv_list *new_qsv_atom = hb_qsv_list_init(HAVE_THREADS); - hb_qsv_add_stagee(&new_qsv_atom, new_stage, HAVE_THREADS); - hb_qsv_list_add (qsv_ctx->pipes, new_qsv_atom); - } - - int i = hb_list_count(pv->delayed_processing); - while (--i >= 0) - { - hb_qsv_list *item = hb_list_item(pv->delayed_processing, i); - - if (item != NULL) - { - hb_list_rem(pv->delayed_processing, item); - hb_qsv_flush_stages(qsv_ctx->pipes, &item, 1); - } - } - break; - } - - ff_qsv_atomic_dec(&qsv_enc_space->p_syncp[sync_idx]->in_use); - break; - } - while (sts >= MFX_ERR_NONE); - - do - { - if (pv->async_depth == 0) break; - - /* we've done enough asynchronous operations or we're flushing */ - if (pv->async_depth >= pv->max_async_depth || surface == NULL) - { - hb_qsv_task *task = hb_qsv_list_item(qsv_enc_space->tasks, 0); - pv->async_depth--; - - /* perform a sync operation to get the output bitstream */ - err = hb_qsv_wait_on_sync(qsv_ctx, task->stage); - if (err < 0) - { - hb_error("encqsv: hb_qsv_wait_on_sync failed (%d)", err); - return err; - } - - if (task->bs->DataLength > 0) - { - hb_qsv_list *pipe = hb_qsv_pipe_by_stage(qsv_ctx->pipes, - task->stage); - hb_qsv_flush_stages(qsv_ctx->pipes, &pipe, 1); - - /* get the encoded frame from the bitstream */ - qsv_bitstream_slurp(pv, task->bs); - - /* shift for fifo */ - if (pv->async_depth) - { - hb_qsv_list_rem(qsv_enc_space->tasks, task); - hb_qsv_list_add(qsv_enc_space->tasks, task); - } - task->stage = NULL; - } - } - } - while (surface == NULL); - } - while (surface == NULL && sts != MFX_ERR_MORE_DATA); - - return 0; -} - -int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out) -{ - int err; - hb_work_private_t *pv = w->private_data; - hb_buffer_t *in = *buf_in; - hb_job_t *job = pv->job; - while (qsv_enc_init(pv) >= 2) - { - hb_qsv_sleep(1); // encoding not initialized, wait and repeat the call - } - - if (*job->die) - { - goto fail; // unrecoverable error, don't attempt to encode - } - - /* - * EOF on input. Flush the decoder, then send the - * EOF downstream to let the muxer know we're done. - */ - if (in->s.flags & HB_BUF_FLAG_EOF) - { - err = qsv_enc_work(pv, NULL, NULL, NULL); - if (err < 0) - { - hb_error("encqsvWork: EOF qsv_enc_work failed %d", err); - goto fail; - } - hb_buffer_list_append(&pv->encoded_frames, in); - *buf_out = hb_buffer_list_clear(&pv->encoded_frames); - *buf_in = NULL; // don't let 'work_loop' close this buffer - return HB_WORK_DONE; - } - - mfxFrameSurface1 *surface = NULL; - HBQSVFramesContext *frames_ctx = NULL; - hb_qsv_list *qsv_atom = NULL; - hb_qsv_context *qsv_ctx = job->qsv.ctx; - hb_qsv_space *qsv_enc_space = job->qsv.ctx->enc_space; - - if (pv->is_sys_mem) - { - mfxFrameInfo *info = &pv->param.videoParam->mfx.FrameInfo; - int surface_index = hb_qsv_get_free_surface(qsv_enc_space, qsv_ctx, info, - QSV_PART_ANY); - if (surface_index == -1) - { - hb_error("encqsv: hb_qsv_get_free_surface failed"); - goto fail; - } - - surface = qsv_enc_space->p_surfaces[surface_index]; - qsv_copy_buffer_to_surface(surface, in); - } - else - { - QSVMid *mid = NULL; - AVFrame *frame = (AVFrame *)in->storage; - if (frame && frame->data[3]) - { - surface = ((mfxFrameSurface1*)frame->data[3]); - frames_ctx = in->qsv_details.qsv_frames_ctx; - hb_qsv_get_mid_by_surface_from_pool(frames_ctx, surface, &mid); - hb_qsv_replace_surface_mid(frames_ctx, mid, surface); - } - else - { - hb_error("encqsv: in->qsv_details no surface available"); - goto fail; - } - - // At this point, enc_qsv takes ownership of the QSV resources - // in the 'in' buffer. - in->qsv_details.qsv_atom = NULL; - - /* - * QSV decoding fills the QSV context's dts_seq list, we need to - * pop this surface's DTS so dts_seq doesn't grow unnecessarily. - */ - hb_qsv_dts_pop(qsv_ctx); - } - - /* - * Debugging code to check that the upstream modules have generated - * a continuous, self-consistent frame stream. - */ - if (pv->last_start > in->s.start) - { - hb_log("encqsv: input continuity error, " - "last start %"PRId64" start %"PRId64"", - pv->last_start, in->s.start); - } - pv->last_start = in->s.start; - - /* for DTS generation */ - if (pv->frames_in <= BFRM_DELAY_MAX) - { - pv->init_pts[pv->frames_in] = in->s.start; - } - if (pv->frames_in) - { - hb_qsv_add_new_dts(pv->list_dts, in->s.start); - } - pv->frames_in++; - - /* - * Chapters have to start with a keyframe, so request one here. - * - * Using an mfxEncodeCtrl structure to force key frame generation is not - * possible when using a lookahead and frame reordering, so instead do - * the following before encoding the frame attached to the chapter: - * - * - flush the encoder to encode and retrieve any buffered frames - * - * - do a hard reset (MFXVideoENCODE_Close, then Init) of - * the encoder to make sure the next frame is a keyframe - * - * The hard reset ensures encoding resumes with a clean state, avoiding - * miscellaneous hard-to-diagnose issues that may occur when resuming - * an encode after flushing the encoder or using MFXVideoENCODE_Reset. - */ - if (in->s.new_chap > 0 && job->chapter_markers) - { - mfxStatus sts; - - err = qsv_enc_work(pv, NULL, NULL, NULL); - if (err < 0) - { - hb_error("encqsvWork: new_chap qsv_enc_work failed %d", err); - goto fail; - } - - sts = MFXVideoENCODE_Close(qsv_ctx->mfx_session); - if (sts != MFX_ERR_NONE) - { - hb_error("encqsv: MFXVideoENCODE_Close failed (%d)", sts); - goto fail; - } - - sts = MFXVideoENCODE_Init(qsv_ctx->mfx_session, pv->param.videoParam); - if (sts < MFX_ERR_NONE) - { - hb_error("encqsv: MFXVideoENCODE_Init failed (%d)", sts); - goto fail; - } - - hb_chapter_enqueue(pv->chapter_queue, in); - } - - /* - * If interlaced encoding is requested during encoder initialization, - * but the input mfxFrameSurface1 is flagged as progressive here, - * the output bitstream will be progressive (according to MediaInfo). - * - * Assume the user knows what he's doing (say he is e.g. encoding a - * progressive-flagged source using interlaced compression - he may - * well have a good reason to do so; mis-flagged sources do exist). - */ - surface->Info.PicStruct = pv->param.videoParam->mfx.FrameInfo.PicStruct; - surface->Data.TimeStamp = in->s.start; - save_frame_duration(pv, in); - - /* - * Now that the input surface is setup, we can encode it. - */ - err = qsv_enc_work(pv, qsv_atom, surface, frames_ctx); - if (err < 0) - { - hb_error("encqsvWork: qsv_enc_work failed %d", err); - goto fail; - } - - if (in->storage) - { - // FIXME: This looks weird - AVFrame *frame = (AVFrame *)in->storage; - frame->data[3] = 0; - } - - *buf_out = hb_buffer_list_clear(&pv->encoded_frames); - return HB_WORK_OK; - -fail: - if (*job->done_error == HB_ERROR_NONE) - { - *job->done_error = HB_ERROR_UNKNOWN; - } - *job->die = 1; - *buf_out = NULL; - return HB_WORK_ERROR; -} - -#endif // HB_PROJECT_FEATURE_QSV diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index 78bf79d08ac39..0236388820f87 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -19,6 +19,7 @@ #include "handbrake/nvenc_common.h" #include "handbrake/vce_common.h" #include "handbrake/extradata.h" +#include "handbrake/qsv_common.h" /* * The frame info struct remembers information about each frame across calls @@ -46,6 +47,10 @@ struct hb_work_private_s int64_t dts_delay; +#if HB_PROJECT_FEATURE_QSV + qsv_data_t qsv_data; +#endif + struct { int64_t start; int64_t duration; @@ -89,6 +94,16 @@ static const char * const vp9_tune_names[] = "screen", "film", NULL }; +static const char * const h264_qsv_profile_name[] = +{ + "auto", "high", "main", "baseline", NULL +}; + +static const char * const h265_qsv_profile_name[] = +{ + "auto", "main", "main10", "mainsp", NULL +}; + static const char * const h26x_nvenc_preset_names[] = { "fastest", "faster", "fast", "medium", "slow", "slower", "slowest", NULL @@ -157,6 +172,16 @@ static const enum AVPixelFormat standard_10bit_pix_fmts[] = AV_PIX_FMT_YUV420P10, AV_PIX_FMT_NONE }; +static const enum AVPixelFormat qsv_pix_formats[] = +{ + AV_PIX_FMT_NV12, AV_PIX_FMT_NONE +}; + +static const enum AVPixelFormat qsv_10bit_pix_formats[] = +{ + AV_PIX_FMT_P010LE, AV_PIX_FMT_NONE +}; + static const enum AVPixelFormat h26x_mf_pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_NONE @@ -251,6 +276,10 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) hb_log("encavcodecInit: H.264 (MediaFoundation)"); codec_name = "h264_mf"; break; + case HB_VCODEC_FFMPEG_QSV_H264: + hb_log("encavcodecInit: H.264 (Intel Quick Sync Video)"); + codec_name = "h264_qsv"; + break; } }break; case AV_CODEC_ID_HEVC: @@ -270,6 +299,11 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) hb_log("encavcodecInit: H.265 (MediaFoundation)"); codec_name = "hevc_mf"; break; + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + hb_log("encavcodecInit: H.265 (Intel Quick Sync Video)"); + codec_name = "hevc_qsv"; + break; } }break; case AV_CODEC_ID_AV1: @@ -284,6 +318,11 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) hb_log("encavcodecInit: AV1 (AMD VCE)"); codec_name = "av1_amf"; break; + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + hb_log("encavcodecInit: AV1 (Intel Quick Sync Video)"); + codec_name = "av1_qsv"; + break; case HB_VCODEC_FFMPEG_MF_AV1: hb_log("encavcodecInit: AV1 (MediaFoundation)"); codec_name = "av1_mf"; @@ -410,6 +449,13 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) goto done; } +#if HB_PROJECT_FEATURE_QSV + if (hb_qsv_is_ffmpeg_supported_codec(job->vcodec)) + { + hb_qsv_apply_encoder_options(&pv->qsv_data, job, &av_opts); + } +#endif + // Now set the things in context that we don't want to allow // the user to override. if (job->vquality <= HB_INVALID_VIDEO_QUALITY) @@ -426,6 +472,24 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) hb_log( "encavcodec: encoding at rc=vbr, Bitrate %d", job->vbitrate ); } +#if HB_PROJECT_FEATURE_QSV + if (hb_qsv_is_ffmpeg_supported_codec(job->vcodec)) + { + if (pv->qsv_data.param.rc.lookahead) + { + // introduced in API 1.7 + av_dict_set( &av_opts, "look_ahead", "1", 0 ); + } + + if (job->vbitrate == pv->qsv_data.param.rc.vbv_max_bitrate) + { + char maxrate[7]; + snprintf(maxrate, 7, "%.2f", context->bit_rate); + av_dict_set( &av_opts, "maxrate", maxrate, 0 ); + } + } +#endif + if ((job->vcodec == HB_VCODEC_FFMPEG_VCE_H264) || (job->vcodec == HB_VCODEC_FFMPEG_VCE_H265) || (job->vcodec == HB_VCODEC_FFMPEG_VCE_H265_10BIT) @@ -527,6 +591,20 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) av_dict_set( &av_opts, "init_qpI", qualityI, 0 ); hb_log( "encavcodec: encoding at rc=vbr, %.2f", job->vquality ); } +#if HB_PROJECT_FEATURE_QSV + else if (hb_qsv_is_ffmpeg_supported_codec(job->vcodec)) + { + context->bit_rate = 0; + if (pv->qsv_data.param.rc.icq) + { + char global_quality[7]; + int upper_limit = 51; + snprintf(global_quality, 7, "%d", HB_QSV_CLIP3(1, upper_limit, (int)job->vquality)); + av_dict_set(&av_opts, "global_quality", global_quality, 0); + hb_log("encavcodec: encoding with brc ICQ %s", global_quality); + } + } +#endif else if ( job->vcodec == HB_VCODEC_FFMPEG_VCE_H264 || job->vcodec == HB_VCODEC_FFMPEG_VCE_H265 || job->vcodec == HB_VCODEC_FFMPEG_VCE_H265_10BIT || @@ -621,11 +699,23 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) if (hb_hwaccel_is_full_hardware_pipeline_enabled(pv->job)) { context->hw_device_ctx = av_buffer_ref(pv->job->hw_device_ctx); - hb_hwaccel_hwframes_ctx_init(context, job); +#if HB_PROJECT_FEATURE_QSV + if (!hb_qsv_is_ffmpeg_supported_codec(job->vcodec)) +#endif + { + hb_hwaccel_hwframes_ctx_init(context, job); + } context->pix_fmt = job->hw_pix_fmt; } else { +#if HB_PROJECT_FEATURE_QSV + if (hb_qsv_is_ffmpeg_supported_codec(job->vcodec) && !job->hw_device_ctx) + { + hb_qsv_device_init(job, &job->hw_device_ctx); + context->hw_device_ctx = av_buffer_ref(job->hw_device_ctx); + } +#endif context->pix_fmt = job->output_pix_fmt; } @@ -838,6 +928,17 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) free(filename); } +#if HB_PROJECT_FEATURE_QSV + if (hb_hwaccel_is_full_hardware_pipeline_enabled(pv->job) && + hb_qsv_decode_is_enabled(job)) + { + pv->context = context; + pv->qsv_data.codec = codec; + pv->qsv_data.av_opts = av_opts; + return 0; + } +#endif + if (hb_avcodec_open(context, codec, &av_opts, HB_FFMPEG_THREADS_AUTO)) { hb_log( "encavcodecInit: avcodec_open failed" ); @@ -1164,6 +1265,50 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_DONE; } +#if HB_PROJECT_FEATURE_QSV + // postponed encoder initialization, reused code from encavcodecInit() + if (hb_hwaccel_is_full_hardware_pipeline_enabled(pv->job) && + hb_qsv_decode_is_enabled(pv->job) && pv->context->hw_frames_ctx == NULL && pv->job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx != NULL) + { + // use the same hw frames context as for decoder or filter graph hw frames context + pv->context->hw_frames_ctx = pv->job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx; + int open_ret = 0; + if ((open_ret = hb_avcodec_open(pv->context, pv->qsv_data.codec, &pv->qsv_data.av_opts, HB_FFMPEG_THREADS_AUTO))) + { + hb_log( "encavcodecWork: avcodec_open failed: %s", av_err2str(open_ret) ); + return HB_WORK_ERROR; + } + + /* + * Reload colorimetry settings in case custom + * values were set in the encoder_options string. + */ + pv->job->color_prim_override = pv->context->color_primaries; + pv->job->color_transfer_override = pv->context->color_trc; + pv->job->color_matrix_override = pv->context->colorspace; + + // avcodec_open populates the opts dictionary with the + // things it didn't recognize. + AVDictionaryEntry *t = NULL; + while( ( t = av_dict_get( pv->qsv_data.av_opts, "", t, AV_DICT_IGNORE_SUFFIX ) ) ) + { + hb_log( "encavcodecWork: Unknown avcodec option %s", t->key ); + } + + pv->job->areBframes = 0; + if (pv->context->has_b_frames > 0) + { + pv->job->areBframes = pv->context->has_b_frames; + } + + if (pv->context->extradata != NULL) + { + hb_set_extradata(w->extradata, pv->context->extradata, pv->context->extradata_size); + } + av_dict_free(&pv->qsv_data.av_opts); + } +#endif + hb_buffer_list_clear(&list); if (in->s.flags & HB_BUF_FLAG_EOF) { @@ -1205,6 +1350,13 @@ static int apply_options(hb_job_t *job, AVCodecContext *context, AVDictionary ** static int apply_encoder_options(hb_job_t *job, AVCodecContext *context, AVDictionary **av_opts) { +#if HB_PROJECT_FEATURE_QSV + if (hb_qsv_is_ffmpeg_supported_codec(job->vcodec)) + { + // options applied separately via hb_qsv_apply_encoder_options() call + return 0; + } +#endif /* place job->encoder_options in an hb_dict_t for convenience */ hb_dict_t *lavc_opts = NULL; if (job->encoder_options != NULL && *job->encoder_options) @@ -1358,6 +1510,18 @@ static int apply_encoder_preset(int vcodec, AVCodecContext *context, break; #endif +#if HB_PROJECT_FEATURE_QSV + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + preset = hb_map_qsv_preset_name(preset); + av_dict_set( av_opts, "preset", preset, 0); + hb_log("encavcodec: encoding with preset %s", preset); + break; +#endif + case HB_VCODEC_FFMPEG_FFV1: return apply_ffv1_preset(context, av_opts, preset); default: @@ -1397,6 +1561,7 @@ static int apply_encoder_level(AVCodecContext *context, AVDictionary **av_opts, { case HB_VCODEC_FFMPEG_VCE_H264: case HB_VCODEC_FFMPEG_NVENC_H264: + case HB_VCODEC_FFMPEG_QSV_H264: case HB_VCODEC_FFMPEG_MF_H264: level_names = hb_h264_level_names; level_values = hb_h264_level_values; @@ -1406,6 +1571,8 @@ static int apply_encoder_level(AVCodecContext *context, AVDictionary **av_opts, case HB_VCODEC_FFMPEG_VCE_H265_10BIT: case HB_VCODEC_FFMPEG_NVENC_H265: case HB_VCODEC_FFMPEG_NVENC_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: case HB_VCODEC_FFMPEG_MF_H265: level_names = hb_h265_level_names; level_values = hb_h265_level_values; @@ -1414,6 +1581,8 @@ static int apply_encoder_level(AVCodecContext *context, AVDictionary **av_opts, case HB_VCODEC_FFMPEG_VCE_AV1: case HB_VCODEC_FFMPEG_NVENC_AV1: case HB_VCODEC_FFMPEG_NVENC_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: case HB_VCODEC_FFMPEG_MF_AV1: level_names = hb_av1_level_names; level_values = hb_av1_level_values; @@ -1489,6 +1658,15 @@ const char* const* hb_av_preset_get_names(int encoder) case HB_VCODEC_FFMPEG_FFV1: return ffv1_preset_names; +#if HB_PROJECT_FEATURE_QSV + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + return hb_qsv_preset_get_names(); +#endif + default: return NULL; } @@ -1524,7 +1702,11 @@ const char* const* hb_av_profile_get_names(int encoder) return av1_mf_profile_name; case HB_VCODEC_FFMPEG_FFV1: return ffv1_profile_names; - + case HB_VCODEC_FFMPEG_QSV_H264: + return h264_qsv_profile_name; + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + return h265_qsv_profile_name; default: return NULL; } @@ -1538,19 +1720,23 @@ const char* const* hb_av_level_get_names(int encoder) case HB_VCODEC_FFMPEG_MF_H264: return hb_h264_level_names; - case HB_VCODEC_FFMPEG_VCE_H264: + case HB_VCODEC_FFMPEG_VCE_H264: return hb_vce_h264_level_names; // Not quite the same as x264 case HB_VCODEC_FFMPEG_NVENC_H265: case HB_VCODEC_FFMPEG_NVENC_H265_10BIT: case HB_VCODEC_FFMPEG_VCE_H265: case HB_VCODEC_FFMPEG_VCE_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: case HB_VCODEC_FFMPEG_MF_H265: return hb_h265_level_names; case HB_VCODEC_FFMPEG_VCE_AV1: case HB_VCODEC_FFMPEG_NVENC_AV1: case HB_VCODEC_FFMPEG_NVENC_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: case HB_VCODEC_FFMPEG_MF_AV1: return hb_av1_level_names; @@ -1589,6 +1775,15 @@ const int* hb_av_get_pix_fmts(int encoder) case HB_VCODEC_FFMPEG_FFV1: return ffv1_pix_formats; + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_AV1: + return qsv_pix_formats; + + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + return qsv_10bit_pix_formats; + default: return standard_pix_fmts; } diff --git a/libhb/fifo.c b/libhb/fifo.c index c56ae8b356576..193cce8680d78 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -11,10 +11,6 @@ #include "libavcodec/avcodec.h" #include "handbrake/handbrake.h" -#if HB_PROJECT_FEATURE_QSV -#include "handbrake/qsv_libav.h" -#include "handbrake/qsv_common.h" -#endif #ifdef __APPLE__ #include @@ -1036,43 +1032,6 @@ void hb_buffer_swap_copy( hb_buffer_t *src, hb_buffer_t *dst ) src->alloc = alloc; } -#if HB_PROJECT_FEATURE_QSV -static void free_qsv_resources(hb_buffer_t *b) -{ - // Reclaim QSV resources before dropping the buffer. - // when decoding without QSV, the QSV atom will be NULL. - if (b->storage != NULL && b->qsv_details.ctx != NULL) - { - AVFrame *frame = (AVFrame *)b->storage; - mfxFrameSurface1 *surface = (mfxFrameSurface1 *)frame->data[3]; - if (surface) - { - hb_qsv_release_surface_from_pool_by_surface_pointer(b->qsv_details.qsv_frames_ctx, surface); - frame->data[3] = 0; - } - } - if (b->qsv_details.qsv_atom != NULL && b->qsv_details.ctx != NULL) - { - hb_qsv_stage *stage = hb_qsv_get_last_stage(b->qsv_details.qsv_atom); - if (stage != NULL) - { - hb_qsv_wait_on_sync(b->qsv_details.ctx, stage); - if (stage->out.sync->in_use > 0) - { - ff_qsv_atomic_dec(&stage->out.sync->in_use); - } - if (stage->out.p_surface->Data.Locked > 0) - { - ff_qsv_atomic_dec(&stage->out.p_surface->Data.Locked); - } - } - hb_qsv_flush_stages(b->qsv_details.ctx->pipes, - (hb_qsv_list**)&b->qsv_details.qsv_atom, 1); - } -} -#endif - - static void free_buffer_resources(hb_buffer_t *b) { if (b->storage_type == AVFRAME) @@ -1111,9 +1070,6 @@ void hb_buffer_close( hb_buffer_t ** _b ) hb_unlock(buffers.lock); #endif -#if HB_PROJECT_FEATURE_QSV - free_qsv_resources(b); -#endif free_buffer_resources(b); if (buffer_pool && !hb_fifo_is_full(buffer_pool)) diff --git a/libhb/format.c b/libhb/format.c index 12ef9ca07115b..173b82fc6e7c5 100644 --- a/libhb/format.c +++ b/libhb/format.c @@ -11,8 +11,6 @@ #include "handbrake/avfilter_priv.h" #if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) #include "handbrake/qsv_common.h" -#include "libavutil/hwcontext_qsv.h" -#include "libavutil/hwcontext.h" #endif static int format_init(hb_filter_object_t *filter, @@ -71,15 +69,6 @@ static int format_init(hb_filter_object_t *filter, hb_filter_init_t *init) if (init->job->qsv.ctx->out_range != AVCOL_RANGE_UNSPECIFIED) hb_dict_set_string(avsettings, "out_range", (init->job->qsv.ctx->out_range == AVCOL_RANGE_JPEG) ? "full" : "limited"); - if (hb_qsv_hw_filters_via_video_memory_are_enabled(init->job)) - { - int result = hb_qsv_create_ffmpeg_vpp_pool(init, init->geometry.width, init->geometry.height); - if (result < 0) - { - hb_error("hb_create_ffmpeg_pool vpp allocation failed"); - return result; - } - } hb_dict_set(avfilter, "vpp_qsv", avsettings); } else diff --git a/libhb/handbrake/common.h b/libhb/handbrake/common.h index 5cb08b2d31906..8d9eb634b318a 100644 --- a/libhb/handbrake/common.h +++ b/libhb/handbrake/common.h @@ -642,14 +642,14 @@ struct hb_job_s #define HB_VCODEC_VT_H265 (0x00000051 | HB_VCODEC_VT_MASK | HB_VCODEC_H265_MASK) #define HB_VCODEC_VT_H265_10BIT (0x00000052 | HB_VCODEC_VT_MASK | HB_VCODEC_H265_MASK) -#define HB_VCODEC_QSV_H264 (0x00000060 | HB_VCODEC_QSV_MASK | HB_VCODEC_H264_MASK) -#define HB_VCODEC_QSV_H265_8BIT (0x00000061 | HB_VCODEC_QSV_MASK | HB_VCODEC_H265_MASK) -#define HB_VCODEC_QSV_H265_10BIT (0x00000062 | HB_VCODEC_QSV_MASK | HB_VCODEC_H265_MASK) -#define HB_VCODEC_QSV_H265 HB_VCODEC_QSV_H265_8BIT +#define HB_VCODEC_FFMPEG_QSV_H264 (0x00000060 | HB_VCODEC_FFMPEG_MASK | HB_VCODEC_QSV_MASK | HB_VCODEC_H264_MASK) +#define HB_VCODEC_FFMPEG_QSV_H265_8BIT (0x00000061 | HB_VCODEC_FFMPEG_MASK | HB_VCODEC_QSV_MASK | HB_VCODEC_H265_MASK) +#define HB_VCODEC_FFMPEG_QSV_H265_10BIT (0x00000062 | HB_VCODEC_FFMPEG_MASK | HB_VCODEC_QSV_MASK | HB_VCODEC_H265_MASK) +#define HB_VCODEC_FFMPEG_QSV_H265 HB_VCODEC_FFMPEG_QSV_H265_8BIT -#define HB_VCODEC_QSV_AV1_8BIT (0x00000070 | HB_VCODEC_QSV_MASK | HB_VCODEC_AV1_MASK) -#define HB_VCODEC_QSV_AV1_10BIT (0x00000071 | HB_VCODEC_QSV_MASK | HB_VCODEC_AV1_MASK) -#define HB_VCODEC_QSV_AV1 HB_VCODEC_QSV_AV1_8BIT +#define HB_VCODEC_FFMPEG_QSV_AV1_8BIT (0x00000070 | HB_VCODEC_FFMPEG_MASK | HB_VCODEC_QSV_MASK | HB_VCODEC_AV1_MASK) +#define HB_VCODEC_FFMPEG_QSV_AV1_10BIT (0x00000071 | HB_VCODEC_FFMPEG_MASK | HB_VCODEC_QSV_MASK | HB_VCODEC_AV1_MASK) +#define HB_VCODEC_FFMPEG_QSV_AV1 HB_VCODEC_FFMPEG_QSV_AV1_8BIT /* define an invalid CQ value compatible with all CQ-capable codecs */ #define HB_INVALID_VIDEO_QUALITY (-1000.) @@ -1257,7 +1257,7 @@ struct hb_title_s #define HB_DECODE_SUPPORT_VIDEOTOOLBOX 0x08 #define HB_DECODE_SUPPORT_MF 0x10 // Windows Media Foundation -#define HB_DECODE_SUPPORT_HWACCEL (HB_DECODE_SUPPORT_NVDEC | HB_DECODE_SUPPORT_VIDEOTOOLBOX | HB_DECODE_SUPPORT_MF) +#define HB_DECODE_SUPPORT_HWACCEL (HB_DECODE_SUPPORT_NVDEC | HB_DECODE_SUPPORT_VIDEOTOOLBOX | HB_DECODE_SUPPORT_QSV | HB_DECODE_SUPPORT_MF) #define HB_DECODE_SUPPORT_FORCE_HW 0x80000000 hb_metadata_t * metadata; diff --git a/libhb/handbrake/hwaccel.h b/libhb/handbrake/hwaccel.h index 71e898d481bbf..e090e4072607d 100644 --- a/libhb/handbrake/hwaccel.h +++ b/libhb/handbrake/hwaccel.h @@ -16,7 +16,7 @@ int hb_directx_available(); enum AVPixelFormat hw_hwaccel_get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts); -int hb_hwaccel_hw_ctx_init(int codec_id, int hw_decode, void **hw_device_ctx); +int hb_hwaccel_hw_ctx_init(int codec_id, int hw_decode, void **hw_device_ctx, hb_job_t *job); void hb_hwaccel_hw_ctx_close(void **hw_device_ctx); int hb_hwaccel_hwframes_ctx_init(struct AVCodecContext *ctx, hb_job_t *job); @@ -24,7 +24,8 @@ AVBufferRef *hb_hwaccel_init_hw_frames_ctx(AVBufferRef *hw_device_ctx, enum AVPixelFormat sw_fmt, enum AVPixelFormat hw_fmt, int width, - int height); + int height, + int initial_pool_size); int hb_hwaccel_hwframe_init(hb_job_t *job, struct AVFrame **frame); hb_buffer_t * hb_hwaccel_copy_video_buffer_to_hw_video_buffer(hb_job_t *job, hb_buffer_t **buf); diff --git a/libhb/handbrake/internal.h b/libhb/handbrake/internal.h index 3295f2bbb0ee1..5b2c74b06cc4d 100644 --- a/libhb/handbrake/internal.h +++ b/libhb/handbrake/internal.h @@ -406,7 +406,6 @@ enum WORK_DECSSASUB, WORK_RENDER, WORK_ENCAVCODEC, - WORK_ENCQSV, WORK_ENCVT, WORK_ENCX264, WORK_ENCX265, diff --git a/libhb/handbrake/qsv_common.h b/libhb/handbrake/qsv_common.h index 62398f64d3d9e..2e04f281827a3 100644 --- a/libhb/handbrake/qsv_common.h +++ b/libhb/handbrake/qsv_common.h @@ -25,6 +25,7 @@ int hb_qsv_impl_set_preferred(const char *name); #include "vpl/mfxvideo.h" #include "handbrake/hb_dict.h" #include "handbrake/qsv_libav.h" +#include "libavutil/hwcontext_qsv.h" /* Minimum Intel Media SDK version (currently 1.3, for Sandy Bridge support) */ #define HB_QSV_MINVERSION_MAJOR HB_QSV_MSDK_VERSION_MAJOR @@ -143,6 +144,14 @@ enum QSV_FU, // always last (future processors) }; +typedef struct +{ + const char *name; + const char *key; + const int value; +} +hb_triplet_t; + typedef struct { /* @@ -170,7 +179,7 @@ typedef struct mfxExtCodingOption codingOption; mfxExtCodingOption2 codingOption2; mfxExtVideoSignalInfo videoSignalInfo; - mfxExtHyperModeParam hyperEncodeParam; + hb_triplet_t* hyperEncodeParam; mfxExtAV1ScreenContentTools av1ScreenContentToolsParam; mfxExtChromaLocInfo chromaLocInfo; mfxExtMasteringDisplayColourVolume masteringDisplayColourVolume; @@ -195,6 +204,7 @@ typedef struct // assigned via hb_qsv_param_default, may be shared with another structure mfxVideoParam *videoParam; + int low_power; } hb_qsv_param_t; static const char* const hb_qsv_preset_names1[] = { "speed", "balanced", NULL, }; @@ -218,20 +228,23 @@ int hb_qsv_atoi (const char *str, int *err); float hb_qsv_atof (const char *str, int *err); int hb_qsv_param_default_async_depth(); -int hb_qsv_param_default_preset (hb_qsv_param_t *param, mfxVideoParam *videoParam, hb_qsv_info_t *info, const char *preset); -int hb_qsv_param_default (hb_qsv_param_t *param, mfxVideoParam *videoParam, hb_qsv_info_t *info); -int hb_qsv_param_parse (hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job, const char *key, const char *value); +int hb_qsv_param_default_preset (AVDictionary* av_opts, hb_qsv_param_t *param, mfxVideoParam *videoParam, hb_qsv_info_t *info, const char *preset); +int hb_qsv_param_default (hb_qsv_param_t *param, hb_qsv_info_t *info); +int hb_qsv_param_parse (AVDictionary **av_opts, hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job, const char *key, const char *value); int hb_qsv_profile_parse (hb_qsv_param_t *param, hb_qsv_info_t *info, const char *profile_key, const int codec); int hb_qsv_level_parse (hb_qsv_param_t *param, hb_qsv_info_t *info, const char *level_key); int hb_qsv_param_parse_dx_index (hb_job_t *job, const int dx_index); typedef struct { - const char *name; - const char *key; - const int value; -} -hb_triplet_t; + hb_qsv_info_t * qsv_info; + hb_qsv_param_t param; + int async_depth; + int max_async_depth; + int is_sys_mem; + const AVCodec * codec; + AVDictionary * av_opts; +} qsv_data_t; hb_triplet_t* hb_triplet4value(hb_triplet_t *triplets, const int value); hb_triplet_t* hb_triplet4name (hb_triplet_t *triplets, const char *name); @@ -248,31 +261,18 @@ int hb_qsv_impl_get_num(int impl); const char* hb_qsv_impl_get_via_name(int impl); mfxIMPL hb_qsv_dx_index_to_impl(int dx_index); -/* Full QSV pipeline helpers */ +/* QSV pipeline helpers */ +const char * hb_map_qsv_preset_name(const char * preset); +int hb_qsv_apply_encoder_options(qsv_data_t * qsv_data, hb_job_t * job, AVDictionary** av_opts); int hb_qsv_is_enabled(hb_job_t *job); hb_qsv_context* hb_qsv_context_init(); void hb_qsv_context_uninit(hb_job_t *job); +int hb_qsv_are_filters_supported(hb_job_t *job); int hb_qsv_sanitize_filter_list(hb_job_t *job); -int hb_qsv_hw_frames_init(AVCodecContext *s); -int hb_qsv_create_ffmpeg_dec_pool(hb_job_t * job, int width, int height, int sw_pix_fmt); -int hb_qsv_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum AVPixelFormat sw_pix_fmt, int pool_size, int extra_hw_frames, AVBufferRef **out_hw_frames_ctx); -int hb_qsv_create_ffmpeg_vpp_pool(hb_filter_init_t *init, int width, int height); -int hb_qsv_hw_filters_via_system_memory_are_enabled(hb_job_t *job); -int hb_qsv_hw_filters_via_video_memory_are_enabled(hb_job_t *job); int hb_qsv_get_memory_type(hb_job_t *job); int hb_qsv_full_path_is_enabled(hb_job_t *job); -AVBufferRef *hb_qsv_create_mids(AVBufferRef *hw_frames_ref); -hb_buffer_t * hb_qsv_copy_video_buffer_to_hw_video_buffer(hb_job_t *job, hb_buffer_t *in, const int is_vpp); -hb_buffer_t * hb_qsv_buffer_dup(hb_job_t *job, hb_buffer_t *in, const int is_vpp); -hb_buffer_t * hb_qsv_copy_avframe_to_video_buffer(hb_job_t *job, AVFrame *frame, AVRational time_base, const int is_vpp); -int hb_qsv_get_free_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, AVFrame* frame, QSVMid** out_mid); -void hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const int start_index, const int end_index, QSVMid** out_mid, mfxFrameSurface1** out_surface); -int hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, mfxFrameSurface1 *surface, QSVMid **out_mid); -int hb_qsv_replace_surface_mid(HBQSVFramesContext* hb_qsv_frames_ctx, const QSVMid *mid, mfxFrameSurface1 *surface); -int hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const mfxFrameSurface1 *surface); int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags); enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts); -void hb_qsv_uninit_dec(AVCodecContext *s); void hb_qsv_uninit_enc(hb_job_t *job); int hb_qsv_setup_job(hb_job_t *job); int hb_qsv_decode_h264_is_supported(int adapter_index); @@ -281,7 +281,8 @@ int hb_qsv_decode_h265_10_bit_is_supported(int adapter_index); int hb_qsv_decode_av1_is_supported(int adapter_index); int hb_qsv_decode_vvc_is_supported(int adapter_index); int hb_qsv_decode_is_codec_supported(int adapter_index, int video_codec_param, int pix_fmt, int width, int height); -int hb_qsv_device_init(hb_job_t *job); +int hb_qsv_device_init(hb_job_t *job, void **hw_device_ctx); +int hb_qsv_is_ffmpeg_supported_codec(int vcodec); #endif // __LIBHB__ #endif // HB_PROJECT_FEATURE_QSV diff --git a/libhb/hb.c b/libhb/hb.c index 4b31439d9cfa7..76938ca87db53 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -2149,12 +2149,6 @@ int hb_global_init() hb_register(&hb_encx265); #endif hb_register(&hb_encsvtav1); -#if HB_PROJECT_FEATURE_QSV - if (!disable_hardware) - { - hb_register(&hb_encqsv); - } -#endif hb_x264_global_init(); hb_common_global_init(disable_hardware); diff --git a/libhb/hb_json.c b/libhb/hb_json.c index 80634ecbf4595..2acacae4a0015 100644 --- a/libhb/hb_json.c +++ b/libhb/hb_json.c @@ -1312,6 +1312,10 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict ) if (job->qsv.ctx) { job->qsv.ctx->dx_index = adapter_index; } + // Prefer to use QSV decode when QSV encoder is enabled + if (!job->hw_decode && job->qsv.decode && hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec)) { + job->hw_decode = HB_DECODE_SUPPORT_QSV; + } #endif // If both vbitrate and vquality were specified, vbitrate is used; // we need to ensure the unused rate control mode is always set to an diff --git a/libhb/hbavfilter.c b/libhb/hbavfilter.c index 2d8236d9bf39b..c99da80e1e58f 100644 --- a/libhb/hbavfilter.c +++ b/libhb/hbavfilter.c @@ -67,64 +67,37 @@ hb_avfilter_graph_init(hb_value_t * settings, hb_filter_init_t * init) #endif // Build filter input -#if HB_PROJECT_FEATURE_QSV - // Need to handle preview as special case - if (hb_qsv_full_path_is_enabled(graph->job) && init->pix_fmt != AV_PIX_FMT_YUV420P) { - enum AVPixelFormat pix_fmt = init->hw_pix_fmt; - if (pix_fmt == AV_PIX_FMT_NONE) + enum AVPixelFormat pix_fmt = init->pix_fmt; + if (init->hw_pix_fmt == AV_PIX_FMT_QSV) { - pix_fmt = init->pix_fmt; - } + par = av_buffersrc_parameters_alloc(); + par->format = init->hw_pix_fmt; + // TODO: qsv_vpp changes time_base, adapt settings to hb pipeline + par->frame_rate.num = init->time_base.den; + par->frame_rate.den = init->time_base.num; - par = av_buffersrc_parameters_alloc(); - par->format = pix_fmt; - // TODO: qsv_vpp changes time_base, adapt settings to hb pipeline - par->frame_rate.num = init->time_base.den; - par->frame_rate.den = init->time_base.num; - par->width = init->geometry.width; - par->height = init->geometry.height; - par->sample_aspect_ratio.num = init->geometry.par.num; - par->sample_aspect_ratio.den = init->geometry.par.den; - par->time_base.num = init->time_base.num; - par->time_base.den = init->time_base.den; + par->width = init->geometry.width; + par->height = init->geometry.height; - filter_args = hb_strdup_printf( - "video_size=%dx%d:pix_fmt=%d:sar=%d/%d:" - "colorspace=%d:range=%d:" - "time_base=%d/%d:frame_rate=%d/%d", - init->geometry.width, init->geometry.height, pix_fmt, - init->geometry.par.num, init->geometry.par.den, - init->color_matrix, init->color_range, - init->time_base.num, init->time_base.den, - init->vrate.num, init->vrate.den); - - AVBufferRef *hb_hw_frames_ctx = NULL; - - if (pix_fmt == AV_PIX_FMT_QSV) - { - result = hb_qsv_create_ffmpeg_pool(graph->job, init->geometry.width, init->geometry.height, init->pix_fmt, HB_QSV_POOL_SURFACE_SIZE, 0, &hb_hw_frames_ctx); - if (result < 0) - { - hb_error("hb_create_ffmpeg_pool failed"); + par->sample_aspect_ratio.num = init->geometry.par.num; + par->sample_aspect_ratio.den = init->geometry.par.den; + + par->time_base.num = init->time_base.num; + par->time_base.den = init->time_base.den; + par->hw_frames_ctx = hb_hwaccel_init_hw_frames_ctx((AVBufferRef*)init->job->hw_device_ctx, + init->pix_fmt, + init->hw_pix_fmt, + par->width, + par->height, + 32); + if (!par->hw_frames_ctx) + { goto fail; } + pix_fmt = init->hw_pix_fmt; } - else - { - hb_qsv_device_init(graph->job); - for (int i = 0; i < graph->avgraph->nb_filters; i++) - { - graph->avgraph->filters[i]->hw_device_ctx = av_buffer_ref(graph->job->qsv.ctx->hb_hw_device_ctx); - } - } - par->hw_frames_ctx = hb_hw_frames_ctx; - } - else -#endif - { - enum AVPixelFormat pix_fmt = init->pix_fmt; - if (init->hw_pix_fmt == AV_PIX_FMT_CUDA) + else if (init->hw_pix_fmt == AV_PIX_FMT_CUDA) { par = av_buffersrc_parameters_alloc(); par->format = init->hw_pix_fmt; @@ -136,7 +109,8 @@ hb_avfilter_graph_init(hb_value_t * settings, hb_filter_init_t * init) init->pix_fmt, init->hw_pix_fmt, par->width, - par->height); + par->height, + 0); if (!par->hw_frames_ctx) { goto fail; @@ -317,15 +291,22 @@ hb_buffer_t * hb_avfilter_get_buf(hb_avfilter_graph_t * graph) { hb_buffer_t * buf; #if HB_PROJECT_FEATURE_QSV - if (hb_qsv_hw_filters_via_video_memory_are_enabled(graph->job)) + if (hb_hwaccel_is_full_hardware_pipeline_enabled(graph->job) && + hb_qsv_decode_is_enabled(graph->job)) { - buf = hb_qsv_copy_avframe_to_video_buffer(graph->job, graph->frame, graph->out_time_base, 1); - } - else -#endif - { - buf = hb_avframe_to_video_buffer(graph->frame, graph->out_time_base); + AVBufferRef *hw_frames_ctx = av_buffersink_get_hw_frames_ctx(graph->output); + if (!hw_frames_ctx) + { + hb_error("hb_avfilter_get_buf: failed to get hw_frames_ctx from sink"); + } + else + { + // copy hw frame ctx from filter graph for future encoder initialization + graph->job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx = av_buffer_ref(hw_frames_ctx); + } } + #endif + buf = hb_avframe_to_video_buffer(graph->frame, graph->out_time_base); av_frame_unref(graph->frame); return buf; } diff --git a/libhb/hwaccel.c b/libhb/hwaccel.c index b435fdf6cd4db..76570750197c0 100644 --- a/libhb/hwaccel.c +++ b/libhb/hwaccel.c @@ -10,7 +10,7 @@ #include "handbrake/hbffmpeg.h" #include "handbrake/handbrake.h" #include "handbrake/nvenc_common.h" - +#include "handbrake/qsv_common.h" #ifdef __APPLE__ #include "platform/macosx/vt_common.h" #endif @@ -24,6 +24,9 @@ enum AVHWDeviceType hb_hwaccel_available(int codec_id, const char *hwdevice_name const AVCodec *codec = avcodec_find_decoder(codec_id); enum AVHWDeviceType hw_type = av_hwdevice_find_type_by_name(hwdevice_name); + if (hw_type == AV_HWDEVICE_TYPE_QSV) { + return 1; + } if (hw_type != AV_HWDEVICE_TYPE_NONE) { @@ -56,6 +59,16 @@ enum AVPixelFormat hw_hwaccel_get_hw_format(AVCodecContext *ctx, const enum AVPi { if (*p == job->hw_pix_fmt) { +#if HB_PROJECT_FEATURE_QSV + if (*p == AV_PIX_FMT_QSV) + { + if (job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) + { + // in case if decoder and encoder have the same size + ctx->hw_frames_ctx = av_buffer_ref(job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); + } + } +#endif return *p; } } @@ -69,7 +82,7 @@ enum AVPixelFormat hw_hwaccel_get_hw_format(AVCodecContext *ctx, const enum AVPi return AV_PIX_FMT_NONE; } -int hb_hwaccel_hw_ctx_init(int codec_id, int hw_decode, void **hw_device_ctx) +int hb_hwaccel_hw_ctx_init(int codec_id, int hw_decode, void **hw_device_ctx, hb_job_t *job) { enum AVHWDeviceType hw_type = AV_HWDEVICE_TYPE_NONE; enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE; @@ -85,6 +98,22 @@ int hb_hwaccel_hw_ctx_init(int codec_id, int hw_decode, void **hw_device_ctx) { hw_type = av_hwdevice_find_type_by_name("cuda"); } +#if HB_PROJECT_FEATURE_QSV + else if (hw_decode & HB_DECODE_SUPPORT_QSV) + { + AVBufferRef *ctx = NULL; + hw_type = av_hwdevice_find_type_by_name("qsv"); + pix_fmt = AV_PIX_FMT_QSV; + err = hb_qsv_device_init(job, (void**)&ctx); + if (err < 0) + { + hb_error("hwaccel: failed to create hwdevice"); + return err; + } + *hw_device_ctx = av_buffer_ref(ctx); + return err; + } +#endif else if (hw_decode & HB_DECODE_SUPPORT_MF) { hw_type = av_hwdevice_find_type_by_name("d3d11va"); @@ -117,7 +146,7 @@ int hb_hwaccel_hw_ctx_init(int codec_id, int hw_decode, void **hw_device_ctx) } else { - *hw_device_ctx = ctx; + *hw_device_ctx = av_buffer_ref(ctx); } } @@ -136,23 +165,48 @@ int hb_hwaccel_hwframes_ctx_init(AVCodecContext *ctx, hb_job_t *job) { if (!ctx->hw_device_ctx) { - hb_error("hwaccel: failed to initialize hw frames context"); + hb_error("hwaccel: failed to initialize hw frames context - no hw_device_ctx"); return 1; } ctx->get_format = hw_hwaccel_get_hw_format; ctx->pix_fmt = job->hw_pix_fmt; +#if HB_PROJECT_FEATURE_QSV + if (hb_hwaccel_is_full_hardware_pipeline_enabled(job) && + hb_qsv_decode_is_enabled(job)) + { + ctx->extra_hw_frames = 32; + ctx->sw_pix_fmt = job->input_pix_fmt; + } +#endif + ctx->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->hw_device_ctx); AVHWFramesContext *frames_ctx = (AVHWFramesContext *)ctx->hw_frames_ctx->data; frames_ctx->format = job->hw_pix_fmt; - frames_ctx->sw_format = job->output_pix_fmt; frames_ctx->width = ctx->width; frames_ctx->height = ctx->height; +#if HB_PROJECT_FEATURE_QSV + if (hb_hwaccel_is_full_hardware_pipeline_enabled(job) && + hb_qsv_decode_is_enabled(job)) + { + // Use input pix format for decoder and filters frame pools, output frame pools are created by FFmpeg + frames_ctx->sw_format = job->input_pix_fmt; + frames_ctx->initial_pool_size = HB_QSV_POOL_FFMPEG_SURFACE_SIZE; + if (ctx->extra_hw_frames >= 0) + { + frames_ctx->initial_pool_size += ctx->extra_hw_frames; + } + + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } +#endif + if (av_hwframe_ctx_init(ctx->hw_frames_ctx) != 0) { - hb_error("hwaccel: failed to initialize hw frames context"); + hb_error("hwaccel: failed to initialize hw frames context - av_hwframe_ctx_init"); return 1; } @@ -163,7 +217,8 @@ AVBufferRef *hb_hwaccel_init_hw_frames_ctx(AVBufferRef *hw_device_ctx, enum AVPixelFormat sw_fmt, enum AVPixelFormat hw_fmt, int width, - int height) + int height, + int initial_pool_size) { AVBufferRef *hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx); AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; @@ -171,6 +226,11 @@ AVBufferRef *hb_hwaccel_init_hw_frames_ctx(AVBufferRef *hw_device_ctx, frames_ctx->sw_format = sw_fmt; frames_ctx->width = width; frames_ctx->height = height; + + if(initial_pool_size > 0) + { + frames_ctx->initial_pool_size = initial_pool_size; + } if (0 != av_hwframe_ctx_init(hw_frames_ctx)) { hb_error("hwaccel: failed to initialize hw frames context"); @@ -194,7 +254,7 @@ static int hb_hwaccel_hwframe_init(hb_job_t *job, AVFrame **frame) *frame = av_frame_alloc(); hw_frames_ctx = hb_hwaccel_init_hw_frames_ctx(hw_device_ctx, job->input_pix_fmt, job->hw_pix_fmt, - job->width, job->height); + job->width, job->height, 0); return av_hwframe_get_buffer(hw_frames_ctx, *frame, 0); } @@ -261,41 +321,57 @@ static int is_encoder_supported(int encoder_id) case HB_VCODEC_VT_H264: case HB_VCODEC_VT_H265: case HB_VCODEC_VT_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: return 1; default: return 0; } } -static int are_filters_supported(hb_list_t *filters, int hw_decode) +static int are_filters_supported(hb_job_t * job) { int ret = 0; - #ifdef __APPLE__ - if (hw_decode & HB_DECODE_SUPPORT_VIDEOTOOLBOX) + if (job->hw_decode & HB_DECODE_SUPPORT_VIDEOTOOLBOX) { - ret = hb_vt_are_filters_supported(filters); + ret = hb_vt_are_filters_supported(job->list_filter); } #endif - if (hw_decode & HB_DECODE_SUPPORT_NVDEC) + if (job->hw_decode & HB_DECODE_SUPPORT_NVDEC) { - ret = hb_nvenc_are_filters_supported(filters); + ret = hb_nvenc_are_filters_supported(job->list_filter); } - +#if HB_PROJECT_FEATURE_QSV + if (job->hw_decode & HB_DECODE_SUPPORT_QSV) + { + ret = hb_qsv_are_filters_supported(job); + } +#endif return ret; } int hb_hwaccel_is_enabled(hb_job_t *job) { return job != NULL && - (job->title->video_decode_support & HB_DECODE_SUPPORT_HWACCEL) && - (job->hw_decode & HB_DECODE_SUPPORT_HWACCEL); + ( + ( + (job->title->video_decode_support & HB_DECODE_SUPPORT_HWACCEL) && + (job->hw_decode & HB_DECODE_SUPPORT_HWACCEL) + ) +#if HB_PROJECT_FEATURE_QSV + || hb_qsv_decode_is_enabled(job) +#endif + ); } int hb_hwaccel_is_full_hardware_pipeline_enabled(hb_job_t *job) { return hb_hwaccel_is_enabled(job) && - are_filters_supported(job->list_filter, job->hw_decode) && + are_filters_supported(job) && is_encoder_supported(job->vcodec); } diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c index 4f4155c4e5d05..72b27a61c2b05 100644 --- a/libhb/muxavformat.c +++ b/libhb/muxavformat.c @@ -284,10 +284,10 @@ static int avformatInit( hb_mux_object_t * m ) { case HB_VCODEC_X264_8BIT: case HB_VCODEC_X264_10BIT: - case HB_VCODEC_QSV_H264: case HB_VCODEC_VT_H264: case HB_VCODEC_FFMPEG_VCE_H264: case HB_VCODEC_FFMPEG_NVENC_H264: + case HB_VCODEC_FFMPEG_QSV_H264: case HB_VCODEC_FFMPEG_MF_H264: track->st->codecpar->codec_id = AV_CODEC_ID_H264; if (job->mux == HB_MUX_AV_MP4 && job->inline_parameter_sets) @@ -322,41 +322,12 @@ static int avformatInit( hb_mux_object_t * m ) case HB_VCODEC_FFMPEG_NVENC_AV1: case HB_VCODEC_FFMPEG_NVENC_AV1_10BIT: case HB_VCODEC_FFMPEG_VCE_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: case HB_VCODEC_FFMPEG_MF_AV1: track->st->codecpar->codec_id = AV_CODEC_ID_AV1; break; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: - { - const AVBitStreamFilter *bsf; - AVBSFContext *ctx; - int ret; - - track->st->codecpar->codec_id = AV_CODEC_ID_AV1; - - bsf = av_bsf_get_by_name("extract_extradata"); - ret = av_bsf_alloc(bsf, &ctx); - if (ret < 0) - { - hb_error("AV1 bitstream filter: alloc failure"); - goto error; - } - - track->bitstream_context = ctx; - if (track->bitstream_context != NULL) - { - avcodec_parameters_copy(track->bitstream_context->par_in, - track->st->codecpar); - ret = av_bsf_init(track->bitstream_context); - if (ret < 0) - { - hb_error("AV1 bitstream filter: init failure"); - goto error; - } - } - } break; - case HB_VCODEC_THEORA: track->st->codecpar->codec_id = AV_CODEC_ID_THEORA; break; @@ -365,14 +336,14 @@ static int avformatInit( hb_mux_object_t * m ) case HB_VCODEC_X265_10BIT: case HB_VCODEC_X265_12BIT: case HB_VCODEC_X265_16BIT: - case HB_VCODEC_QSV_H265: - case HB_VCODEC_QSV_H265_10BIT: case HB_VCODEC_VT_H265: case HB_VCODEC_VT_H265_10BIT: case HB_VCODEC_FFMPEG_VCE_H265: case HB_VCODEC_FFMPEG_VCE_H265_10BIT: case HB_VCODEC_FFMPEG_NVENC_H265: case HB_VCODEC_FFMPEG_NVENC_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: case HB_VCODEC_FFMPEG_MF_H265: track->st->codecpar->codec_id = AV_CODEC_ID_HEVC; if (job->mux == HB_MUX_AV_MP4 && job->inline_parameter_sets) diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c index e583c02714db7..45c9ebec2e499 100644 --- a/libhb/qsv_common.c +++ b/libhb/qsv_common.c @@ -24,12 +24,6 @@ #include "handbrake/h265_common.h" #include "handbrake/av1_common.h" #include "handbrake/hbffmpeg.h" -#include "libavfilter/avfilter.h" -#include "libavfilter/buffersrc.h" -#include "libavfilter/buffersink.h" -#include "libavutil/hwcontext_qsv.h" -#include "libavutil/hwcontext.h" -#include "vpl/mfxadapter.h" typedef struct hb_qsv_adapter_details { @@ -758,11 +752,11 @@ int hb_qsv_available() hb_log("qsv: is available on this system"); // Return the codec capabilities for the highest platform generation - qsv_init_result = ((hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H264) ? HB_VCODEC_QSV_H264 : 0) | - (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H265) ? HB_VCODEC_QSV_H265 : 0) | - (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H265_10BIT) ? HB_VCODEC_QSV_H265_10BIT : 0) | - (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_AV1) ? HB_VCODEC_QSV_AV1 : 0) | - (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_AV1_10BIT) ? HB_VCODEC_QSV_AV1_10BIT : 0)); + qsv_init_result = ((hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_FFMPEG_QSV_H264) ? HB_VCODEC_FFMPEG_QSV_H264 : 0) | + (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_FFMPEG_QSV_H265) ? HB_VCODEC_FFMPEG_QSV_H265 : 0) | + (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_FFMPEG_QSV_H265_10BIT) ? HB_VCODEC_FFMPEG_QSV_H265_10BIT : 0) | + (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_FFMPEG_QSV_AV1) ? HB_VCODEC_FFMPEG_QSV_AV1 : 0) | + (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_FFMPEG_QSV_AV1_10BIT) ? HB_VCODEC_FFMPEG_QSV_AV1_10BIT : 0)); return qsv_init_result; } @@ -782,6 +776,21 @@ int hb_qsv_hyper_encode_available(int adapter_index) } } + +int hb_qsv_is_ffmpeg_supported_codec(int vcodec) +{ + if (vcodec == HB_VCODEC_FFMPEG_QSV_H264 || + vcodec == HB_VCODEC_FFMPEG_QSV_H265 || + vcodec == HB_VCODEC_FFMPEG_QSV_H265_10BIT || + vcodec == HB_VCODEC_FFMPEG_QSV_AV1 || + vcodec == HB_VCODEC_FFMPEG_QSV_AV1_10BIT + ) + { + return 1; + } + return 0; +} + int hb_qsv_video_encoder_is_enabled(int adapter_index, int encoder) { hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(adapter_index); @@ -795,15 +804,15 @@ int hb_qsv_video_encoder_is_enabled(int adapter_index, int encoder) { switch (encoder) { - case HB_VCODEC_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H264: return details->hb_qsv_info_avc != NULL && details->hb_qsv_info_avc->available; - case HB_VCODEC_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: if (hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) < QSV_G6) return 0; - case HB_VCODEC_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265: return details->hb_qsv_info_hevc != NULL && details->hb_qsv_info_hevc->available; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: return details->hb_qsv_info_av1 != NULL && details->hb_qsv_info_av1->available; default: return 0; @@ -2083,13 +2092,13 @@ hb_qsv_info_t* hb_qsv_encoder_info_get(int adapter_index, int encoder) { switch (encoder) { - case HB_VCODEC_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H264: return details->hb_qsv_info_avc; - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: return details->hb_qsv_info_hevc; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: return details->hb_qsv_info_av1; default: return NULL; @@ -2224,6 +2233,7 @@ static int hb_qsv_parse_options(hb_job_t *job) free(str); if (!err) { + hb_log("hb_qsv_parse_options: gpu=%d", dx_index); hb_qsv_param_parse_dx_index(job, dx_index); } } @@ -2302,16 +2312,6 @@ int hb_qsv_decode_is_enabled(hb_job_t *job) qsv_decode_is_codec_supported; } -int hb_qsv_hw_filters_via_video_memory_are_enabled(hb_job_t *job) -{ - return hb_qsv_full_path_is_enabled(job) && (hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_VIDEO_MEMORY) && (job->qsv.ctx->num_hw_filters > 0); -} - -int hb_qsv_hw_filters_via_system_memory_are_enabled(hb_job_t *job) -{ - return hb_qsv_full_path_is_enabled(job) && (hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_SYSTEM_MEMORY) && (job->qsv.ctx->num_hw_filters > 0); -} - int hb_qsv_is_enabled(hb_job_t *job) { return hb_qsv_decode_is_enabled(job) || hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec); @@ -2459,7 +2459,112 @@ float hb_qsv_atof(const char *str, int *err) return v; } -int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job, +int hb_qsv_apply_encoder_options(qsv_data_t *qsv_data, hb_job_t *job, AVDictionary **av_opts) +{ + qsv_data->is_sys_mem = (hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_SYSTEM_MEMORY); + qsv_data->qsv_info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec); + + if (qsv_data != NULL && qsv_data->qsv_info != NULL) + { + int ret = hb_qsv_param_default(&qsv_data->param, qsv_data->qsv_info); + if (ret) + { + return ret; + } + } + else + { + hb_error("hb_qsv_apply_encoder_options: invalid pointer(s) qsv_data=%p qsv_data->qsv_info=%p", qsv_data, qsv_data->qsv_info); + return -1; + } + + if (job->encoder_options != NULL && *job->encoder_options) + { + hb_dict_t *options_list; + options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec); + + hb_dict_iter_t iter; + for (iter = hb_dict_iter_init(options_list); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(options_list, iter)) + { + const char *key = hb_dict_iter_key(iter); + hb_value_t *value = hb_dict_iter_value(iter); + char *str = hb_value_get_string_xform(value); + + switch (hb_qsv_param_parse(av_opts, &qsv_data->param, qsv_data->qsv_info, job, key, str)) + { + case HB_QSV_PARAM_OK: + break; + + case HB_QSV_PARAM_BAD_NAME: + hb_log("qsv_encavcodecInit: hb_qsv_param_parse: bad key %s", key); + break; + case HB_QSV_PARAM_BAD_VALUE: + hb_log("qsv_encavcodecInit: hb_qsv_param_parse: bad value %s for key %s", + str, key); + break; + case HB_QSV_PARAM_UNSUPPORTED: + hb_log("qsv_encavcodecInit: hb_qsv_param_parse: unsupported option %s", + key); + break; + + case HB_QSV_PARAM_ERROR: + default: + hb_log("qsv_encavcodecInit: hb_qsv_param_parse: unknown error"); + break; + } + free(str); + } + hb_dict_free(&options_list); + } + + hb_log("encavcodec: using%s%s path", + hb_qsv_full_path_is_enabled(job) ? " full QSV" : " encode-only", + hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_VIDEO_MEMORY ? " via video memory" : " via system memory"); + + if(qsv_data->qsv_info->capabilities & HB_QSV_CAP_LOWPOWER_ENCODE) + { + char low_power[7]; + snprintf(low_power, sizeof(low_power), "%d", qsv_data->param.low_power); + av_dict_set(av_opts, "low_power", low_power, 0); + if(qsv_data->param.low_power) + hb_log("encavcodec: using Low Power mode"); + } + + if((qsv_data->qsv_info->capabilities & HB_QSV_CAP_HYPERENCODE) && + qsv_data->param.hyperEncodeParam->value != MFX_HYPERMODE_OFF) + { + char hyperencode[16]; + snprintf(hyperencode, sizeof(hyperencode), "%s", qsv_data->param.hyperEncodeParam->key); + av_dict_set(av_opts, "dual_gfx", hyperencode, 0); + //av_dict_set(av_opts, "async_depth", "30", 0); + hb_log("encavcodec: Hyper Encoding mode: %s", hyperencode); + } + + if((qsv_data->qsv_info->capabilities & HB_QSV_CAP_AV1_SCREENCONTENT) && + qsv_data->param.av1ScreenContentToolsParam.IntraBlockCopy) + { + char intrabc[7]; + snprintf(intrabc, sizeof(intrabc), "%d", qsv_data->param.av1ScreenContentToolsParam.IntraBlockCopy); + av_dict_set(av_opts, "intrabc", intrabc, 0); + hb_log("encavcodec: ScreenContentCoding is enabled IBC %s", + qsv_data->param.av1ScreenContentToolsParam.IntraBlockCopy ? "on" : "off"); + } + + if((qsv_data->qsv_info->capabilities & HB_QSV_CAP_AV1_SCREENCONTENT) && + qsv_data->param.av1ScreenContentToolsParam.Palette) + { + char palette_mode[7]; + snprintf(palette_mode, sizeof(palette_mode), "%d", qsv_data->param.av1ScreenContentToolsParam.Palette); + av_dict_set(av_opts, "palette_mode", palette_mode, 0); + hb_log("encavcodec: ScreenContentCoding is enabled Palette %s", + qsv_data->param.av1ScreenContentToolsParam.Palette ? "on" : "off"); + } + return 0; +} + +int hb_qsv_param_parse(AVDictionary** av_opts, hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job, const char *key, const char *value) { float fvalue; @@ -2495,9 +2600,33 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->videoParam->mfx.TargetUsage = HB_QSV_CLIP3(MFX_TARGETUSAGE_1, - MFX_TARGETUSAGE_7, - ivalue); + int target_usage = HB_QSV_CLIP3(MFX_TARGETUSAGE_1, MFX_TARGETUSAGE_7, ivalue); + switch (target_usage) + { + case MFX_TARGETUSAGE_1: + av_dict_set(av_opts, "preset", "veryslow", 0); + break; + case MFX_TARGETUSAGE_2: + av_dict_set(av_opts, "preset", "slower", 0); + break; + case MFX_TARGETUSAGE_3: + av_dict_set(av_opts, "preset", "slow", 0); + break; + case MFX_TARGETUSAGE_4: + av_dict_set(av_opts, "preset", "medium", 0); + break; + case MFX_TARGETUSAGE_5: + av_dict_set(av_opts, "preset", "fast", 0); + break; + case MFX_TARGETUSAGE_6: + av_dict_set(av_opts, "preset", "faster", 0); + break; + case MFX_TARGETUSAGE_7: + av_dict_set(av_opts, "preset", "veryfast", 0); + break; + default: + break; + } } } else if (!strcasecmp(key, "num-ref-frame") || @@ -2506,7 +2635,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->videoParam->mfx.NumRefFrame = HB_QSV_CLIP3(0, 16, ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(0, 16, ivalue)); + av_dict_set(av_opts, "refs", cvalue, 0); } } else if (!strcasecmp(key, "gop-ref-dist")) @@ -2514,7 +2645,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->gop.gop_ref_dist = HB_QSV_CLIP3(-1, 32, ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(-1, 32, ivalue)); + av_dict_set(av_opts, "bf", cvalue, 0); } } else if (!strcasecmp(key, "gop-pic-size") || @@ -2523,7 +2656,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->gop.gop_pic_size = HB_QSV_CLIP3(-1, UINT16_MAX, ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(-1, UINT16_MAX, ivalue)); + av_dict_set(av_opts, "g", cvalue, 0); } } else if (!strcasecmp(key, "b-pyramid")) @@ -2533,7 +2668,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->gop.b_pyramid = HB_QSV_CLIP3(-1, 1, ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(-1, 1, ivalue)); + av_dict_set(av_opts, "b_strategy", cvalue, 0); } } else @@ -2541,21 +2678,6 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job return HB_QSV_PARAM_UNSUPPORTED; } } - else if (!strcasecmp(key, "scenecut")) - { - ivalue = hb_qsv_atobool(value, &error); - if (!error) - { - if (!ivalue) - { - param->videoParam->mfx.GopOptFlag |= MFX_GOP_STRICT; - } - else - { - param->videoParam->mfx.GopOptFlag &= ~MFX_GOP_STRICT; - } - } - } else if (!strcasecmp(key, "adaptive-i") || !strcasecmp(key, "i-adapt")) { @@ -2564,7 +2686,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->codingOption2.AdaptiveI = hb_qsv_codingoption_xlat(ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_codingoption_xlat(ivalue)); + av_dict_set(av_opts, "adaptive_i", cvalue, 0); } } else @@ -2580,7 +2704,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->codingOption2.AdaptiveB = hb_qsv_codingoption_xlat(ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_codingoption_xlat(ivalue)); + av_dict_set(av_opts, "adaptive_b", cvalue, 0); } } else @@ -2625,7 +2751,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job fvalue = hb_qsv_atof(value, &error); if (!error) { - param->rc.vbv_buffer_init = HB_QSV_CLIP3(0, INT32_MAX, fvalue); + char cvalue[7]; + snprintf(cvalue, 7, "%.2f", HB_QSV_CLIP3(0, INT32_MAX, fvalue)); + av_dict_set(av_opts, "rc_initial_buffer_occupancy", cvalue, 0); } } else if (!strcasecmp(key, "vbv-bufsize")) @@ -2633,7 +2761,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->rc.vbv_buffer_size = HB_QSV_CLIP3(0, INT32_MAX, ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(0, INT32_MAX, ivalue)); + av_dict_set(av_opts, "rc_buffer_size", cvalue, 0); } } else if (!strcasecmp(key, "vbv-maxrate")) @@ -2641,7 +2771,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->rc.vbv_max_bitrate = HB_QSV_CLIP3(0, INT32_MAX, ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(0, INT32_MAX, ivalue)); + av_dict_set(av_opts, "rc_max_rate", cvalue, 0); } } else if (!strcasecmp(key, "cavlc") || !strcasecmp(key, "cabac")) @@ -2667,32 +2799,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job { ivalue = !ivalue; } - param->codingOption.CAVLC = hb_qsv_codingoption_xlat(ivalue); - } - } - else if (!strcasecmp(key, "videoformat")) - { - if (info->capabilities & HB_QSV_CAP_VUI_VSINFO) - { - switch (info->codec_id) - { - case MFX_CODEC_AVC: - ivalue = hb_qsv_atoindex(hb_h264_vidformat_names, value, &error); - break; - case MFX_CODEC_HEVC: - ivalue = hb_qsv_atoindex(hb_h265_vidformat_names, value, &error); - break; - default: - return HB_QSV_PARAM_UNSUPPORTED; - } - } - else - { - return HB_QSV_PARAM_UNSUPPORTED; - } - if (!error) - { - param->videoSignalInfo.VideoFormat = ivalue; + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_codingoption_xlat(ivalue)); + av_dict_set(av_opts, "cavlc", cvalue, 0); } } else if (!strcasecmp(key, "colorprim")) @@ -2717,8 +2826,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job } if (!error) { - param->videoSignalInfo.ColourDescriptionPresent = 1; - param->videoSignalInfo.ColourPrimaries = ivalue; + char cvalue[7]; + snprintf(cvalue, 7, "%d", ivalue); + av_dict_set(av_opts, "color_primaries", cvalue, 0); } } else if (!strcasecmp(key, "transfer")) @@ -2743,8 +2853,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job } if (!error) { - param->videoSignalInfo.ColourDescriptionPresent = 1; - param->videoSignalInfo.TransferCharacteristics = ivalue; + char cvalue[7]; + snprintf(cvalue, 7, "%d", ivalue); + av_dict_set(av_opts, "color_trc", cvalue, 0); } } else if (!strcasecmp(key, "colormatrix")) @@ -2769,8 +2880,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job } if (!error) { - param->videoSignalInfo.ColourDescriptionPresent = 1; - param->videoSignalInfo.MatrixCoefficients = ivalue; + char cvalue[7]; + snprintf(cvalue, 7, "%d", ivalue); + av_dict_set(av_opts, "colorspace", cvalue, 0); } } else if (!strcasecmp(key, "tff") || @@ -2786,9 +2898,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job } if (!error) { - param->videoParam->mfx.FrameInfo.PicStruct = (ivalue ? - MFX_PICSTRUCT_FIELD_TFF : - MFX_PICSTRUCT_PROGRESSIVE); + char cvalue[7]; + snprintf(cvalue, 7, "+%d", ivalue ? MFX_PICSTRUCT_FIELD_TFF : MFX_PICSTRUCT_PROGRESSIVE); + av_dict_set(av_opts, "flags", cvalue, AV_DICT_APPEND); } } else if (!strcasecmp(key, "bff")) @@ -2803,9 +2915,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job } if (!error) { - param->videoParam->mfx.FrameInfo.PicStruct = (ivalue ? - MFX_PICSTRUCT_FIELD_BFF : - MFX_PICSTRUCT_PROGRESSIVE); + char cvalue[7]; + snprintf(cvalue, 7, "+%d", ivalue ? MFX_PICSTRUCT_FIELD_BFF : MFX_PICSTRUCT_PROGRESSIVE); + av_dict_set(av_opts, "flags", cvalue, AV_DICT_APPEND); } } else if (!strcasecmp(key, "mbbrc")) @@ -2815,7 +2927,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->codingOption2.MBBRC = hb_qsv_codingoption_xlat(ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_codingoption_xlat(ivalue)); + av_dict_set(av_opts, "mbbrc", cvalue, 0); } } else @@ -2830,7 +2944,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->codingOption2.ExtBRC = hb_qsv_codingoption_xlat(ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_codingoption_xlat(ivalue)); + av_dict_set(av_opts, "extbrc", cvalue, 0); } } else @@ -2862,8 +2978,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->codingOption2.LookAheadDepth = HB_QSV_CLIP3(10, 100, - ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(10, 100, ivalue)); + av_dict_set(av_opts, "look_ahead_depth", cvalue, 0); } } else @@ -2879,9 +2996,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->codingOption2.LookAheadDS = HB_QSV_CLIP3(MFX_LOOKAHEAD_DS_UNKNOWN, - MFX_LOOKAHEAD_DS_4x, - ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", HB_QSV_CLIP3(MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_4x, ivalue)); + av_dict_set(av_opts, "look_ahead_downsampling", cvalue, 0); } } else @@ -2896,7 +3013,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atoi(value, &error); if (!error) { - param->codingOption2.Trellis = hb_qsv_trellisvalue_xlat(ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_trellisvalue_xlat(ivalue)); + av_dict_set(av_opts, "trellis", cvalue, 0); } } else @@ -2911,7 +3030,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->codingOption2.RepeatPPS = hb_qsv_codingoption_xlat(ivalue); + char cvalue[7]; + snprintf(cvalue, 7, "%d", hb_qsv_codingoption_xlat(ivalue)); + av_dict_set(av_opts, "repeat_pps", cvalue, 0); } } else @@ -2926,7 +3047,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->videoParam->mfx.LowPower = ivalue ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; + param->low_power = ivalue; } } else @@ -3008,7 +3129,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job } if (mode) { - param->hyperEncodeParam.Mode = mode->value; + param->hyperEncodeParam = mode; } } else if (!strcasecmp(key, "palette")) @@ -3018,7 +3139,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->av1ScreenContentToolsParam.Palette = ivalue ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; + param->av1ScreenContentToolsParam.Palette = ivalue; } } else @@ -3033,7 +3154,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job ivalue = hb_qsv_atobool(value, &error); if (!error) { - param->av1ScreenContentToolsParam.IntraBlockCopy = ivalue ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; + param->av1ScreenContentToolsParam.IntraBlockCopy = ivalue; } } else @@ -3046,7 +3167,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job int async_depth = hb_qsv_atoi(value, &error); if (!error) { - param->videoParam->AsyncDepth = async_depth; + char cvalue[7]; + snprintf(cvalue, 7, "%d", async_depth); + av_dict_set(av_opts, "async_depth", cvalue, 0); } } else @@ -3107,7 +3230,7 @@ int hb_qsv_profile_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char } /* HEVC 10 bits defaults to Main 10 */ else if (((profile_key != NULL && !strcasecmp(profile_key, "auto")) || profile_key == NULL) && - codec == HB_VCODEC_QSV_H265_10BIT && + codec == HB_VCODEC_FFMPEG_QSV_H265_10BIT && param->videoParam->mfx.CodecId == MFX_CODEC_HEVC && hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G6) { @@ -3116,7 +3239,7 @@ int hb_qsv_profile_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char } /* AV1 10 bits defaults to Main */ else if (((profile_key != NULL && !strcasecmp(profile_key, "auto")) || profile_key == NULL) && - codec == HB_VCODEC_QSV_AV1_10BIT && + codec == HB_VCODEC_FFMPEG_QSV_AV1_10BIT && param->videoParam->mfx.CodecId == MFX_CODEC_AV1 && hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) > QSV_G8) { @@ -3188,14 +3311,14 @@ const char* const* hb_qsv_profile_get_names(int encoder) { switch (encoder) { - case HB_VCODEC_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H264: return hb_h264_profile_names_8bit; - case HB_VCODEC_QSV_H265_8BIT: + case HB_VCODEC_FFMPEG_QSV_H265_8BIT: return hb_h265_profile_names_8bit; - case HB_VCODEC_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: return hb_qsv_h265_profiles_names_10bit; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: return hb_qsv_av1_profiles_names; default: return NULL; @@ -3206,13 +3329,13 @@ const char* const* hb_qsv_level_get_names(int encoder) { switch (encoder) { - case HB_VCODEC_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H264: return hb_h264_qsv_level_names; - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: return hb_h265_qsv_level_names; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: return hb_av1_qsv_level_names; default: return NULL; @@ -3223,12 +3346,12 @@ const int* hb_qsv_get_pix_fmts(int encoder) { switch (encoder) { - case HB_VCODEC_QSV_H264: - case HB_VCODEC_QSV_H265: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_AV1: return hb_qsv_pix_fmts; - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: return hb_qsv_10bit_pix_fmts; default: @@ -3244,17 +3367,17 @@ const char* hb_qsv_video_quality_get_name(uint32_t codec) { switch (codec) { - case HB_VCODEC_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H264: if (details->hb_qsv_info_avc != NULL) caps = details->hb_qsv_info_avc->capabilities; break; - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: if (details->hb_qsv_info_hevc != NULL) caps = details->hb_qsv_info_hevc->capabilities; break; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: if (details->hb_qsv_info_av1 != NULL) caps = details->hb_qsv_info_av1->capabilities; break; @@ -3274,8 +3397,8 @@ void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high, { switch (codec) { - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_H265: if (details->hb_qsv_info_hevc != NULL) caps = details->hb_qsv_info_hevc->capabilities; *direction = 1; *granularity = 1.; @@ -3283,8 +3406,8 @@ void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high, *high = 51.; break; - case HB_VCODEC_QSV_AV1_10BIT: - case HB_VCODEC_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: if (details->hb_qsv_info_av1 != NULL) caps = details->hb_qsv_info_av1->capabilities; *direction = 1; *granularity = 1.; @@ -3292,7 +3415,7 @@ void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high, *high = 51.; break; - case HB_VCODEC_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H264: default: if (details->hb_qsv_info_avc != NULL) caps = details->hb_qsv_info_avc->capabilities; *direction = 1; @@ -3304,136 +3427,22 @@ void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high, } } -int hb_qsv_param_default_preset(hb_qsv_param_t *param, - mfxVideoParam *videoParam, - hb_qsv_info_t *info, const char *preset) +const char * hb_map_qsv_preset_name(const char * preset) { - if (param != NULL && videoParam != NULL && info != NULL) - { - int ret = hb_qsv_param_default(param, videoParam, info); - if (ret) - { - return ret; - } - } - else + if (preset == NULL) { - hb_error("hb_qsv_param_default_preset: invalid pointer(s) param=%p videoParam=%p info=%p preset=%p", param, videoParam, info, preset); - return -1; + return "medium"; } - if (preset != NULL && preset[0] != '\0') - { - if (!strcasecmp(preset, "quality")) - { - /* - * HSW TargetUsage: 2 - * NumRefFrame: 0 - * GopRefDist: 4 (CQP), 3 (VBR) -> -1 (set by encoder) - * GopPicSize: 32 (CQP), 1 second (VBR) -> -1 (set by encoder) - * BPyramid: 1 (CQP), 0 (VBR) -> -1 (set by encoder) - * LookAhead: 1 (on) - * LookAheadDepth: 40 - * - * - * SNB - * IVB Preset Not Available - * - * Note: this preset is the libhb default (like x264's "medium"). - */ - if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7) - { - // Since IceLake only - param->rc.lookahead = 0; - param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_1; - } - } - else if (!strcasecmp(preset, "balanced")) - { - /* - * HSW TargetUsage: 4 - * NumRefFrame: 1 - * GopRefDist: 4 (CQP), 3 (VBR) -> -1 (set by encoder) - * GopPicSize: 32 (CQP), 1 second (VBR) -> -1 (set by encoder) - * BPyramid: 1 (CQP), 0 (VBR) -> -1 (set by encoder) - * LookAhead: 0 (off) - * LookAheadDepth: Not Applicable - */ - if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3) - { - param->rc.lookahead = 0; - param->videoParam->mfx.NumRefFrame = 1; - param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_4; - } - else - { - /* - * SNB - * IVB TargetUsage: 2 - * NumRefFrame: 0 - * GopRefDist: 4 (CQP), 3 (VBR) -> -1 (set by encoder) - * GopPicSize: 32 (CQP), 1 second (VBR) -> -1 (set by encoder) - * BPyramid: Not Applicable - * LookAhead: Not Applicable - * LookAheadDepth: Not Applicable - * - * Note: this preset is not the libhb default, - * but the settings are the same so do nothing. - */ - } - } - else if (!strcasecmp(preset, "speed")) - { - if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7) - { - // Since IceLake only - param->rc.lookahead = 0; - param->videoParam->mfx.NumRefFrame = 1; - param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_7; - } - else if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3) - { - /* - * HSW TargetUsage: 6 - * NumRefFrame: 0 (CQP), 1 (VBR) -> see note - * GopRefDist: 4 (CQP), 3 (VBR) -> -1 (set by encoder) - * GopPicSize: 32 (CQP), 1 second (VBR) -> -1 (set by encoder) - * BPyramid: 1 (CQP), 0 (VBR) -> -1 (set by encoder) - * LookAhead: 0 (off) - * LookAheadDepth: Not Applicable - * - * Note: NumRefFrame depends on the RC method, which we don't - * know here. Rather than have an additional variable and - * having the encoder set it, we set it to 1 and let the - * B-pyramid code sanitize it. Since BPyramid is 1 w/CQP, - * the result (3) is the same as what MSDK would pick for - * NumRefFrame 0 GopRefDist 4 GopPicSize 32. - */ - param->rc.lookahead = 0; - param->videoParam->mfx.NumRefFrame = 1; - param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_6; - } - else - { - /* - * SNB - * IVB TargetUsage: 4 - * NumRefFrame: 0 - * GopRefDist: 4 (CQP), 3 (VBR) -> -1 (set by encoder) - * GopPicSize: 32 (CQP), 1 second (VBR) -> -1 (set by encoder) - * BPyramid: Not Applicable - * LookAhead: Not Applicable - * LookAheadDepth: Not Applicable - */ - param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_4; - } - } - else - { - hb_error("hb_qsv_param_default_preset: invalid preset '%s'", preset); - return -1; - } + + if (strcmp(preset, "speed") == 0) { + return "veryfast"; + } else if (strcmp(preset, "balanced") == 0) { + return "medium"; + } else if (strcmp(preset, "quality") == 0) { + return "veryslow"; } - return 0; + + return "medium"; } int hb_qsv_param_default_async_depth() @@ -3441,10 +3450,9 @@ int hb_qsv_param_default_async_depth() return hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7 ? 6 : HB_QSV_ASYNC_DEPTH_DEFAULT; } -int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam, - hb_qsv_info_t *info) +int hb_qsv_param_default(hb_qsv_param_t *param, hb_qsv_info_t *info) { - if (param != NULL && videoParam != NULL && info != NULL) + if (param != NULL && info != NULL) { // introduced in API 1.0 memset(¶m->codingOption, 0, sizeof(mfxExtCodingOption)); @@ -3518,21 +3526,19 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam, param->codingOption2.LookAheadDS = MFX_LOOKAHEAD_DS_OFF; param->codingOption2.NumMbPerSlice = 0; // introduced in API 2.5 - memset(¶m->hyperEncodeParam, 0, sizeof(mfxExtHyperModeParam)); - param->hyperEncodeParam.Header.BufferId = MFX_EXTBUFF_HYPER_MODE_PARAM; - param->hyperEncodeParam.Header.BufferSz = sizeof(mfxExtHyperModeParam); - param->hyperEncodeParam.Mode = MFX_HYPERMODE_OFF; + param->hyperEncodeParam = hb_triplet4key(hb_qsv_hyper_encode_modes, "off"); memset(¶m->av1BitstreamParam, 0, sizeof(mfxExtAV1BitstreamParam)); param->av1BitstreamParam.Header.BufferId = MFX_EXTBUFF_AV1_BITSTREAM_PARAM; param->av1BitstreamParam.Header.BufferSz = sizeof(mfxExtAV1BitstreamParam); param->av1BitstreamParam.WriteIVFHeaders = MFX_CODINGOPTION_OFF; + // introduced in API 2.11 memset(¶m->av1ScreenContentToolsParam, 0, sizeof(mfxExtAV1ScreenContentTools)); param->av1ScreenContentToolsParam.Header.BufferId = MFX_EXTBUFF_AV1_SCREEN_CONTENT_TOOLS; param->av1ScreenContentToolsParam.Header.BufferSz = sizeof(mfxExtAV1ScreenContentTools); - param->av1ScreenContentToolsParam.IntraBlockCopy = MFX_CODINGOPTION_OFF; - param->av1ScreenContentToolsParam.Palette = MFX_CODINGOPTION_OFF; + param->av1ScreenContentToolsParam.IntraBlockCopy = 0; + param->av1ScreenContentToolsParam.Palette = 0; // GOP & rate control param->gop.b_pyramid = 1; // enabled by default (if supported) @@ -3540,7 +3546,7 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam, param->gop.gop_ref_dist = -1; // set automatically param->gop.int_ref_cycle_size = -1; // set automatically param->rc.icq = 1; // enabled by default (if supported) - param->rc.lookahead = 1; // enabled by default (if supported) + param->rc.lookahead = 0; // disabled by default param->rc.cqp_offsets[0] = 0; param->rc.cqp_offsets[1] = 2; param->rc.cqp_offsets[2] = 4; @@ -3548,73 +3554,12 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam, param->rc.vbv_buffer_size = 0; // set automatically param->rc.vbv_buffer_init = .0; // set automatically - // introduced in API 1.0 - memset(videoParam, 0, sizeof(mfxVideoParam)); - param->videoParam = videoParam; - param->videoParam->Protected = 0; // reserved, must be 0 - param->videoParam->NumExtParam = 0; - param->videoParam->IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; - param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED; - param->videoParam->mfx.GopOptFlag = MFX_GOP_CLOSED; - param->videoParam->mfx.NumThread = 0; // deprecated, must be 0 - param->videoParam->mfx.EncodedOrder = 0; // input is in display order - param->videoParam->mfx.IdrInterval = 0; // all I-frames are IDR - param->videoParam->mfx.NumSlice = 0; // use Media SDK default - param->videoParam->mfx.NumRefFrame = 0; // use Media SDK default - param->videoParam->mfx.GopPicSize = 0; // use Media SDK default - param->videoParam->mfx.GopRefDist = 0; // use Media SDK default - param->videoParam->mfx.LowPower = MFX_CODINGOPTION_OFF; // use Media SDK default - // introduced in API 1.1 - param->videoParam->AsyncDepth = hb_qsv_param_default_async_depth(); - // introduced in API 1.3 - param->videoParam->mfx.BRCParamMultiplier = 0; // no multiplier + param->low_power = 0; - // FrameInfo: set by video encoder, except PicStruct - param->videoParam->mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; - - // attach supported mfxExtBuffer structures to the mfxVideoParam - param->videoParam->NumExtParam = 0; - param->videoParam->ExtParam = param->ExtParamArray; - if (info->capabilities & HB_QSV_CAP_VUI_VSINFO) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->videoSignalInfo; - } - if (info->capabilities & HB_QSV_CAP_VUI_CHROMALOCINFO) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->chromaLocInfo; - } - if (info->capabilities & HB_QSV_CAP_VUI_MASTERINGINFO) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->masteringDisplayColourVolume; - } - if (info->capabilities & HB_QSV_CAP_VUI_CLLINFO) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->contentLightLevelInfo; - } - if (info->capabilities & HB_QSV_CAP_OPTION1) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption; - } - if (info->capabilities & HB_QSV_CAP_OPTION2) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption2; - } - if (info->capabilities & HB_QSV_CAP_HYPERENCODE) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->hyperEncodeParam; - } - if (info->capabilities & HB_QSV_CAP_AV1_BITSTREAM) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->av1BitstreamParam; - } - if (info->capabilities & HB_QSV_CAP_AV1_SCREENCONTENT) - { - param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->av1ScreenContentToolsParam; - } #if defined(_WIN32) || defined(__MINGW32__) if (info->capabilities & HB_QSV_CAP_LOWPOWER_ENCODE) { - param->videoParam->mfx.LowPower = MFX_CODINGOPTION_ON; + param->low_power = 1; } #endif } @@ -3880,723 +3825,99 @@ int hb_qsv_param_parse_dx_index(hb_job_t *job, const int dx_index) } #if defined(_WIN32) || defined(__MINGW32__) -// Direct X -#define COBJMACROS -#include -static int hb_qsv_find_surface_idx(const QSVMid *mids, const int nb_mids, const QSVMid *mid) +static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) { - if (mids) + int ret = -1; + if(s->hw_frames_ctx) { - int i; - for (i = 0; i < nb_mids; i++) { - const QSVMid *m = &mids[i]; - if ((m->handle_pair->first == mid->handle_pair->first) && - (m->handle_pair->second == mid->handle_pair->second)) - return i; - } + ret = av_hwframe_get_buffer(s->hw_frames_ctx, frame, 0); } - return -1; + return ret; } -int hb_qsv_replace_surface_mid(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const QSVMid *mid, mfxFrameSurface1 *surface) +void hb_qsv_uninit_enc(hb_job_t *job) { - if (!hb_enc_qsv_frames_ctx || !surface) - return -1; - - int ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx->mids, hb_enc_qsv_frames_ctx->nb_mids, mid); - if (ret < 0) + if(job->qsv.ctx && job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) { - hb_error("hb_qsv_replace_surface_mid: Surface with MemId=%p has not been found in the pool", mid); - return -1; + if (job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) + av_buffer_unref(&job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); + av_free(job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); + job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx = NULL; } - else + if (job->qsv.ctx && job->qsv.ctx->hb_dec_qsv_frames_ctx) { - surface->Data.MemId = &hb_enc_qsv_frames_ctx->mids[ret]; + if (job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf) + av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf); + job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf = NULL; + if (job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx) + av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx); + job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx = NULL; + av_free(job->qsv.ctx->hb_dec_qsv_frames_ctx); + job->qsv.ctx->hb_dec_qsv_frames_ctx = NULL; } - return 0; -} - -int hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const mfxFrameSurface1 *surface) -{ - if (!(hb_enc_qsv_frames_ctx && hb_enc_qsv_frames_ctx->hw_frames_ctx) || !surface) - return -1; - - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - - for(int i = 0; i < hb_enc_qsv_frames_ctx->nb_mids; i++) + if (job->qsv.ctx && job->qsv.ctx->hb_vpp_qsv_frames_ctx) { - mfxFrameSurface1 *pool_surface = &frames_hwctx->surfaces[i]; - if(surface == pool_surface && hb_enc_qsv_frames_ctx->pool[i] > 0) - { - ff_qsv_atomic_dec(&hb_enc_qsv_frames_ctx->pool[i]); - return 0; - } + if (job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf) + av_buffer_unref(&job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf); + job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf = NULL; + if (job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx) + av_buffer_unref(&job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx); + job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx = NULL; + av_free(job->qsv.ctx->hb_vpp_qsv_frames_ctx); + job->qsv.ctx->hb_vpp_qsv_frames_ctx = NULL; } - return -1; + if (job->qsv.ctx && job->qsv.ctx->hb_hw_device_ctx) + { + av_buffer_unref(&job->qsv.ctx->hb_hw_device_ctx); + job->qsv.ctx->hb_hw_device_ctx = NULL; + } + job->qsv.ctx->device_manager_handle = NULL; } -int hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, mfxFrameSurface1 *surface, QSVMid **out_mid) +static int hb_qsv_ffmpeg_set_options(hb_job_t *job, AVDictionary** dict) { - if (!hb_enc_qsv_frames_ctx || !surface) - return -1; + int err; + AVDictionary* out_dict = *dict; - QSVMid *mid = NULL; - - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - // find the first available surface in the pool - int count = 0; - while(1) + if (job->qsv.ctx && job->qsv.ctx->dx_index >= 0) { - if(count > 30) - { - hb_error("hb_qsv_get_mid_by_surface_from_pool has not been found or busy", mid); - hb_qsv_sleep(10); // prevent hang when all surfaces all used - count = 0; - } - - for(int i = 0; i < hb_enc_qsv_frames_ctx->nb_mids; i++) + char device[32]; + snprintf(device, 32, "%u", job->qsv.ctx->dx_index); + err = av_dict_set(&out_dict, "child_device", device, 0); + if (err < 0) { - mid = &hb_enc_qsv_frames_ctx->mids[i]; - mfxFrameSurface1 *pool_surface = &frames_hwctx->surfaces[i]; - if( (pool_surface->Data.Locked == 0) && (surface == pool_surface)) - { - *out_mid = mid; - return 0; - } + return err; } - count++; } + + av_dict_set(&out_dict, "child_device_type", "d3d11va", 0); + + *dict = out_dict; + return 0; } -int hb_qsv_get_free_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, AVFrame* frame, QSVMid** out_mid) +int hb_qsv_device_init(hb_job_t *job, void **hw_device_ctx) { - if (!hb_enc_qsv_frames_ctx || !frame) - return -1; - - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + int err; + AVDictionary *dict = NULL; + AVBufferRef *ctx = NULL; - // find the first available surface in the pool - int count = 0; - while(1) + if(job) { - if(count > 30) - { - hb_qsv_sleep(10); // prevent hang when all surfaces all used - count = 0; - } - - int ret = av_hwframe_get_buffer(hb_enc_qsv_frames_ctx->hw_frames_ctx, frame, 0); - if (ret) - { - continue; - } - else - { - mfxFrameSurface1 *output_surface = (mfxFrameSurface1 *)frame->data[3]; - for(int i = 0; i < hb_enc_qsv_frames_ctx->nb_mids; i++) - { - QSVMid* mid = &hb_enc_qsv_frames_ctx->mids[i]; - mfxFrameSurface1* cur_surface = &frames_hwctx->surfaces[i]; - if(cur_surface == output_surface) - { - if((hb_enc_qsv_frames_ctx->pool[i] == 0) && (output_surface->Data.Locked == 0)) - { - *out_mid = mid; - ff_qsv_atomic_inc(&hb_enc_qsv_frames_ctx->pool[i]); - return 0; - } - else - { - // we need to do unref if surface is not taken to be used, otherwise -12. - av_frame_unref(frame); - break; - } - } - } - } - count++; - } -} - -static int hb_qsv_get_dx_device(hb_job_t *job) -{ - AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)job->qsv.ctx->hb_hw_device_ctx->data; - AVQSVDeviceContext *device_hwctx = device_ctx->hwctx; - mfxSession parent_session = device_hwctx->session; - - if (job->qsv.ctx->device_manager_handle == NULL) - { - mfxIMPL device_impl; - int err = MFXQueryIMPL(parent_session, &device_impl); - if (err != MFX_ERR_NONE) - { - hb_error("hb_qsv_get_dx_device: no impl could be retrieved"); - return -1; - } - - if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(device_impl)) - { - job->qsv.ctx->device_manager_handle_type = MFX_HANDLE_D3D11_DEVICE; - } - else - { - hb_error("hb_qsv_get_dx_device: unsupported impl"); - return -1; - } - - err = MFXVideoCORE_GetHandle(parent_session, job->qsv.ctx->device_manager_handle_type, &job->qsv.ctx->device_manager_handle); - if (err != MFX_ERR_NONE) - { - hb_error("hb_qsv_get_dx_device: no supported hw handle could be retrieved " - "from the session\n"); - return -1; - } - if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE) - { - if (job->qsv.ctx->device_context == NULL) - { - ID3D11Device *device = (ID3D11Device *)job->qsv.ctx->device_manager_handle; - ID3D11Device_GetImmediateContext(device, (ID3D11DeviceContext **)&job->qsv.ctx->device_context); - if (!job->qsv.ctx->device_context) - return -1; - } - } - } - return 0; -} - -void hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const int start_index, const int end_index, QSVMid** out_mid, mfxFrameSurface1** out_surface) -{ - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data; - AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - - // find the first available surface in the pool - int count = 0; - while(1) - { - if (count > 30) - { - hb_qsv_sleep(10); // prevent hang when all surfaces all used - count = 0; - } - - for (int i = start_index; i < end_index; i++) - { - if ((hb_enc_qsv_frames_ctx->pool[i] == 0) && (frames_hwctx->surfaces[i].Data.Locked == 0)) - { - *out_mid = &hb_enc_qsv_frames_ctx->mids[i]; - *out_surface = &frames_hwctx->surfaces[i]; - ff_qsv_atomic_inc(&hb_enc_qsv_frames_ctx->pool[i]); - return; - } - } - count++; - } -} - -static ID3D11Texture2D* hb_qsv_create_dx11_texture_with_bytes(ID3D11Device* device, const byte* bytes, int stride, int width, int height, DXGI_FORMAT texture_format) -{ - if (device == NULL) - { - hb_error("hb_qsv_create_dx11_texture_with_bytes: device is NULL"); - return NULL; - } - - ID3D11Texture2D* tex; - D3D11_TEXTURE2D_DESC tdesc; - D3D11_SUBRESOURCE_DATA tbsd; - HRESULT hr; - - tbsd.pSysMem = (void *)bytes; - tbsd.SysMemPitch = stride; - - tdesc.Width = width; - tdesc.Height = height; - tdesc.MipLevels = 1; - tdesc.ArraySize = 1; - tdesc.SampleDesc.Count = 1; - tdesc.SampleDesc.Quality = 0; - tdesc.Usage = D3D11_USAGE_DEFAULT; - tdesc.Format = texture_format; - tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - tdesc.CPUAccessFlags = 0; - tdesc.MiscFlags = 0; - - hr = ID3D11Device_CreateTexture2D(device, &tdesc, &tbsd, &tex); - if (FAILED(hr)) - { - hb_error("CreateTexture: ID3D11Device_CreateTexture2D failed", hr); - return NULL; - } - return tex; -} - -static int hb_qsv_copy_surface(hb_qsv_context *ctx, void* output_surface, int output_index, void* input_surface, int input_index) -{ - if(!ctx) - { - hb_error("hb_qsv_copy_surface: qsv context is NULL"); - return -1; - } - - if (ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE) - { - ID3D11DeviceContext_CopySubresourceRegion((ID3D11DeviceContext *)ctx->device_context, output_surface, output_index, 0, 0, 0, input_surface, input_index, NULL); - ID3D11DeviceContext_Flush((ID3D11DeviceContext *)ctx->device_context); - } - else - { - hb_error("hb_qsv_copy_surface: incorrect device type %d", ctx->device_manager_handle_type); - return -1; - } - return 0; -} - -hb_buffer_t * hb_qsv_copy_video_buffer_to_hw_video_buffer(hb_job_t *job, hb_buffer_t *in, const int is_vpp) -{ - hb_buffer_t *out = hb_buffer_wrapper_init(); - - if (out == NULL) - { - goto fail; - } - - // Alloc new frame - AVFrame *frame = av_frame_alloc(); - - if (frame == NULL) - { - hb_error("hb_qsv_copy_video_buffer_to_hw_video_buffer: av_frame_alloc() failed"); - goto fail; - } - - frame->pts = in->s.start; - frame->duration = in->s.duration; - frame->width = in->f.width; - frame->height = in->f.height; - frame->format = in->f.fmt; - - if (in->s.combed) - { - frame->flags |= AV_FRAME_FLAG_INTERLACED; - } - else - { - frame->flags &= ~AV_FRAME_FLAG_INTERLACED; - } - - if (in->s.flags & PIC_FLAG_TOP_FIELD_FIRST) - { - frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; - } - else - { - frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; - } - - frame->format = in->f.fmt; - frame->color_primaries = hb_colr_pri_hb_to_ff(in->f.color_prim); - frame->color_trc = hb_colr_tra_hb_to_ff(in->f.color_transfer); - frame->colorspace = hb_colr_mat_hb_to_ff(in->f.color_matrix); - frame->color_range = in->f.color_range; - frame->chroma_location = in->f.chroma_location; - - out->storage_type = AVFRAME; - out->storage = frame; - out->f = in->f; - hb_buffer_copy_props(out, in); - - QSVMid *mid = NULL; - mfxFrameSurface1 *surface = NULL; - HBQSVFramesContext *hb_qsv_frames_ctx = NULL; - - if (is_vpp) - { - hb_qsv_frames_ctx = job->qsv.ctx->hb_vpp_qsv_frames_ctx; - } - else - { - hb_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx; - } - - if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE) - { - DXGI_FORMAT texture_format; - ID3D11Texture2D* output_surface; - D3D11_TEXTURE2D_DESC desc = { 0 }; - if (job->input_pix_fmt == AV_PIX_FMT_NV12) - { - texture_format = DXGI_FORMAT_NV12; - } - else if(job->input_pix_fmt == AV_PIX_FMT_P010) - { - texture_format = DXGI_FORMAT_P010; - } - else - { - hb_error("hb_qsv_copy_video_buffer_to_hw_video_buffer: unsupported texture_format=%d", job->input_pix_fmt); - goto fail; - } - hb_qsv_get_free_surface_from_pool_with_range(hb_qsv_frames_ctx, 0, HB_QSV_POOL_SURFACE_SIZE, &mid, &surface); - output_surface = mid->handle_pair->first; - ID3D11Texture2D_GetDesc(output_surface, &desc); - ID3D11Texture2D* blank_surface = hb_qsv_create_dx11_texture_with_bytes(job->qsv.ctx->device_manager_handle, - in->data, in->plane[0].stride, desc.Width, desc.Height, texture_format); - if (!blank_surface) - { - hb_error("hb_qsv_copy_video_buffer_to_hw_video_buffer: hb_qsv_create_dx11_texture_with_bytes() failed"); - goto fail; - } - mfxHDLPair* output_pair = (mfxHDLPair*)surface->Data.MemId; - int output_index = (int)(intptr_t)output_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)output_pair->second; - int ret = hb_qsv_copy_surface(job->qsv.ctx, output_surface, output_index, blank_surface, 0); - if (ret < 0) - { - hb_error("hb_qsv_copy_video_buffer_to_hw_video_buffer: hb_qsv_copy_surface() failed"); - goto fail; - } - ID3D11Texture2D_Release(blank_surface); - } - - frame->data[3] = (uint8_t *)surface; - - out->qsv_details.qsv_frames_ctx = hb_qsv_frames_ctx; - out->qsv_details.qsv_atom = NULL; - out->qsv_details.ctx = job->qsv.ctx; - - return out; - -fail: - hb_buffer_close(&out); - av_frame_free(&frame); - return NULL; -} - -hb_buffer_t * hb_qsv_buffer_dup(hb_job_t *job, hb_buffer_t *in, const int is_vpp) -{ - if (in->storage == NULL || in->storage_type != AVFRAME) - { - hb_error("hb_qsv_buffer_dup: in->storage is NULL"); - goto fail; - } - - hb_buffer_t *out = hb_buffer_wrapper_init(); - - if (out == NULL) - { - goto fail; - } - - // Alloc new frame - AVFrame *frame_copy = av_frame_alloc(); - - if (frame_copy == NULL) - { - hb_error("hb_qsv_buffer_dup: av_frame_alloc() failed"); - goto fail; - } - - AVFrame *frame = (AVFrame *)in->storage; - frame_copy->format = frame->format; - frame_copy->width = frame->width; - frame_copy->height = frame->height; - frame_copy->ch_layout = frame->ch_layout; - frame_copy->nb_samples = frame->nb_samples; - - mfxFrameSurface1 *input_surface = (mfxFrameSurface1 *)frame->data[3]; - mfxHDLPair *input_pair = (mfxHDLPair*)input_surface->Data.MemId; - - int ret = av_frame_copy_props(frame_copy, frame); - if (ret < 0) - { - hb_error("hb_qsv_buffer_dup: av_frame_copy_props error %d", ret); - goto fail; - } - - out->storage_type = AVFRAME; - out->storage = frame_copy; - out->f = in->f; - hb_buffer_copy_props(out, in); - - QSVMid *mid = NULL; - mfxFrameSurface1 *surface = NULL; - HBQSVFramesContext *hb_qsv_frames_ctx = NULL; - - if (is_vpp) - { - hb_qsv_frames_ctx = job->qsv.ctx->hb_vpp_qsv_frames_ctx; - } - else - { - hb_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx; - } - - if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE) - { - hb_qsv_get_free_surface_from_pool_with_range(hb_qsv_frames_ctx, 0, HB_QSV_POOL_SURFACE_SIZE, &mid, &surface); - mfxHDLPair* output_pair = (mfxHDLPair*)surface->Data.MemId; - int input_index = (int)(intptr_t)input_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)input_pair->second; - int output_index = (int)(intptr_t)output_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)output_pair->second; - int ret = hb_qsv_copy_surface(job->qsv.ctx, mid->handle_pair->first, output_index, input_pair->first, input_index); - if (ret < 0) - { - hb_error("hb_qsv_buffer_dup: hb_qsv_copy_surface() failed"); - goto fail; - } - } - else - { - hb_error("hb_qsv_buffer_dup: device_manager_handle_type unsupported=%d", job->qsv.ctx->device_manager_handle_type); - goto fail; - } - - frame_copy->data[3] = (uint8_t *)surface; - - out->qsv_details.qsv_frames_ctx = hb_qsv_frames_ctx; - out->qsv_details.qsv_atom = NULL; - out->qsv_details.ctx = job->qsv.ctx; - - return out; - -fail: - hb_buffer_close(&out); - av_frame_free(&frame_copy); - return NULL; -} - -hb_buffer_t * hb_qsv_copy_avframe_to_video_buffer(hb_job_t *job, AVFrame *frame, AVRational time_base, const int is_vpp) -{ - hb_buffer_t *out = hb_buffer_wrapper_init(); - - if (out == NULL) - { - return NULL; - } - - // Alloc new frame - AVFrame *frame_copy = av_frame_alloc(); - if (frame_copy == NULL) - { - goto fail; - } - - frame_copy->format = frame->format; - frame_copy->width = frame->width; - frame_copy->height = frame->height; - frame_copy->ch_layout = frame->ch_layout; - frame_copy->nb_samples = frame->nb_samples; - - int ret = av_frame_copy_props(frame_copy, frame); - if (ret < 0) - { - hb_error("hb_qsv_copy_avframe_to_video_buffer: av_frame_copy_props error %d", ret); - goto fail; - } - - out->storage_type = AVFRAME; - out->storage = frame_copy; - - out->s.type = FRAME_BUF; - out->f.width = frame_copy->width; - out->f.height = frame_copy->height; - hb_avframe_set_video_buffer_flags(out, frame, time_base); - - out->side_data = (void **)frame_copy->side_data; - out->nb_side_data = frame_copy->nb_side_data; - - QSVMid *mid = NULL; - mfxFrameSurface1 *output_surface = NULL; - HBQSVFramesContext *hb_qsv_frames_ctx = NULL; - - if (is_vpp) - { - hb_qsv_frames_ctx = job->qsv.ctx->hb_vpp_qsv_frames_ctx; - } - else - { - hb_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx; - if (!hb_qsv_frames_ctx || !hb_qsv_frames_ctx->hw_frames_ctx) - { - AVHWFramesContext *frames_ctx = (AVHWFramesContext *)frame->hw_frames_ctx->data; - ret = hb_qsv_create_ffmpeg_dec_pool(job, frame_copy->width, frame_copy->height, frames_ctx->sw_format); - if (ret < 0) - { - hb_error("hb_qsv_copy_avframe_to_video_buffer: hb_create_ffmpeg_pool decoder failed %d", ret); - goto fail; - } - } - } - - if (!is_vpp && hb_qsv_hw_filters_via_video_memory_are_enabled(job)) - { - ret = hb_qsv_get_free_surface_from_pool(hb_qsv_frames_ctx, frame_copy, &mid); - if (ret < 0) - { - hb_error("hb_qsv_copy_avframe_to_video_buffer: hb_qsv_get_free_surface_from_pool error %d", ret); - goto fail; - } - output_surface = (mfxFrameSurface1 *)frame_copy->data[3]; - } - else - { - hb_qsv_get_free_surface_from_pool_with_range(hb_qsv_frames_ctx, 0, HB_QSV_POOL_SURFACE_SIZE, &mid, &output_surface); - } - - if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE) - { - mfxFrameSurface1 *input_surface = (mfxFrameSurface1 *)frame->data[3]; - mfxHDLPair *input_pair = (mfxHDLPair *)input_surface->Data.MemId; - - // Need to pass 0 instead of MFX_INFINITE to DirectX as index of surface - int input_index = (int)(intptr_t)input_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)input_pair->second; - int output_index = (int)(intptr_t)mid->handle_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)mid->handle_pair->second; - - // Copy all surface fields - *output_surface = *input_surface; - output_surface->Info.CropW = frame->width; - output_surface->Info.CropH = frame->height; - if (hb_qsv_hw_filters_via_video_memory_are_enabled(job)) - { - // Make sure that we pass handle_pair to scale_qsv - output_surface->Data.MemId = mid->handle_pair; - } - else - { - // Make sure that we pass QSVMid to QSV encoder - output_surface->Data.MemId = mid; - } - - // Copy input surface to surface from the pool - ret = hb_qsv_copy_surface(job->qsv.ctx, mid->handle_pair->first, output_index, input_pair->first, input_index); - if (ret < 0) - { - hb_error("hb_qsv_copy_avframe_to_video_buffer: hb_qsv_copy_surface() failed"); - goto fail; - } - } - else - { - hb_error("hb_qsv_copy_avframe_to_video_buffer: incorrect mfx impl"); - goto fail; - } - - frame_copy->data[3] = (uint8_t *)output_surface; - - out->qsv_details.qsv_frames_ctx = hb_qsv_frames_ctx; - out->qsv_details.qsv_atom = NULL; - out->qsv_details.ctx = job->qsv.ctx; - - return out; - -fail: - hb_buffer_close(&out); - av_frame_free(&frame_copy); - return NULL; -} - -static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) -{ - int ret = -1; - if(s->hw_frames_ctx) - { - ret = av_hwframe_get_buffer(s->hw_frames_ctx, frame, 0); - } - return ret; -} - -void hb_qsv_uninit_dec(AVCodecContext *s) -{ - if(s && s->hw_frames_ctx) - av_buffer_unref(&s->hw_frames_ctx); -} - -void hb_qsv_uninit_enc(hb_job_t *job) -{ - if (job->qsv.ctx && job->qsv.ctx->device_context) - { - ID3D11DeviceContext_Release((ID3D11DeviceContext *)job->qsv.ctx->device_context); - job->qsv.ctx->device_context = NULL; - } - if(job->qsv.ctx && job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) - { - if (job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) - av_buffer_unref(&job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); - av_free(job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); - job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx = NULL; - } - if (job->qsv.ctx && job->qsv.ctx->hb_dec_qsv_frames_ctx) - { - if (job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf) - av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf); - job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf = NULL; - if (job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx) - av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx); - job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx = NULL; - av_free(job->qsv.ctx->hb_dec_qsv_frames_ctx); - job->qsv.ctx->hb_dec_qsv_frames_ctx = NULL; - } - if (job->qsv.ctx && job->qsv.ctx->hb_vpp_qsv_frames_ctx) - { - if (job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf) - av_buffer_unref(&job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf); - job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf = NULL; - if (job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx) - av_buffer_unref(&job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx); - job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx = NULL; - av_free(job->qsv.ctx->hb_vpp_qsv_frames_ctx); - job->qsv.ctx->hb_vpp_qsv_frames_ctx = NULL; - } - if (job->qsv.ctx && job->qsv.ctx->hb_hw_device_ctx) - { - av_buffer_unref(&job->qsv.ctx->hb_hw_device_ctx); - job->qsv.ctx->hb_hw_device_ctx = NULL; - } - job->qsv.ctx->device_manager_handle = NULL; -} - -static int hb_qsv_ffmpeg_set_options(hb_job_t *job, AVDictionary** dict) -{ - int err; - AVDictionary* out_dict = *dict; - - if (job->qsv.ctx && job->qsv.ctx->dx_index >= 0) - { - char device[32]; - snprintf(device, 32, "%u", job->qsv.ctx->dx_index); - err = av_dict_set(&out_dict, "child_device", device, 0); + err = hb_qsv_ffmpeg_set_options(job, &dict); if (err < 0) - { return err; - } } - av_dict_set(&out_dict, "child_device_type", "d3d11va", 0); - - *dict = out_dict; - return 0; -} - -int hb_qsv_device_init(hb_job_t *job) -{ - int err; - AVDictionary *dict = NULL; - - err = hb_qsv_ffmpeg_set_options(job, &dict); - - if (err < 0) - return err; - - err = av_hwdevice_ctx_create(&job->qsv.ctx->hb_hw_device_ctx, AV_HWDEVICE_TYPE_QSV, + err = av_hwdevice_ctx_create(&ctx, AV_HWDEVICE_TYPE_QSV, 0, dict, 0); if (err < 0) { hb_error("hb_qsv_device_init: error creating a QSV device %d", err); goto err_out; } + *hw_device_ctx = ctx; err_out: if (dict) av_dict_free(&dict); @@ -4604,184 +3925,6 @@ int hb_qsv_device_init(hb_job_t *job) return err; } -int hb_qsv_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum AVPixelFormat sw_pix_fmt, int pool_size, int extra_hw_frames, AVBufferRef **out_hw_frames_ctx) -{ - AVHWFramesContext *frames_ctx; - AVQSVFramesContext *frames_hwctx; - - AVBufferRef *hw_frames_ctx = *out_hw_frames_ctx; - - int ret = 0; - - if (job->qsv.ctx && !job->qsv.ctx->hb_hw_device_ctx) { - // parse and use user-specified encoder options for decoder, if present - if (job->encoder_options != NULL && *job->encoder_options) - { - hb_dict_t *options_list; - options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec); - - hb_dict_iter_t iter; - for (iter = hb_dict_iter_init(options_list); - iter != HB_DICT_ITER_DONE; - iter = hb_dict_iter_next(options_list, iter)) - { - const char *key = hb_dict_iter_key(iter); - if ((!strcasecmp(key, "scalingmode") || !strcasecmp(key, "vpp-sm")) && (hb_qsv_hw_filters_via_video_memory_are_enabled(job) || - hb_qsv_hw_filters_via_system_memory_are_enabled(job))) - { - hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec); - if (info && (info->capabilities & HB_QSV_CAP_VPP_SCALING)) - { - hb_value_t *value = hb_dict_iter_value(iter); - char *mode_key = hb_value_get_string_xform(value); - hb_triplet_t *mode = NULL; - if (mode_key != NULL) - { - mode = hb_triplet4key(hb_qsv_vpp_scale_modes, mode_key); - } - if (mode != NULL) - { - job->qsv.ctx->vpp_scale_mode = mode->key; - } - } - } - if ((!strcasecmp(key, "interpolationmethod") || !strcasecmp(key, "vpp-im")) && (hb_qsv_hw_filters_via_video_memory_are_enabled(job) || - hb_qsv_hw_filters_via_system_memory_are_enabled(job))) - { - hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec); - if (info && (info->capabilities & HB_QSV_CAP_VPP_INTERPOLATION)) - { - hb_value_t *value = hb_dict_iter_value(iter); - char *mode_key = hb_value_get_string_xform(value); - hb_triplet_t *mode = NULL; - if (mode_key != NULL) - { - mode = hb_triplet4key(hb_qsv_vpp_interpolation_methods, mode_key); - } - if (mode != NULL) - { - job->qsv.ctx->vpp_interpolation_method = mode->key; - } - } - } - } - hb_dict_free(&options_list); - } - - ret = hb_qsv_device_init(job); - if (ret < 0) - return ret; - } - - av_buffer_unref(&hw_frames_ctx); - hw_frames_ctx = av_hwframe_ctx_alloc(job->qsv.ctx->hb_hw_device_ctx); - if (!hw_frames_ctx) - return AVERROR(ENOMEM); - - *out_hw_frames_ctx = hw_frames_ctx; - - frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; - frames_hwctx = frames_ctx->hwctx; - - frames_ctx->width = FFALIGN(coded_width, 32); - frames_ctx->height = FFALIGN(coded_height, 32); - frames_ctx->format = AV_PIX_FMT_QSV; - frames_ctx->sw_format = sw_pix_fmt; - frames_ctx->initial_pool_size = pool_size; - if (extra_hw_frames >= 0) - frames_ctx->initial_pool_size += extra_hw_frames; - frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; - - ret = av_hwframe_ctx_init(hw_frames_ctx); - if (ret < 0) { - hb_error("hb_create_ffmpeg_pool: av_hwframe_ctx_init failed %d", ret); - return ret; - } - return 0; -} - -int hb_qsv_hw_frames_init(AVCodecContext *s) -{ - int ret; - - hb_job_t *job = s->opaque; - if (!job) { - hb_error("hb_qsv_hw_frames_init: job is NULL"); - return -1; - } - - int coded_width = s->coded_width; - int coded_height = s->coded_height; - enum AVPixelFormat sw_pix_fmt = s->sw_pix_fmt; - int extra_hw_frames = s->extra_hw_frames; - AVBufferRef **out_hw_frames_ctx = &s->hw_frames_ctx; - - ret = hb_qsv_create_ffmpeg_pool(job, coded_width, coded_height, sw_pix_fmt, HB_QSV_POOL_FFMPEG_SURFACE_SIZE, extra_hw_frames, out_hw_frames_ctx); - if (ret < 0) { - hb_error("hb_qsv_hw_frames_init: hb_create_ffmpeg_pool decoder failed %d", ret); - return ret; - } - - // hb_qsv_hw_frames_init function called two times by FFmpeg, first with NV12 by default, second with P010 if requested - if(job->qsv.ctx && job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) - { - if (job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx) - av_buffer_unref(&job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); - av_free(job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx); - job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx = NULL; - } - job->qsv.ctx->hb_ffmpeg_qsv_hw_frames_ctx = *out_hw_frames_ctx; - - ret = hb_qsv_get_dx_device(job); - if (ret < 0) { - hb_error("qsv_init: hb_qsv_get_dx_device failed %d", ret); - return ret; - } - - return 0; -} - -int hb_qsv_create_ffmpeg_dec_pool(hb_job_t * job, int width, int height, int sw_pix_fmt) -{ - if (job->qsv.ctx && job->qsv.ctx->hb_dec_qsv_frames_ctx && job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx) - { - if (job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf) - av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf); - job->qsv.ctx->hb_dec_qsv_frames_ctx->mids_buf = NULL; - if (job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx) - av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx); - job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx = NULL; - } - - int ret = hb_qsv_create_ffmpeg_pool(job, width, height, sw_pix_fmt, HB_QSV_POOL_SURFACE_SIZE, 0, &job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx); - if (ret < 0) - { - hb_error("hb_qsv_create_ffmpeg_dec_pool allocation failed"); - return ret; - } - - AVHWFramesContext *frames_ctx; - AVQSVFramesContext *frames_hwctx; - AVBufferRef *hw_frames_ctx; - - hw_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx; - frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; - frames_hwctx = frames_ctx->hwctx; - mfxHDLPair* handle_pair = (mfxHDLPair*)frames_hwctx->surfaces[0].Data.MemId; - HBQSVFramesContext *hb_dec_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx; - hb_dec_qsv_frames_ctx->input_texture = ((size_t)handle_pair->second != MFX_INFINITE) ? handle_pair->first : NULL; - - /* allocate the memory ids for the external frames */ - av_buffer_unref(&hb_dec_qsv_frames_ctx->mids_buf); - hb_dec_qsv_frames_ctx->mids_buf = hb_qsv_create_mids(hb_dec_qsv_frames_ctx->hw_frames_ctx); - if (!hb_dec_qsv_frames_ctx->mids_buf) - return AVERROR(ENOMEM); - hb_dec_qsv_frames_ctx->mids = (QSVMid*)hb_dec_qsv_frames_ctx->mids_buf->data; - hb_dec_qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; - memset(hb_dec_qsv_frames_ctx->pool, 0, hb_dec_qsv_frames_ctx->nb_mids * sizeof(hb_dec_qsv_frames_ctx->pool[0])); - - return 0; -} int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) { if (frame->format == AV_PIX_FMT_QSV) @@ -4790,76 +3933,10 @@ int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) return avcodec_default_get_buffer2(s, frame, flags); } -enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts) +int hb_qsv_are_filters_supported(hb_job_t *job) { - int n; - hb_job_t *job = s->opaque; - - // Find end of list. - for (n = 0; pix_fmts[n] != AV_PIX_FMT_NONE; n++); - // if not full path, take the system format, it must be the last entry - if (hb_qsv_get_memory_type(job) == MFX_IOPATTERN_OUT_SYSTEM_MEMORY) - return pix_fmts[n - 1]; - - while (*pix_fmts != AV_PIX_FMT_NONE) { - if (*pix_fmts == AV_PIX_FMT_QSV) { - int ret = hb_qsv_hw_frames_init(s); - if (ret < 0) { - hb_error("hb_qsv_get_format: QSV hwaccel initialization failed"); - return AV_PIX_FMT_NONE; - } - if (s->hw_frames_ctx) { - s->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx); - if (!s->hw_frames_ctx) - return AV_PIX_FMT_NONE; - } - return AV_PIX_FMT_QSV; - } - - pix_fmts++; - } - - hb_error("hb_qsv_get_format: the QSV pixel format not offered in get_format()"); - return AV_PIX_FMT_NONE; -} - -int hb_qsv_create_ffmpeg_vpp_pool(hb_filter_init_t *init, int width, int height) -{ - if (init->job->qsv.ctx && init->job->qsv.ctx->hb_vpp_qsv_frames_ctx && init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx) - { - if (init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf) - av_buffer_unref(&init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf); - init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf = NULL; - if (init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx) - av_buffer_unref(&init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx); - init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx = NULL; - } - - int result = hb_qsv_create_ffmpeg_pool(init->job, width, height, init->pix_fmt, HB_QSV_POOL_SURFACE_SIZE, 0, &init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx); - if (result < 0) - { - hb_error("hb_create_ffmpeg_pool vpp allocation failed"); - return result; - } - AVHWFramesContext *frames_ctx; - AVQSVFramesContext *frames_hwctx; - AVBufferRef *hw_frames_ctx; - - hw_frames_ctx = init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx; - frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; - frames_hwctx = frames_ctx->hwctx; - mfxHDLPair* handle_pair = (mfxHDLPair*)frames_hwctx->surfaces[0].Data.MemId; - init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->input_texture = ((size_t)handle_pair->second != MFX_INFINITE) ? handle_pair->first : NULL; - - /* allocate the memory ids for the external frames */ - av_buffer_unref(&init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf); - init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf = hb_qsv_create_mids(init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx); - if (!init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf) - return AVERROR(ENOMEM); - init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids = (QSVMid*)init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->mids_buf->data; - init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; - memset(init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->pool, 0, init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->nb_mids * sizeof(init->job->qsv.ctx->hb_vpp_qsv_frames_ctx->pool[0])); - return 0; + hb_qsv_sanitize_filter_list(job); + return job->qsv.ctx->num_sw_filters == 0; } int hb_qsv_sanitize_filter_list(hb_job_t *job) @@ -4901,6 +3978,9 @@ int hb_qsv_sanitize_filter_list(hb_job_t *job) break; } } + case HB_FILTER_AVFILTER: + num_hw_filters++; + break; default: // count only filters with access to frame data num_sw_filters++; @@ -4927,9 +4007,9 @@ int hb_qsv_sanitize_filter_list(hb_job_t *job) #else // other OS -int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum AVPixelFormat sw_pix_fmt, int pool_size, int extra_hw_frames, AVBufferRef **out_hw_frames_ctx) +int hb_qsv_are_filters_supported(hb_job_t *job) { - return -1; + return 0; } int hb_qsv_hw_frames_init(AVCodecContext *s) @@ -4937,42 +4017,7 @@ int hb_qsv_hw_frames_init(AVCodecContext *s) return -1; } -int hb_qsv_device_init(hb_job_t *job) -{ - return -1; -} - -int hb_qsv_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum AVPixelFormat sw_pix_fmt, int pool_size, int extra_hw_frames, AVBufferRef **out_hw_frames_ctx) -{ - return -1; -} - -hb_buffer_t * hb_qsv_copy_video_buffer_to_hw_video_buffer(hb_job_t *job, hb_buffer_t *in, const int is_vpp) -{ - return NULL; -} - -hb_buffer_t * hb_qsv_buffer_dup(hb_job_t *job, hb_buffer_t *in, const int is_vpp) -{ - return NULL; -} - -hb_buffer_t * hb_qsv_copy_avframe_to_video_buffer(hb_job_t *job, AVFrame *frame, AVRational time_base, const int is_vpp) -{ - return NULL; -} - -int hb_qsv_get_free_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, AVFrame* frame, QSVMid** out_mid) -{ - return -1; -} - -void hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const int start_index, const int end_index, QSVMid** out_mid, mfxFrameSurface1** out_surface) -{ - return; -} - -int hb_qsv_replace_surface_mid(HBQSVFramesContext* hb_qsv_frames_ctx, const QSVMid *mid, mfxFrameSurface1 *surface) +int hb_qsv_device_init(hb_job_t *job, void **hw_device_ctx) { return -1; } @@ -4987,24 +4032,10 @@ int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) return -1; } -void hb_qsv_uninit_dec(AVCodecContext *s) -{ -} - void hb_qsv_uninit_enc(hb_job_t *job) { } -int hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, mfxFrameSurface1 *surface, QSVMid **out_mid) -{ - return -1; -} - -int hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const mfxFrameSurface1 *surface) -{ - return -1; -} - #endif hb_qsv_context* hb_qsv_context_init() diff --git a/libhb/rotate.c b/libhb/rotate.c index 733a3923c5c85..207116a699d98 100644 --- a/libhb/rotate.c +++ b/libhb/rotate.c @@ -12,8 +12,6 @@ #if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) #include "handbrake/qsv_common.h" -#include "libavutil/hwcontext_qsv.h" -#include "libavutil/hwcontext.h" #endif static int rotate_init(hb_filter_object_t * filter, hb_filter_init_t * init); @@ -90,16 +88,6 @@ static int qsv_rotate_init(hb_filter_private_t * pv, hb_filter_init_t * init, in break; } - if (hb_qsv_hw_filters_via_video_memory_are_enabled(init->job)) - { - int result = hb_qsv_create_ffmpeg_vpp_pool(init, width, height); - if (result < 0) - { - hb_error("hb_create_ffmpeg_pool vpp allocation failed"); - return result; - } - } - if (trans != NULL) { hb_dict_t * avfilter = hb_dict_init(); @@ -195,7 +183,8 @@ static int rotate_init(hb_filter_object_t * filter, hb_filter_init_t * init) } #if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ )) - if (hb_qsv_hw_filters_via_video_memory_are_enabled(init->job) || hb_qsv_hw_filters_via_system_memory_are_enabled(init->job)) + if (hb_hwaccel_is_full_hardware_pipeline_enabled(init->job) && + hb_qsv_decode_is_enabled(init->job)) { qsv_rotate_init(pv, init, angle, flip); return 0; diff --git a/libhb/scan.c b/libhb/scan.c index 63281d001fce5..109957182081b 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -715,6 +715,11 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush ) { hw_decode = HB_DECODE_SUPPORT_VIDEOTOOLBOX; } + else if (data->hw_decode == HB_DECODE_SUPPORT_QSV && + hb_hwaccel_available(title->video_codec_param, "qsv")) + { + hw_decode = HB_DECODE_SUPPORT_QSV; + } else if (data->hw_decode == HB_DECODE_SUPPORT_MF && hb_hwaccel_available(title->video_codec_param, "d3d11va")) { @@ -724,7 +729,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush ) void *hw_device_ctx = NULL; if (hw_decode) { - hb_hwaccel_hw_ctx_init(title->video_codec_param, hw_decode, &hw_device_ctx); + hb_hwaccel_hw_ctx_init(title->video_codec_param, hw_decode, &hw_device_ctx, NULL); } hb_work_object_t *vid_decoder = hb_get_work(data->h, title->video_codec); diff --git a/libhb/sync.c b/libhb/sync.c index b4ce3f5653f82..17f14aff5e983 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -407,13 +407,6 @@ static hb_buffer_t * CreateBlackBuf( sync_stream_t * stream, } } -#if HB_PROJECT_FEATURE_QSV - if (hb_qsv_get_memory_type(stream->common->job) == MFX_IOPATTERN_OUT_VIDEO_MEMORY) - { - buf = hb_qsv_copy_video_buffer_to_hw_video_buffer(stream->common->job, buf, hb_qsv_hw_filters_via_video_memory_are_enabled(stream->common->job)); - } - else -#endif if (hb_hwaccel_is_full_hardware_pipeline_enabled(stream->common->job)) { buf = hb_hwaccel_copy_video_buffer_to_hw_video_buffer(stream->common->job, &buf); @@ -421,13 +414,6 @@ static hb_buffer_t * CreateBlackBuf( sync_stream_t * stream, } else { -#if HB_PROJECT_FEATURE_QSV - if (hb_qsv_get_memory_type(stream->common->job) == MFX_IOPATTERN_OUT_VIDEO_MEMORY) - { - buf = hb_qsv_buffer_dup(stream->common->job, buf, hb_qsv_hw_filters_via_video_memory_are_enabled(stream->common->job)); - } - else -#endif { buf = hb_buffer_dup(buf); } diff --git a/libhb/work.c b/libhb/work.c index 064817bbf5925..7076957f6c7ba 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -267,13 +267,22 @@ hb_work_object_t* hb_video_encoder(hb_handle_t *h, int vcodec) case HB_VCODEC_X264_10BIT: w = hb_get_work(h, WORK_ENCX264); break; - case HB_VCODEC_QSV_H264: - case HB_VCODEC_QSV_H265: - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_AV1: - case HB_VCODEC_QSV_AV1_10BIT: - w = hb_get_work(h, WORK_ENCQSV); +#if HB_PROJECT_FEATURE_QSV + case HB_VCODEC_FFMPEG_QSV_H264: + w = hb_get_work(h, WORK_ENCAVCODEC); + w->codec_param = AV_CODEC_ID_H264; + break; + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + w = hb_get_work(h, WORK_ENCAVCODEC); + w->codec_param = AV_CODEC_ID_HEVC; break; + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: + w = hb_get_work(h, WORK_ENCAVCODEC); + w->codec_param = AV_CODEC_ID_AV1; + break; +#endif case HB_VCODEC_THEORA: w = hb_get_work(h, WORK_ENCTHEORA); break; @@ -584,11 +593,11 @@ void hb_display_job_info(hb_job_t *job) case HB_VCODEC_X265_10BIT: case HB_VCODEC_X265_12BIT: case HB_VCODEC_X265_16BIT: - case HB_VCODEC_QSV_H264: - case HB_VCODEC_QSV_H265: - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_AV1: - case HB_VCODEC_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: case HB_VCODEC_FFMPEG_VCE_H264: case HB_VCODEC_FFMPEG_VCE_H265: case HB_VCODEC_FFMPEG_VCE_H265_10BIT: @@ -620,11 +629,11 @@ void hb_display_job_info(hb_job_t *job) case HB_VCODEC_X265_8BIT: case HB_VCODEC_X265_10BIT: case HB_VCODEC_X265_12BIT: - case HB_VCODEC_QSV_H264: - case HB_VCODEC_QSV_H265: - case HB_VCODEC_QSV_H265_10BIT: - case HB_VCODEC_QSV_AV1: - case HB_VCODEC_QSV_AV1_10BIT: + case HB_VCODEC_FFMPEG_QSV_H264: + case HB_VCODEC_FFMPEG_QSV_H265: + case HB_VCODEC_FFMPEG_QSV_H265_10BIT: + case HB_VCODEC_FFMPEG_QSV_AV1: + case HB_VCODEC_FFMPEG_QSV_AV1_10BIT: case HB_VCODEC_FFMPEG_VCE_H264: case HB_VCODEC_FFMPEG_VCE_H265: case HB_VCODEC_FFMPEG_VCE_H265_10BIT: @@ -1716,7 +1725,8 @@ static void do_job(hb_job_t *job) { hb_hwaccel_hw_ctx_init(job->title->video_codec_param, job->hw_decode, - &job->hw_device_ctx); + &job->hw_device_ctx, + job); } sanitize_dynamic_hdr_metadata_passthru(job); @@ -2176,15 +2186,6 @@ static void do_job(hb_job_t *job) hb_buffer_pool_free(); hb_hwaccel_hw_ctx_close(&job->hw_device_ctx); - -#if HB_PROJECT_FEATURE_QSV - if (!job->indepth_scan && - (job->pass_id != HB_PASS_ENCODE_ANALYSIS) && - hb_qsv_is_enabled(job)) - { - hb_qsv_context_uninit(job); - } -#endif } static inline void copy_chapter( hb_buffer_t * dst, hb_buffer_t * src ) diff --git a/test/test.c b/test/test.c index 9d54d17cbf522..1611f4b7b34e9 100644 --- a/test/test.c +++ b/test/test.c @@ -1502,6 +1502,7 @@ static void ShowHelp(void) " Use 'videotoolbox' to enable VideoToolbox \n" #else " Use 'nvdec' to enable NVDec \n" +" Use 'qsv' to enable QSV decoding \n" #endif " --disable-hw-decoding Disable hardware decoding of the video track,\n" " forcing software decoding instead\n" @@ -3225,6 +3226,13 @@ static int ParseOptions( int argc, char ** argv ) } #endif } +#if HB_PROJECT_FEATURE_QSV + else if (!strcmp(optarg, "qsv")) + { + qsv_decode = 1; + hw_decode = HB_DECODE_SUPPORT_QSV; + } +#endif else if (!strcmp(optarg, "mf")) { hw_decode = HB_DECODE_SUPPORT_MF; @@ -4374,6 +4382,7 @@ static hb_dict_t * PreparePreset(const char *preset_name) if (qsv_decode != -1) { hb_dict_set(preset, "VideoQSVDecode", hb_value_int(qsv_decode)); + hw_decode = qsv_decode ? HB_DECODE_SUPPORT_QSV : 0; } #endif if (hw_decode != -1) diff --git a/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs b/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs index 1f5464f038c4a..9df5470442f5a 100644 --- a/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs +++ b/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs @@ -108,7 +108,7 @@ public static bool IsQsvAvailableH264 { try { - return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_QSV_H264) > 0; + return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_FFMPEG_QSV_H264) > 0; } catch (Exception) { @@ -124,7 +124,7 @@ public static bool IsQsvAvailableH265 { try { - return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_QSV_H265) > 0; + return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_FFMPEG_QSV_H265) > 0; } catch (Exception) { @@ -186,7 +186,7 @@ public static bool IsQsvAvailableH26510bit { try { - return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_QSV_H265_10BIT) > 0; + return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_FFMPEG_QSV_H265_10BIT) > 0; } catch (Exception) { @@ -202,7 +202,7 @@ public static bool IsQsvAvailableAV1 { try { - return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_QSV_AV1) > 0; + return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_FFMPEG_QSV_AV1) > 0; } catch (Exception) { @@ -218,7 +218,7 @@ public static bool IsQsvAvailableAV110bit { try { - return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_QSV_AV1_10BIT) > 0; + return (HBFunctions.hb_qsv_available() & NativeConstants.HB_VCODEC_FFMPEG_QSV_AV1_10BIT) > 0; } catch (Exception) { diff --git a/win/CS/HandBrake.Interop/Interop/HbLib/NativeConstants.cs b/win/CS/HandBrake.Interop/Interop/HbLib/NativeConstants.cs index ac2c1b48ea679..a494c059c9709 100644 --- a/win/CS/HandBrake.Interop/Interop/HbLib/NativeConstants.cs +++ b/win/CS/HandBrake.Interop/Interop/HbLib/NativeConstants.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // @@ -73,6 +73,6 @@ public class NativeConstants public const uint HB_DECODE_SUPPORT_VIDEOTOOLBOX = 0x08; public const uint HB_DECODE_SUPPORT_MF = 0x10; - public const uint HB_DECODE_SUPPORT_HWACCEL = (HB_DECODE_SUPPORT_NVDEC | HB_DECODE_SUPPORT_VIDEOTOOLBOX | HB_DECODE_SUPPORT_MF); + public const uint HB_DECODE_SUPPORT_HWACCEL = (HB_DECODE_SUPPORT_NVDEC | HB_DECODE_SUPPORT_VIDEOTOOLBOX | HB_DECODE_SUPPORT_QSV | HB_DECODE_SUPPORT_MF); } }