From d63dea50bf06f590030bc6fc88dc5381dcbb93aa Mon Sep 17 00:00:00 2001 From: rigaya Date: Tue, 30 Jul 2024 23:21:14 +0900 Subject: [PATCH] =?UTF-8?q?dolby=20vision=20profile=E3=81=AE=E3=82=B3?= =?UTF-8?q?=E3=83=94=E3=83=BC=E3=81=AB=E5=AF=BE=E5=BF=9C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NVEnc/NVEnc_readme.txt | 14 +++++- NVEncC_Options.en.md | 24 ++++++---- NVEncC_Options.ja.md | 23 +++++---- NVEncCore/NVEncCore.cpp | 16 +++++-- NVEncCore/NVEncCore.h | 1 + NVEncCore/NVEncParam.cpp | 7 +-- NVEncCore/NVEncParam.h | 2 +- NVEncCore/rgy_avutil.cpp | 25 ++++++++++ NVEncCore/rgy_avutil.h | 7 +++ NVEncCore/rgy_cmd.cpp | 15 ++++-- NVEncCore/rgy_def.h | 21 +++++++-- NVEncCore/rgy_frame.cpp | 31 ++++++++++++- NVEncCore/rgy_input.h | 3 ++ NVEncCore/rgy_input_avcodec.cpp | 4 ++ NVEncCore/rgy_input_avcodec.h | 2 + NVEncCore/rgy_output.cpp | 25 +++++----- NVEncCore/rgy_output_avcodec.cpp | 80 ++++++++++++++++++++++++++++---- NVEncCore/rgy_output_avcodec.h | 4 ++ NVEncCore/rgy_prm.cpp | 2 +- NVEncCore/rgy_prm.h | 2 +- NVEncCore/rgy_version.h | 6 +-- 21 files changed, 252 insertions(+), 62 deletions(-) diff --git a/NVEnc/NVEnc_readme.txt b/NVEnc/NVEnc_readme.txt index 32f1ee43..83b1f619 100644 --- a/NVEnc/NVEnc_readme.txt +++ b/NVEnc/NVEnc_readme.txt @@ -215,8 +215,18 @@ NVIDIA グラフィックドライバ 551.23 今後の更新で設定ファイルの互換性がなくなるかもしれません。 【メモ】 -2024.07.2x (7.58) -- --vpp-frucでfps指定の時の処理速度を大幅に向上。 +2024.08.01 (7.58) +[NVEncC] +- Dolby Vision profileのコピー機能を追加。(--dolby-vision-profile copy) +- Dolby Vision rpu metadataのコピー機能を追加。(--dolby-vision-rpu copy) +- --vpp-frucでfps指定の時の処理速度を大幅に向上。( #586 ) +- --vpp-tweakにチャネルごとの制御を追加。 +- H.264/HEVCのヘッダがうまく取得できない場合、最初のパケットから取得するように。( #604 ) +- --vpp-nlmeansで search=3 にするとエラー終了していた問題を修正。 +- 音声のmux用のバッファ不足になり、音声が同時刻の映像と違うfragmentにmuxされる問題を修正。 + +[NVEnc.auo] +- Windowsの登録拡張子の状況によっては、意図せず出力拡張子が設定されず、muxされなくなってしまう問題を回避。 2024.06.29 (7.57) - --vpp-colorspace, --vpp-resize ngx-vsr, --vpp-ngx-truehdr が一部の言語のOSで正常に動作しない問題を修正。 diff --git a/NVEncC_Options.en.md b/NVEncC_Options.en.md index bddf6b30..9a886891 100644 --- a/NVEncC_Options.en.md +++ b/NVEncC_Options.en.md @@ -121,8 +121,9 @@ - [--atc-sei \ or \ \[HEVC only\]](#--atc-sei-string-or-int-hevc-only) - [--dhdr10-info \ \[HEVC, AV1\]](#--dhdr10-info-string-hevc-av1) - [--dhdr10-info copy \[HEVC, AV1\]](#--dhdr10-info-copy-hevc-av1) - - [--dolby-vision-profile \](#--dolby-vision-profile-float) - - [--dolby-vision-rpu \](#--dolby-vision-rpu-string) + - [--dolby-vision-profile \ \[HEVC, AV1\]](#--dolby-vision-profile-string-hevc-av1) + - [--dolby-vision-rpu \ \[HEVC, AV1\]](#--dolby-vision-rpu-string-hevc-av1) + - [--dolby-vision-rpu copy \[HEVC\]](#--dolby-vision-rpu-copy-hevc) - [--aud \[H.264/HEVC\]](#--aud-h264hevc) - [--repeat-headers](#--repeat-headers) - [--pic-struct \[H.264/HEVC\]](#--pic-struct-h264hevc) @@ -887,16 +888,23 @@ Copy HDR10+ dynamic metadata from input file. Limitations for avhw reader: this option uses timestamps to reorder frames to decoded order to presentation order. Therefore, input files without timestamps (such as raw ES), are not supported. Please try for avsw reader for that case. -### --dolby-vision-profile <float> -Output file which is specified in Dolby Vision profile. +### --dolby-vision-profile <string> [HEVC, AV1] +Output file which is specified in Dolby Vision profile. Recommended to be used with [--dolby-vision-rpu](#--dolby-vision-rpu-string). + +"copy" will use dolby vision profile from input file (available when using [avhw](#--avhw)/[avsw](#--avsw) reader). + ``` -5.0, 8.1, 8.2, 8.4 +unset, copy, 5.0, 8.1, 8.2, 8.4 ``` -### --dolby-vision-rpu <string> -Interleave Dolby Vision RPU metadata from the specified file into the output file. +### --dolby-vision-rpu <string> [HEVC, AV1] +Interleave Dolby Vision RPU metadata from the specified file into the output file. Recommended to be used with [--dolby-vision-profile](#--dolby-vision-profile-string). + +### --dolby-vision-rpu copy [HEVC] +Interleave Dolby Vision RPU metadata copied from HEVC input file. Recommended to be used with [--dolby-vision-profile](#--dolby-vision-profile-string). -Currently, the Dolby Vision info in the re-encoded file will not be detected by MediaInfo. In order to be able to detect the Dolby Vision info by MediaInfo, you will need to re-mux the output file by [tsMuxeR](https://github.com/justdan96/tsMuxer/releases) (nightly). +Limitations for avhw reader: this option uses timestamps to reorder frames to decoded order to presentation order. +Therefore, input files without timestamps (such as raw ES), are not supported. Please try for avsw reader for that case. ### --aud [H.264/HEVC] Insert Access Unit Delimiter NAL. diff --git a/NVEncC_Options.ja.md b/NVEncC_Options.ja.md index ab44aab8..909aa124 100644 --- a/NVEncC_Options.ja.md +++ b/NVEncC_Options.ja.md @@ -117,8 +117,9 @@ - [--atc-sei \ or \ \[HEVCのみ\]](#--atc-sei-string-or-int-hevcのみ) - [--dhdr10-info \ \[HEVC, AV1\]](#--dhdr10-info-string-hevc-av1) - [--dhdr10-info copy \[HEVC, AV1\]](#--dhdr10-info-copy-hevc-av1) - - [--dolby-vision-profile \ \[HEVC\]](#--dolby-vision-profile-float-hevc) - - [--dolby-vision-rpu \ \[HEVC\]](#--dolby-vision-rpu-string-hevc) + - [--dolby-vision-profile \ \[HEVC, AV1\]](#--dolby-vision-profile-string-hevc-av1) + - [--dolby-vision-rpu \ \[HEVC, AV1\]](#--dolby-vision-rpu-string-hevc-av1) + - [--dolby-vision-rpu copy \[HEVC, AV1\]](#--dolby-vision-rpu-copy-hevc-av1) - [--aud \[H.264/HEVC\]](#--aud-h264hevc) - [--repeat-headers](#--repeat-headers) - [--pic-struct \[H.264/HEVC\]](#--pic-struct-h264hevc) @@ -893,18 +894,24 @@ HDR10+のメタデータを入力ファイルからそのままコピーしま avhw読み込みでは、フレームの並び替えにタイムスタンプを使用するため、タイムスタンプの取得できないraw ESのような入力ファイルでは使用できません。 こうした場合には、avsw読み込みを使用してください。 -### --dolby-vision-profile <float> [HEVC] -指定されたdolby visionプロファイルを適用します。 +### --dolby-vision-profile <string> [HEVC, AV1] +指定されたdolby visionプロファイルを適用します。[--dolby-vision-rpu](#--dolby-vision-rpu-string)との併用が推奨です。 + +"copy" は、入力ファイルのdolby visionプロファイルを適用します。 ([avhw](#--avhw)/[avsw](#--avsw)読み込みのみ) + ``` -5.0, 8.1, 8.2, 8.4 +unset, copy, 5.0, 8.1, 8.2, 8.4 ``` -### --dolby-vision-rpu <string> [HEVC] +### --dolby-vision-rpu <string> [HEVC, AV1] 指定のrpuファイルに含まれるdolby visionのmetadataを出力ファイルに挿入します。 -現時点(2022年1月実装時点)では、このオプションを使用して出力した動画ファイルは、MediaInfoによりDolby Vision情報が検出されません。 +### --dolby-vision-rpu copy [HEVC, AV1] +HEVCの入力ファイルから読み取ったdolby visionのmetadataを出力ファイルに挿入します。 [--dolby-vision-profile](#--dolby-vision-profile-string)との併用が推奨です。 + +avhw読み込みでは、フレームの並び替えにタイムスタンプを使用するため、タイムスタンプの取得できないraw ESのような入力ファイルでは使用できません。 +こうした場合には、avsw読み込みを使用してください。 -MediaInfoによるDolby Vision情報の検出を可能とするには、[tsMuxeR](https://github.com/justdan96/tsMuxer/releases) (nightly版) による再muxが必要です。 ### --aud [H.264/HEVC] Access Unit Delimiter NALを挿入する。 diff --git a/NVEncCore/NVEncCore.cpp b/NVEncCore/NVEncCore.cpp index c9fe9e5e..87908bf1 100644 --- a/NVEncCore/NVEncCore.cpp +++ b/NVEncCore/NVEncCore.cpp @@ -301,6 +301,7 @@ NVEncCore::NVEncCore() : m_hdrsei(), m_dovirpu(), m_dovirpuMetadataCopy(false), + m_doviProfile(RGY_DOVI_PROFILE_UNSET), m_encTimestamp(), m_encodeFrameID(0), m_videoIgnoreTimestampError(DEFAULT_VIDEO_IGNORE_TIMESTAMP_ERROR), @@ -635,6 +636,7 @@ NVENCSTATUS NVEncCore::InitInput(InEncodeVideoParam *inputParam, const std::vect } else if (inputParam->common.doviRpuMetadataCopy) { m_dovirpuMetadataCopy = true; } + m_doviProfile = inputParam->common.doviProfile; #endif m_hdrsei = createHEVCHDRSei(inputParam->common.maxCll, inputParam->common.masterDisplay, inputParam->common.atcSei, m_pFileReader.get()); @@ -3421,7 +3423,6 @@ NVENCSTATUS NVEncCore::InitEncode(InEncodeVideoParam *inputParam) { PrintMes(RGY_LOG_DEBUG, _T("Set Process priority: %s.\n"), rgy_thread_priority_mode_to_str(priority)); } - inputParam->applyDOVIProfile(); m_nAVSyncMode = inputParam->common.AVSyncMode; m_nProcSpeedLimit = inputParam->ctrl.procSpeedLimit; m_videoIgnoreTimestampError = inputParam->common.videoIgnoreTimestampError; @@ -3476,6 +3477,8 @@ NVENCSTATUS NVEncCore::InitEncode(InEncodeVideoParam *inputParam) { } PrintMes(RGY_LOG_DEBUG, _T("InitInput: Success.\n")); + inputParam->applyDOVIProfile(m_pFileReader->getInputDOVIProfile()); + bool bOutputHighBitDepth = encodeIsHighBitDepth(inputParam); if (inputParam->lossless && inputParam->losslessIgnoreInputCsp == 0) { const auto inputFrameInfo = m_pFileReader->GetInputFrameInfo(); @@ -5385,9 +5388,16 @@ tstring NVEncCore::GetEncodingParamsInfo(int output_level) { } } if (m_hdr10plus) { - add_str(RGY_LOG_INFO, _T("Dynamic HDR10 %s\n"), m_hdr10plus->inputJson().c_str()); + add_str(RGY_LOG_INFO, _T("Dynamic HDR10 %s\n"), m_hdr10plus->inputJson().c_str()); } else if (m_hdr10plusMetadataCopy) { - add_str(RGY_LOG_INFO, _T("Dynamic HDR10 copy\n")); + add_str(RGY_LOG_INFO, _T("Dynamic HDR10 copy\n")); + } + if (m_doviProfile != RGY_DOVI_PROFILE_UNSET) { + tstring profile_copy; + if (m_doviProfile == RGY_DOVI_PROFILE_COPY) { + profile_copy = tstring(_T(" (")) + get_cx_desc(list_dovi_profile, m_pFileReader->getInputDOVIProfile()) + tstring(_T(")")); + } + add_str(RGY_LOG_INFO, _T("dovi profile %s%s\n"), get_cx_desc(list_dovi_profile, m_doviProfile), profile_copy.c_str()); } if (m_dovirpu) { add_str(RGY_LOG_INFO, _T("dovi rpu %s\n"), m_dovirpu->get_filepath().c_str()); diff --git a/NVEncCore/NVEncCore.h b/NVEncCore/NVEncCore.h index b6c5d22b..36e7be2a 100644 --- a/NVEncCore/NVEncCore.h +++ b/NVEncCore/NVEncCore.h @@ -209,6 +209,7 @@ class NVEncCore : public NVEncCtrl { unique_ptr m_hdrsei; unique_ptr m_dovirpu; bool m_dovirpuMetadataCopy; + RGYDOVIProfile m_doviProfile; std::unique_ptr m_encTimestamp; int64_t m_encodeFrameID; int m_videoIgnoreTimestampError; diff --git a/NVEncCore/NVEncParam.cpp b/NVEncCore/NVEncParam.cpp index d798220d..0b5471b7 100644 --- a/NVEncCore/NVEncParam.cpp +++ b/NVEncCore/NVEncParam.cpp @@ -286,15 +286,16 @@ InEncodeVideoParam::InEncodeVideoParam() : input.vui = VideoVUIInfo(); } -void InEncodeVideoParam::applyDOVIProfile() { +void InEncodeVideoParam::applyDOVIProfile(const RGYDOVIProfile inputProfile) { #if !FOR_AUO if (codec_rgy != RGY_CODEC_HEVC) { return; } - if (common.doviProfile == 0) { + auto targetDoviProfile = (common.doviProfile == RGY_DOVI_PROFILE_COPY) ? inputProfile : common.doviProfile; + if (targetDoviProfile == 0) { return; } - auto profile = getDOVIProfile(common.doviProfile); + auto profile = getDOVIProfile(targetDoviProfile); if (profile == nullptr) { return; } diff --git a/NVEncCore/NVEncParam.h b/NVEncCore/NVEncParam.h index 03f07bb2..dc22a379 100644 --- a/NVEncCore/NVEncParam.h +++ b/NVEncCore/NVEncParam.h @@ -739,7 +739,7 @@ struct InEncodeVideoParam { InEncodeVideoParam(); - void applyDOVIProfile(); + void applyDOVIProfile(const RGYDOVIProfile inputProfile); }; static void setQP(NV_ENC_QP& nvencqp, const RGYQPSet& qp) { diff --git a/NVEncCore/rgy_avutil.cpp b/NVEncCore/rgy_avutil.cpp index cbaf1cf6..e65acf20 100644 --- a/NVEncCore/rgy_avutil.cpp +++ b/NVEncCore/rgy_avutil.cpp @@ -921,4 +921,29 @@ tstring getDispositionStr(uint32_t disposition) { return str; } +RGYDOVIProfile getStreamDOVIProfile(const AVStream *stream) { +#if LIBAVUTIL_DOVI_META_AVAIL + size_t side_data_size = 0; + auto doviconf = AVStreamGetSideData(stream, AV_PKT_DATA_DOVI_CONF, side_data_size); + if (!doviconf) { + return RGY_DOVI_PROFILE_UNSET; + } + switch (doviconf->dv_profile) { + case 5: + return RGY_DOVI_PROFILE_50; + case 8: + switch (doviconf->dv_bl_signal_compatibility_id) { + case 1: return RGY_DOVI_PROFILE_81; + case 2: return RGY_DOVI_PROFILE_82; + case 4: return RGY_DOVI_PROFILE_84; + default: return RGY_DOVI_PROFILE_UNSET; + } + default: + return RGY_DOVI_PROFILE_UNSET; + } +#else + return RGY_DOVI_PROFILE_UNSET; +#endif +} + #endif //ENABLE_AVSW_READER diff --git a/NVEncCore/rgy_avutil.h b/NVEncCore/rgy_avutil.h index 01d74208..aaf8de5e 100644 --- a/NVEncCore/rgy_avutil.h +++ b/NVEncCore/rgy_avutil.h @@ -47,6 +47,12 @@ extern "C" { #include #include #include +#if __has_include() +#define LIBAVUTIL_DOVI_META_AVAIL 1 +#include +#else +#define LIBAVUTIL_DOVI_META_AVAIL 0 +#endif #include #include #include @@ -498,6 +504,7 @@ MAP_PAIR_0_1_PROTO(disposition, str, tstring, av, uint32_t); uint32_t parseDisposition(const tstring &disposition_str); tstring getDispositionStr(uint32_t disposition); +RGYDOVIProfile getStreamDOVIProfile(const AVStream *stream); #else #define AV_NOPTS_VALUE (-1) diff --git a/NVEncCore/rgy_cmd.cpp b/NVEncCore/rgy_cmd.cpp index 81cf3b6b..44b0447c 100644 --- a/NVEncCore/rgy_cmd.cpp +++ b/NVEncCore/rgy_cmd.cpp @@ -5364,11 +5364,11 @@ int parse_one_common_option(const TCHAR *option_name, const TCHAR *strInput[], i i++; int value = 0; if (get_list_value(list_dovi_profile, strInput[i], &value)) { - common->doviProfile = value; + common->doviProfile = (RGYDOVIProfile)value; } else if (_stscanf_s(strInput[i], _T("%d"), &value) == 1) { - common->doviProfile = value; + common->doviProfile = (RGYDOVIProfile)value; } else { - print_cmd_error_invalid_value(option_name, strInput[i], list_colorprim); + print_cmd_error_invalid_value(option_name, strInput[i], list_dovi_profile); return 1; } return 0; @@ -7287,7 +7287,11 @@ tstring gen_cmd(const RGYParamCommon *param, const RGYParamCommon *defaultPrm, b OPT_TSTR(_T("--dhdr10-info"), dynamicHdr10plusJson); } OPT_LST(_T("--dolby-vision-profile"), doviProfile, list_dovi_profile); - OPT_STR_PATH(_T("--dolby-vision-rpu"), doviRpuFile); + if (param->doviRpuMetadataCopy) { + cmd << _T("--dolby-vision-rpu copy"); + } else { + OPT_STR_PATH(_T("--dolby-vision-rpu"), doviRpuFile); + } if (param->timecode || param->timecodeFile.length() > 0) { cmd << (param->timecode ? _T("--timecode ") : _T("--no-timecode ")); if (param->timecodeFile.length() > 0) { @@ -7536,7 +7540,8 @@ tstring gen_cmd_help_common() { #if ENABLE_DOVI_METADATA_OPTIONS str += print_list_options(_T("--dolby-vision-profile "), list_dovi_profile, 0); str += strsprintf( - _T(" --dolby-vision-rpu Copy dolby vision metadata from input rpu file.\n")); + _T(" --dolby-vision-rpu Copy dolby vision metadata from input rpu file.\n") + _T(" --dolby-vision-rpu copy Copy dolby vision metadata from input file.\n")); #endif //#if ENABLE_DOVI_METADATA_OPTIONS str += strsprintf( _T(" --input-analyze set time (sec) which reader analyze input file.\n") diff --git a/NVEncCore/rgy_def.h b/NVEncCore/rgy_def.h index f47717af..ba5bc6ad 100644 --- a/NVEncCore/rgy_def.h +++ b/NVEncCore/rgy_def.h @@ -474,12 +474,23 @@ const CX_DESC list_videoformat[] = { { NULL, 0 } }; + +enum RGYDOVIProfile { + RGY_DOVI_PROFILE_UNSET = 0, + RGY_DOVI_PROFILE_COPY = -1, + RGY_DOVI_PROFILE_50 = 50, + RGY_DOVI_PROFILE_81 = 81, + RGY_DOVI_PROFILE_82 = 82, + RGY_DOVI_PROFILE_84 = 84, +}; + const CX_DESC list_dovi_profile[] = { - { _T("unset"), 0 }, - { _T("5.0"), 50 }, - { _T("8.1"), 81 }, - { _T("8.2"), 82 }, - { _T("8.4"), 84 }, + { _T("unset"), RGY_DOVI_PROFILE_UNSET }, + { _T("copy"), RGY_DOVI_PROFILE_COPY }, + { _T("5.0"), RGY_DOVI_PROFILE_50 }, + { _T("8.1"), RGY_DOVI_PROFILE_81 }, + { _T("8.2"), RGY_DOVI_PROFILE_82 }, + { _T("8.4"), RGY_DOVI_PROFILE_84 }, { NULL, 0 } }; diff --git a/NVEncCore/rgy_frame.cpp b/NVEncCore/rgy_frame.cpp index 36886a7e..a91de076 100644 --- a/NVEncCore/rgy_frame.cpp +++ b/NVEncCore/rgy_frame.cpp @@ -169,7 +169,22 @@ std::vector RGYFrameDataHDR10plus::gen_nal() const { } std::vector RGYFrameDataHDR10plus::gen_obu() const { - return gen_av1_obu_metadata(AV1_METADATA_TYPE_ITUT_T35, m_data); + // https://aomediacodec.github.io/av1-hdr10plus/#hdr10-metadata + static const uint8_t itut_t35_header[] = { + 0xB5, // country code + 0x00, 0x3C, // provider_code + 0x00, 0x01, // provider_oriented_code + 0x04, // application_identifier + 0x01 // application_mode + }; + std::vector buf; + if (m_data.size() > sizeof(itut_t35_header) && memcmp(m_data.data(), itut_t35_header, sizeof(itut_t35_header)) == 0) { + buf = m_data; + } else { + buf = make_vector(itut_t35_header); + vector_cat(buf, m_data); + } + return gen_av1_obu_metadata(AV1_METADATA_TYPE_ITUT_T35, buf); } RGYFrameDataDOVIRpu::RGYFrameDataDOVIRpu() : RGYFrameDataMetadata() { m_dataType = RGY_FRAME_DATA_DOVIRPU; }; @@ -194,7 +209,19 @@ std::vector RGYFrameDataDOVIRpu::gen_nal() const { return ret; } std::vector RGYFrameDataDOVIRpu::gen_obu() const { - return gen_av1_obu_metadata(AV1_METADATA_TYPE_ITUT_T35, m_data); + static const uint8_t itut_t35_header[] = { + 0xB5, // country code + 0x00, 0x3B, // provider_code + 0x00, 0x00, 0x08, 0x00 // provider_oriented_code + }; + std::vector buf; + if (m_data.size() > sizeof(itut_t35_header) && memcmp(m_data.data(), itut_t35_header, sizeof(itut_t35_header)) == 0) { + buf = m_data; + } else { + buf = make_vector(itut_t35_header); + vector_cat(buf, m_data); + } + return gen_av1_obu_metadata(AV1_METADATA_TYPE_ITUT_T35, buf); } #endif diff --git a/NVEncCore/rgy_input.h b/NVEncCore/rgy_input.h index 8f987cc8..e271a79e 100644 --- a/NVEncCore/rgy_input.h +++ b/NVEncCore/rgy_input.h @@ -299,6 +299,9 @@ class RGYInput { RGY_CODEC getInputCodec() { return m_inputVideoInfo.codec; } + virtual RGYDOVIProfile getInputDOVIProfile() { + return RGY_DOVI_PROFILE_UNSET; + } protected: virtual RGY_ERR Init(const TCHAR *strFileName, VideoInfo *pInputInfo, const RGYInputPrm *prm) = 0; virtual void CreateInputInfo(const TCHAR *inputTypeName, const TCHAR *inputCSpName, const TCHAR *outputCSpName, const TCHAR *convSIMD, const VideoInfo *inputPrm); diff --git a/NVEncCore/rgy_input_avcodec.cpp b/NVEncCore/rgy_input_avcodec.cpp index 26c31cbf..156086a1 100644 --- a/NVEncCore/rgy_input_avcodec.cpp +++ b/NVEncCore/rgy_input_avcodec.cpp @@ -3279,6 +3279,10 @@ RGY_ERR RGYInputAvcodec::LoadNextFrameInternal(RGYFrame *pSurface) { } #pragma warning(pop) +RGYDOVIProfile RGYInputAvcodec::getInputDOVIProfile() { + return getStreamDOVIProfile(m_Demux.video.stream); +} + int RGYInputAvcodec::GetHWDecDeviceID() { return m_Demux.video.HWDecodeDeviceId; } diff --git a/NVEncCore/rgy_input_avcodec.h b/NVEncCore/rgy_input_avcodec.h index 22f1c93a..4f7ba6d7 100644 --- a/NVEncCore/rgy_input_avcodec.h +++ b/NVEncCore/rgy_input_avcodec.h @@ -897,6 +897,8 @@ class RGYInputAvcodec : public RGYInput virtual rgy_rational getInputTimebase() override; + virtual RGYDOVIProfile getInputDOVIProfile() override; + virtual bool rffAware() override; //入力ファイルに存在する音声のトラック数を返す diff --git a/NVEncCore/rgy_output.cpp b/NVEncCore/rgy_output.cpp index 1774a6ed..6de2c473 100644 --- a/NVEncCore/rgy_output.cpp +++ b/NVEncCore/rgy_output.cpp @@ -357,6 +357,9 @@ std::pair> RGYOutput::getMetadata(const RGYFrameDa } RGY_ERR RGYOutput::InsertMetadata(RGYBitstream *bitstream, std::vector>& metadataList) { + if (metadataList.size() == 0) { + return RGY_ERR_NONE; + } if (m_VideoOutputInfo.codec == RGY_CODEC_HEVC) { RGYBitstream bsCopy = RGYBitstreamInit(); bsCopy.copy(bitstream); @@ -679,12 +682,11 @@ RGY_ERR RGYOutputRaw::WriteNextFrame(RGYBitstream *pBitstream) { return sts; } } - const bool isIDR = (pBitstream->frametype() & (RGY_FRAMETYPE_IDR | RGY_FRAMETYPE_xIDR)) != 0; writeRawDebug(pBitstream); if (m_VideoOutputInfo.codec == RGY_CODEC_AV1) { const auto av1_units = parse_unit_av1(pBitstream->data(), pBitstream->size()); - const int td_count = std::count_if(av1_units.begin(), av1_units.end(), [](const std::unique_ptr& info) { return info->type == OBU_TEMPORAL_DELIMITER; }); + const auto td_count = std::count_if(av1_units.begin(), av1_units.end(), [](const std::unique_ptr& info) { return info->type == OBU_TEMPORAL_DELIMITER; }); if (td_count > 1) { RGYBitstream bsCopy = RGYBitstreamInit(); for (int i = 0; i < (int)av1_units.size(); i++) { @@ -736,15 +738,6 @@ RGY_ERR RGYOutputRaw::WriteNextOneFrame(RGYBitstream *pBitstream) { metadataList.push_back(std::make_unique(metadata_hdr10plus, false, false)); } } - { - auto [err_dovirpu, metadata_dovi_rpu] = getMetadata(RGY_FRAME_DATA_DOVIRPU, bs_framedata); - if (err_dovirpu != RGY_ERR_NONE) { - return err_dovirpu; - } - if (metadata_dovi_rpu.size() > 0) { - metadataList.push_back(std::make_unique(metadata_dovi_rpu, false, true)); - } - } if (m_doviRpu) { std::vector dovi_nal; if (m_doviRpu->get_next_rpu_nal(dovi_nal, bs_framedata.inputFrameId) != 0) { @@ -753,6 +746,14 @@ RGY_ERR RGYOutputRaw::WriteNextOneFrame(RGYBitstream *pBitstream) { if (dovi_nal.size() > 0) { metadataList.push_back(std::make_unique(dovi_nal, false, true)); } + } else { + auto [err_dovirpu, metadata_dovi_rpu] = getMetadata(RGY_FRAME_DATA_DOVIRPU, bs_framedata); + if (err_dovirpu != RGY_ERR_NONE) { + return err_dovirpu; + } + if (metadata_dovi_rpu.size() > 0) { + metadataList.push_back(std::make_unique(metadata_dovi_rpu, false, m_VideoOutputInfo.codec == RGY_CODEC_HEVC ? true : false)); + } } auto err = InsertMetadata(pBitstream, metadataList); @@ -1131,6 +1132,8 @@ RGY_ERR initWriters( writerPrm.attachments = common->attachmentSource; writerPrm.hdrMetadata = hdrMetadata; writerPrm.doviRpu = doviRpu; + writerPrm.doviRpuMetadataCopy = common->doviRpuMetadataCopy; + writerPrm.doviProfile = common->doviProfile; writerPrm.vidTimestamp = vidTimestamp; writerPrm.videoCodecTag = common->videoCodecTag; writerPrm.videoMetadata = common->videoMetadata; diff --git a/NVEncCore/rgy_output_avcodec.cpp b/NVEncCore/rgy_output_avcodec.cpp index 8e9b322d..a7e6e073 100644 --- a/NVEncCore/rgy_output_avcodec.cpp +++ b/NVEncCore/rgy_output_avcodec.cpp @@ -934,6 +934,33 @@ RGY_ERR RGYOutputAvcodec::InitVideo(const VideoInfo *videoOutputInfo, const Avco side_data_mastering.reset(); } } + if (prm->doviProfile == RGY_DOVI_PROFILE_COPY) { +#if LIBAVUTIL_DOVI_META_AVAIL + side_data_size = 0; + auto doviconf = AVStreamGetSideData(prm->videoInputStream, AV_PKT_DATA_DOVI_CONF, side_data_size); + if (doviconf) { + doviconf->el_present_flag = 0; + doviconf->rpu_present_flag = prm->doviRpu || prm->doviRpuMetadataCopy ? 1 : 0; + tstring bl_el_rpu; + if (doviconf->bl_present_flag) bl_el_rpu += _T("+BL"); + if (doviconf->el_present_flag) bl_el_rpu += _T("+EL"); + if (doviconf->rpu_present_flag) bl_el_rpu += _T("+RPU"); + AddMessage(RGY_LOG_DEBUG, _T("dovi config ver %d.%d, %d.%d:%d %s\n"), + doviconf->dv_version_major, doviconf->dv_version_minor, + doviconf->dv_profile, doviconf->dv_level, doviconf->dv_bl_signal_compatibility_id, + (bl_el_rpu.size() > 0) ? bl_el_rpu.substr(1).c_str() : _T("")); + int err = AVStreamAddSideData(m_Mux.video.streamOut, AV_PKT_DATA_DOVI_CONF, doviconf, side_data_size); + if (err < 0) { + AddMessage(RGY_LOG_ERROR, _T("failed to copy AV_PKT_DATA_DOVI_CONF\n")); + return RGY_ERR_INVALID_CALL; + } + AddMessage(RGY_LOG_DEBUG, _T("copied AV_PKT_DATA_DOVI_CONF from input\n")); + doviconf.reset(); + } +#else + AddMessage(RGY_LOG_WARN, _T("dovi-profile copy noy supported in this build!\n")); +#endif //#if LIBAVUTIL_DOVI_META_AVAIL + } } m_Mux.video.timestampList.clear(); @@ -1008,6 +1035,42 @@ RGY_ERR RGYOutputAvcodec::InitVideo(const VideoInfo *videoOutputInfo, const Avco } } + if (prm->doviProfile != RGY_DOVI_PROFILE_UNSET && prm->doviProfile != RGY_DOVI_PROFILE_COPY) { +#if LIBAVUTIL_DOVI_META_AVAIL + size_t conf_size = 0; + std::unique_ptr> doviconf(av_dovi_alloc(&conf_size), RGYAVDeleter(av_freep)); + doviconf->dv_version_major = 1; + doviconf->dv_version_minor = 0; + switch (prm->doviProfile) { + case RGY_DOVI_PROFILE_50: doviconf->dv_profile = 5; doviconf->dv_bl_signal_compatibility_id = 0; break; + case RGY_DOVI_PROFILE_81: doviconf->dv_profile = 8; doviconf->dv_bl_signal_compatibility_id = 1; break; + case RGY_DOVI_PROFILE_82: doviconf->dv_profile = 8; doviconf->dv_bl_signal_compatibility_id = 2; break; + case RGY_DOVI_PROFILE_84: doviconf->dv_profile = 8; doviconf->dv_bl_signal_compatibility_id = 4; break; + default: + AddMessage(RGY_LOG_ERROR, _T("Unsupported dolby vision profile: %d\n"), prm->doviProfile); + return RGY_ERR_UNSUPPORTED; + } + doviconf->dv_level = 10; + doviconf->bl_present_flag = 1; + doviconf->el_present_flag = 0; + doviconf->rpu_present_flag = prm->doviRpu || prm->doviRpuMetadataCopy ? 1 : 0; + tstring bl_el_rpu; + if (doviconf->bl_present_flag) bl_el_rpu += _T("+BL"); + if (doviconf->el_present_flag) bl_el_rpu += _T("+EL"); + if (doviconf->rpu_present_flag) bl_el_rpu += _T("+RPU"); + AddMessage(RGY_LOG_DEBUG, _T("dovi config ver %d.%d, %d.%d:%d %s\n"), + doviconf->dv_version_major, doviconf->dv_version_minor, + doviconf->dv_profile, doviconf->dv_level, doviconf->dv_bl_signal_compatibility_id, + (bl_el_rpu.size() > 0) ? bl_el_rpu.substr(1).c_str() : _T("")); + int err = AVStreamAddSideData(m_Mux.video.streamOut, AV_PKT_DATA_DOVI_CONF, doviconf, conf_size); + if (err < 0) { + AddMessage(RGY_LOG_ERROR, _T("failed to set AV_PKT_DATA_DOVI_CONF\n")); + return RGY_ERR_INVALID_CALL; + } + AddMessage(RGY_LOG_DEBUG, _T("set AV_PKT_DATA_DOVI_CONF\n")); +#endif + } + if (auto sts = InitVideoBsf(videoOutputInfo); sts != RGY_ERR_NONE) { return sts; } @@ -2694,15 +2757,6 @@ RGY_ERR RGYOutputAvcodec::WriteNextFrameInternalOneFrame(RGYBitstream *bitstream metadataList.push_back(std::make_unique(metadata_hdr10plus, false, false)); } } - { - auto [err_dovirpu, metadata_dovi_rpu] = getMetadata(RGY_FRAME_DATA_DOVIRPU, bs_framedata); - if (err_dovirpu != RGY_ERR_NONE) { - return err_dovirpu; - } - if (metadata_dovi_rpu.size() > 0) { - metadataList.push_back(std::make_unique(metadata_dovi_rpu, false, true)); - } - } if (m_Mux.video.doviRpu) { std::vector dovi_nal; if (m_Mux.video.doviRpu->get_next_rpu_nal(dovi_nal, bs_framedata.inputFrameId) != 0) { @@ -2711,6 +2765,14 @@ RGY_ERR RGYOutputAvcodec::WriteNextFrameInternalOneFrame(RGYBitstream *bitstream if (dovi_nal.size() > 0) { metadataList.push_back(std::make_unique(dovi_nal, false, true)); } + } else { + auto [err_dovirpu, metadata_dovi_rpu] = getMetadata(RGY_FRAME_DATA_DOVIRPU, bs_framedata); + if (err_dovirpu != RGY_ERR_NONE) { + return err_dovirpu; + } + if (metadata_dovi_rpu.size() > 0) { + metadataList.push_back(std::make_unique(metadata_dovi_rpu, false, m_VideoOutputInfo.codec == RGY_CODEC_HEVC ? true : false)); + } } auto err = InsertMetadata(bitstream, metadataList); diff --git a/NVEncCore/rgy_output_avcodec.h b/NVEncCore/rgy_output_avcodec.h index 28375327..2d23ecb6 100644 --- a/NVEncCore/rgy_output_avcodec.h +++ b/NVEncCore/rgy_output_avcodec.h @@ -393,6 +393,8 @@ struct AvcodecWriterPrm { tstring muxVidTsLogFile; //mux timestampログファイル const RGYHDRMetadata *hdrMetadata; //HDR関連のmetadata DOVIRpu *doviRpu; //DOVIRpu + bool doviRpuMetadataCopy; //doviのmetadataのコピー + RGYDOVIProfile doviProfile; //doviのprofile RGYTimestamp *vidTimestamp; //動画のtimestampの情報 std::string videoCodecTag; //動画タグ std::vector videoMetadata; //動画のmetadata @@ -430,6 +432,8 @@ struct AvcodecWriterPrm { muxVidTsLogFile(), hdrMetadata(nullptr), doviRpu(nullptr), + doviRpuMetadataCopy(false), + doviProfile(RGY_DOVI_PROFILE_UNSET), vidTimestamp(nullptr), videoCodecTag(), videoMetadata(), diff --git a/NVEncCore/rgy_prm.cpp b/NVEncCore/rgy_prm.cpp index 8203aff2..1292d975 100644 --- a/NVEncCore/rgy_prm.cpp +++ b/NVEncCore/rgy_prm.cpp @@ -1831,7 +1831,7 @@ RGYParamCommon::RGYParamCommon() : dynamicHdr10plusJson(), doviRpuMetadataCopy(false), doviRpuFile(), - doviProfile(0), + doviProfile(RGY_DOVI_PROFILE_UNSET), videoCodecTag(), videoMetadata(), formatMetadata(), diff --git a/NVEncCore/rgy_prm.h b/NVEncCore/rgy_prm.h index 311dde87..129ea9b3 100644 --- a/NVEncCore/rgy_prm.h +++ b/NVEncCore/rgy_prm.h @@ -1814,7 +1814,7 @@ struct RGYParamCommon { tstring dynamicHdr10plusJson; bool doviRpuMetadataCopy; tstring doviRpuFile; - int doviProfile; + RGYDOVIProfile doviProfile; std::string videoCodecTag; std::vector videoMetadata; std::vector formatMetadata; diff --git a/NVEncCore/rgy_version.h b/NVEncCore/rgy_version.h index 5ab4ae43..2e398351 100644 --- a/NVEncCore/rgy_version.h +++ b/NVEncCore/rgy_version.h @@ -29,9 +29,9 @@ #ifndef __RGY_CONFIG_H__ #define __RGY_CONFIG_H__ -#define VER_FILEVERSION 0,7,57,0 -#define VER_STR_FILEVERSION "7.57" -#define VER_STR_FILEVERSION_TCHAR _T("7.57") +#define VER_FILEVERSION 0,7,58,0 +#define VER_STR_FILEVERSION "7.58" +#define VER_STR_FILEVERSION_TCHAR _T("7.58") #ifdef _M_IX86 #define BUILD_ARCH_STR _T("x86")