diff --git a/NVEncC_Options.en.md b/NVEncC_Options.en.md index c70d59f3..4a727ffa 100644 --- a/NVEncC_Options.en.md +++ b/NVEncC_Options.en.md @@ -98,6 +98,7 @@ - [--cu-max \ \[HEVC\]](#--cu-max-int-hevc) - [--cu-min \ \[HEVC\]](#--cu-min-int-hevc) - [--alpha-bitrate-ratio \ \[HEVC\]](#--alpha-bitrate-ratio-int-hevc) + - [--alpha-channel-mode \ \[HEVC\]](#--alpha-channel-mode-string-hevc) - [--tf-level \ \[HEVC\]](#--tf-level-int-hevc) - [--part-size-min \ \[AV1\]](#--part-size-min-int-av1) - [--part-size-max \ \[AV1\]](#--part-size-max-int-av1) @@ -755,6 +756,11 @@ Set bitrate ratio for alpha channel which can be used with ```--output-csp yuva4 When the value is set to "x", then approximately "1 / (x+1)" of the bitrate will be used for alpha channel. Therefore, smaller value will result more bitrate to be spent for alpha layer. +### --alpha-channel-mode <string> [HEVC] +Set alpha channel mode. (default: straight) +- straight +- premultiplied + ### --tf-level <int> [HEVC] Set HEVC temporal filtering, requires bframes >= 4. (Default: 0) ``` diff --git a/NVEncC_Options.ja.md b/NVEncC_Options.ja.md index 07e2076f..568315e7 100644 --- a/NVEncC_Options.ja.md +++ b/NVEncC_Options.ja.md @@ -94,6 +94,7 @@ - [--cu-max \ \[HEVC\]](#--cu-max-int-hevc) - [--cu-min \ \[HEVC\]](#--cu-min-int-hevc) - [--alpha-bitrate-ratio \ \[HEVC\]](#--alpha-bitrate-ratio-int-hevc) + - [--alpha-channel-mode \ \[HEVC\]](#--alpha-channel-mode-string-hevc) - [--tf-level \ \[HEVC\]](#--tf-level-int-hevc) - [--part-size-min \ \[AV1\]](#--part-size-min-int-av1) - [--part-size-max \ \[AV1\]](#--part-size-max-int-av1) @@ -758,9 +759,14 @@ HEVCの規格では64まで存在するが、現状NVENCでは32までしかサ **画質が低下する恐れがあることがわかっているので、--cu-min / --cu-max の使用は非推奨。** ### --alpha-bitrate-ratio <int> [HEVC] -```--output-csp yuva420```でAlphaチャンネルエンコードを行う際に、Alphaチャンネルに割り当てるビットレートの割合を指定する。デフォルトは0で「自動」。 +```--output-csp yuva420```でalphaチャンネルエンコードを行う際に、alphaチャンネルに割り当てるビットレートの割合を指定する。デフォルトは0で「自動」。 -この値を"x"に設定すると、ビットレートの約 "1/(x+1)" がAlphaチャンネルに割り当てられる。つまり、値が小さいほど、Alphaチャンネルに多くのビットレートが使用される。 +この値を"x"に設定すると、ビットレートの約 "1/(x+1)" がalphaチャンネルに割り当てられる。つまり、値が小さいほど、alphaチャンネルに多くのビットレートが使用される。 + +### --alpha-channel-mode <string> [HEVC] +```--output-csp yuva420```でalphaチャンネルエンコードを行う際のalphaチャンネルのモードを指定する。(デフォルト: straight) +- straight +- premultiplied ### --tf-level <int> [HEVC] HEVC temporal filterの指定。Bフレーム数が4以上である必要がある。(デフォルト: 0) diff --git a/NVEncCore/NVEncCmd.cpp b/NVEncCore/NVEncCmd.cpp index b3e912aa..dadaccaa 100644 --- a/NVEncCore/NVEncCmd.cpp +++ b/NVEncCore/NVEncCmd.cpp @@ -270,7 +270,10 @@ tstring encoder_help() { _T(" warning: it is not recommended to use --cu-max or --cu-min,\n") _T(" leaving it auto will enhance video quality.\n") _T(" --alpha-bitrate-ratio [HEVC] set ratio for alpha bitrate.\n") - _T(" smaller value will use more bitrate for alpha.\n")); + _T(" smaller value will use more bitrate for alpha.\n") + _T(" --alpha-channel-mode [HEVC] set alpha channel mode.\n") + _T(" - straight (default)\n") + _T(" - premultiplied\n")); str += strsprintf(_T("\n") _T(" --part-size-min [AV1] min size of luma coding block partition.\n") @@ -1441,6 +1444,19 @@ int parse_one_option(const TCHAR *option_name, const TCHAR* strInput[], int& i, } return 0; } + if (IS_OPTION("alpha-channel-mode")) { + i++; + int value = 0; + if (get_list_value(list_hevc_alpha_channel_mode, strInput[i], &value)) { + pParams->alphaChannelMode = value; + } else if (1 == _stscanf_s(strInput[i], _T("%d"), &value)) { + pParams->alphaChannelMode = value; + } else { + print_cmd_error_invalid_value(option_name, strInput[i]); + return 1; + } + return 0; + } if (IS_OPTION("split-enc")) { i++; int value = 0; @@ -1824,6 +1840,7 @@ tstring gen_cmd(const InEncodeVideoParam *pParams, const NV_ENC_CODEC_CONFIG cod OPT_LST_HEVC(_T("--cu-max"), _T(""), maxCUSize, list_hevc_cu_size); OPT_LST_HEVC(_T("--cu-min"), _T(""), minCUSize, list_hevc_cu_size); OPT_NUM(_T("--alpha-bitrate-ratio"), alphaBitrateRatio); + OPT_LST(_T("--alpha-channel-mode"), alphaChannelMode, list_hevc_alpha_channel_mode); } if (pParams->codec_rgy == RGY_CODEC_H264 || save_disabled_prm) { OPT_LST_H264(_T("--level"), _T(":h264"), level, list_avc_level); diff --git a/NVEncCore/NVEncCore.cpp b/NVEncCore/NVEncCore.cpp index 037c7778..33c56a82 100644 --- a/NVEncCore/NVEncCore.cpp +++ b/NVEncCore/NVEncCore.cpp @@ -736,7 +736,8 @@ NVENCSTATUS NVEncCore::InitOutput(InEncodeVideoParam *inputParams, NV_ENC_BUFFER if (initWriters(m_pFileWriter, m_pFileWriterListAudio, m_pFileReader, m_AudioReaders, &inputParams->common, &inputParams->input, &inputParams->ctrl, outputVideoInfo, m_trimParam, m_outputTimebase, m_Chapters, m_hdrsei.get(), m_dovirpu.get(), m_encTimestamp.get(), - false, false, inputParams->alphaChannel, m_poolPkt.get(), m_poolFrame.get(), m_pStatus, m_pPerfMonitor, m_pNVLog) != RGY_ERR_NONE) { + false, false, inputParams->alphaChannel, inputParams->alphaChannelMode, + m_poolPkt.get(), m_poolFrame.get(), m_pStatus, m_pPerfMonitor, m_pNVLog) != RGY_ERR_NONE) { PrintMes(RGY_LOG_ERROR, _T("failed to initialize file reader(s).\n")); return NV_ENC_ERR_GENERIC; } diff --git a/NVEncCore/NVEncParam.cpp b/NVEncCore/NVEncParam.cpp index 51facac3..85a6dc32 100644 --- a/NVEncCore/NVEncParam.cpp +++ b/NVEncCore/NVEncParam.cpp @@ -272,6 +272,7 @@ InEncodeVideoParam::InEncodeVideoParam() : losslessIgnoreInputCsp(0), alphaChannel(false), alphaBitrateRatio(0), + alphaChannelMode(0), nWeightP(0), chromaQPOffset(0), brefMode(NV_ENC_BFRAME_REF_MODE_AUTO), diff --git a/NVEncCore/NVEncParam.h b/NVEncCore/NVEncParam.h index eea0a0ad..05df8918 100644 --- a/NVEncCore/NVEncParam.h +++ b/NVEncCore/NVEncParam.h @@ -646,6 +646,12 @@ const CX_DESC list_nvenc_caps_me_only[] = { { NULL, 0 } }; +const CX_DESC list_hevc_alpha_channel_mode[] = { + { _T("straight"), 0 }, + { _T("premultiplied"), 1 }, + { NULL, 0 } +}; + typedef struct NVEncCap { int id; //feature ID const TCHAR *name; //feature名 @@ -729,6 +735,7 @@ struct InEncodeVideoParam { int losslessIgnoreInputCsp; bool alphaChannel; int alphaBitrateRatio; + int alphaChannelMode; int nWeightP; int chromaQPOffset; int brefMode; diff --git a/NVEncCore/rgy_bitstream.cpp b/NVEncCore/rgy_bitstream.cpp index c446a9c4..e1730ad2 100644 --- a/NVEncCore/rgy_bitstream.cpp +++ b/NVEncCore/rgy_bitstream.cpp @@ -78,9 +78,8 @@ int get_hevc_sei_size(size_t& size, const uint8_t *ptr) { return ptr - orig_ptr; } -std::vector gen_hevc_alpha_channel_info_sei() { - // NVENCの作成するalpha_channel_info_seiはなんか変 - // 下記資料に基づいて、適切なものを再生成する +std::vector gen_hevc_alpha_channel_info_sei(const int mode) { + // 下記資料に基づいて生成する // https://developer.apple.com/av-foundation/HEVC-Video-with-Alpha-Interoperability-Profile.pdf std::vector header = { 0x00, 0x00, 0x00, 0x01 }; std::vector buf; @@ -89,16 +88,15 @@ std::vector gen_hevc_alpha_channel_info_sei() { add_u16(buf, u16); buf.push_back(ALPHA_CHANNEL_INFO); buf.push_back(4); // size + buf.push_back((mode & 0x07) << 4); buf.push_back(0); - buf.push_back(0); - buf.push_back(0xff); - buf.push_back(1 << 7); + buf.push_back(0x7f); + buf.push_back(0x90); to_nal(buf); std::vector nalbuf; vector_cat(nalbuf, header); vector_cat(nalbuf, buf); - nalbuf.push_back(0x80); return nalbuf; } diff --git a/NVEncCore/rgy_bitstream.h b/NVEncCore/rgy_bitstream.h index 9b45dbc4..503984ab 100644 --- a/NVEncCore/rgy_bitstream.h +++ b/NVEncCore/rgy_bitstream.h @@ -234,7 +234,7 @@ size_t get_av1_uleb_size_bytes(uint64_t value); std::vector get_av1_uleb_size_data(uint64_t value); std::vector gen_av1_obu_metadata(const uint8_t metadata_type, const std::vector& metadata); int get_hevc_sei_size(size_t& size, const uint8_t *ptr); -std::vector gen_hevc_alpha_channel_info_sei(); +std::vector gen_hevc_alpha_channel_info_sei(const int mode); struct RGYHDRMetadataPrm { int maxcll; diff --git a/NVEncCore/rgy_output.cpp b/NVEncCore/rgy_output.cpp index 18aa7d5b..9be78635 100644 --- a/NVEncCore/rgy_output.cpp +++ b/NVEncCore/rgy_output.cpp @@ -83,7 +83,8 @@ RGYOutput::RGYOutput() : m_OutType(OUT_TYPE_BITSTREAM), m_sourceHWMem(false), m_y4mHeaderWritten(false), - m_enableHEVCAlphaChannelInfoSEIFix(false), + m_enableHEVCAlphaChannelInfoSEIOverwrite(false), + m_HEVCAlphaChannelMode(0), m_strWriterName(), m_strOutputInfo(), m_VideoOutputInfo(), @@ -358,8 +359,8 @@ std::pair> RGYOutput::getMetadata(const RGYFrameDa } -RGY_ERR RGYOutput::FixHEVCAlphaChannelInfoSEI(RGYBitstream *bitstream) { - if (m_VideoOutputInfo.codec != RGY_CODEC_HEVC || !m_enableHEVCAlphaChannelInfoSEIFix) { +RGY_ERR RGYOutput::OverwriteHEVCAlphaChannelInfoSEI(RGYBitstream *bitstream) { + if (m_VideoOutputInfo.codec != RGY_CODEC_HEVC || !m_enableHEVCAlphaChannelInfoSEIOverwrite) { return RGY_ERR_NONE; } RGYBitstream bsCopy = RGYBitstreamInit(); @@ -387,7 +388,7 @@ RGY_ERR RGYOutput::FixHEVCAlphaChannelInfoSEI(RGYBitstream *bitstream) { const auto sei_data = unnal(ptr, nal.size - nal_header_size); const auto sei_type = sei_data[0]; if (sei_type == ALPHA_CHANNEL_INFO) { // alpha_channel_information - const auto nalbuf = gen_hevc_alpha_channel_info_sei(); + const auto nalbuf = gen_hevc_alpha_channel_info_sei(m_HEVCAlphaChannelMode); bitstream->append(nalbuf.data(), nalbuf.size()); } else { bitstream->append(nal.ptr, nal.size); @@ -681,8 +682,9 @@ RGY_ERR RGYOutputRaw::Init(const TCHAR *strFileName, const VideoInfo *pVideoOutp m_doviRpu = rawPrm->doviRpu; m_timestamp = rawPrm->vidTimestamp; m_debugDirectAV1Out = rawPrm->debugDirectAV1Out; - m_enableHEVCAlphaChannelInfoSEIFix = ENCODER_NVENC && rawPrm->codecId == RGY_CODEC_HEVC && rawPrm->HEVCAlphaChannel; - if (m_enableHEVCAlphaChannelInfoSEIFix) { + m_HEVCAlphaChannelMode = rawPrm->HEVCAlphaChannelMode; + m_enableHEVCAlphaChannelInfoSEIOverwrite = rawPrm->codecId == RGY_CODEC_HEVC && rawPrm->HEVCAlphaChannel; + if (m_enableHEVCAlphaChannelInfoSEIOverwrite) { AddMessage(RGY_LOG_DEBUG, _T("enableHEVCAlphaChannelInfoSEIFix : on\n")); } if (rawPrm->debugRawOut) { @@ -758,7 +760,7 @@ RGY_ERR RGYOutputRaw::WriteNextOneFrame(RGYBitstream *pBitstream) { } // NVENCのalpha_channel_info SEIの出力は変なので、適切なものに置き換える - auto err = FixHEVCAlphaChannelInfoSEI(pBitstream); + auto err = OverwriteHEVCAlphaChannelInfoSEI(pBitstream); if (err != RGY_ERR_NONE) { return err; } @@ -1125,6 +1127,7 @@ RGY_ERR initWriters( const bool videoDtsUnavailable, const bool benchmark, const bool HEVCAlphaChannel, + const int HEVCAlphaChannelMode, RGYPoolAVPacket *poolPkt, RGYPoolAVFrame *poolFrame, shared_ptr pStatus, @@ -1197,6 +1200,7 @@ RGY_ERR initWriters( writerPrm.lowlatency = ctrl->lowLatency; writerPrm.debugDirectAV1Out = common->debugDirectAV1Out; writerPrm.HEVCAlphaChannel = HEVCAlphaChannel; + writerPrm.HEVCAlphaChannelMode = HEVCAlphaChannelMode; writerPrm.muxOpt = common->muxOpt; writerPrm.poolPkt = poolPkt; writerPrm.poolFrame = poolFrame; @@ -1501,6 +1505,7 @@ RGY_ERR initWriters( rawPrm.vidTimestamp = vidTimestamp; rawPrm.debugDirectAV1Out = common->debugDirectAV1Out; rawPrm.HEVCAlphaChannel = HEVCAlphaChannel; + rawPrm.HEVCAlphaChannelMode = HEVCAlphaChannelMode; rawPrm.debugRawOut = common->debugRawOut; rawPrm.outReplayFile = common->outReplayFile; rawPrm.outReplayCodec = common->outReplayCodec; diff --git a/NVEncCore/rgy_output.h b/NVEncCore/rgy_output.h index 3471e52f..82c8b929 100644 --- a/NVEncCore/rgy_output.h +++ b/NVEncCore/rgy_output.h @@ -229,7 +229,7 @@ class RGYOutput { RGY_ERR InsertMetadata(RGYBitstream *bitstream, std::vector>& metadataList); - RGY_ERR FixHEVCAlphaChannelInfoSEI(RGYBitstream *bitstream); + RGY_ERR OverwriteHEVCAlphaChannelInfoSEI(RGYBitstream *bitstream); template std::pair> getMetadata(const RGYFrameDataType metadataType, const RGYTimestampMapVal& bs_framedata); @@ -297,7 +297,8 @@ class RGYOutput { OutputType m_OutType; bool m_sourceHWMem; bool m_y4mHeaderWritten; - bool m_enableHEVCAlphaChannelInfoSEIFix; + bool m_enableHEVCAlphaChannelInfoSEIOverwrite; + int m_HEVCAlphaChannelMode; tstring m_strWriterName; tstring m_strOutputInfo; VideoInfo m_VideoOutputInfo; @@ -314,6 +315,7 @@ struct RGYOutputRawPrm { bool debugDirectAV1Out; bool debugRawOut; bool HEVCAlphaChannel; + int HEVCAlphaChannelMode; tstring outReplayFile; RGY_CODEC outReplayCodec; int bufSizeMB; @@ -366,6 +368,7 @@ RGY_ERR initWriters( const bool videoDtsUnavailable, const bool benchmark, const bool HEVCAlphaChannel, + const int HEVCAlphaChannelMode, RGYPoolAVPacket *poolPkt, RGYPoolAVFrame *poolFrame, shared_ptr pStatus, diff --git a/NVEncCore/rgy_output_avcodec.cpp b/NVEncCore/rgy_output_avcodec.cpp index d2e400e0..7be47898 100644 --- a/NVEncCore/rgy_output_avcodec.cpp +++ b/NVEncCore/rgy_output_avcodec.cpp @@ -813,8 +813,9 @@ RGY_ERR RGYOutputAvcodec::InitVideo(const VideoInfo *videoOutputInfo, const Avco m_Mux.video.outputFps = av_make_q(videoOutputInfo->fpsN, videoOutputInfo->fpsD); AddMessage(RGY_LOG_DEBUG, _T("output video stream fps: %d/%d\n"), m_Mux.video.outputFps.num, m_Mux.video.outputFps.den); - m_enableHEVCAlphaChannelInfoSEIFix = ENCODER_NVENC && videoOutputInfo->codec == RGY_CODEC_HEVC && prm->HEVCAlphaChannel; - if (m_enableHEVCAlphaChannelInfoSEIFix) { + m_HEVCAlphaChannelMode = prm->HEVCAlphaChannelMode; + m_enableHEVCAlphaChannelInfoSEIOverwrite = videoOutputInfo->codec == RGY_CODEC_HEVC && prm->HEVCAlphaChannel; + if (m_enableHEVCAlphaChannelInfoSEIOverwrite) { AddMessage(RGY_LOG_DEBUG, _T("enableHEVCAlphaChannelInfoSEIFix : on\n")); } @@ -2405,8 +2406,8 @@ RGY_ERR RGYOutputAvcodec::AddHeaderToExtraDataHEVC(const RGYBitstream *bitstream const auto sei_type = sei_data[0]; // alpha_channel_infoもextradataに追加しておく必要がある if (sei_type == ALPHA_CHANNEL_INFO) { - if (m_enableHEVCAlphaChannelInfoSEIFix) { // NVENCのalpha_channel_info SEIの出力は変なので、適切なものを追加しておく - vector_cat(hevc_header, gen_hevc_alpha_channel_info_sei()); + if (m_enableHEVCAlphaChannelInfoSEIOverwrite) { + vector_cat(hevc_header, gen_hevc_alpha_channel_info_sei(m_HEVCAlphaChannelMode)); } else { vector_cat(hevc_header, nal.ptr, nal.size); } @@ -2768,7 +2769,7 @@ RGY_ERR RGYOutputAvcodec::WriteNextFrameInternalOneFrame(RGYBitstream *bitstream } // NVENCのalpha_channel_info SEIの出力は変なので、適切なものに置き換える - auto err = FixHEVCAlphaChannelInfoSEI(bitstream); + auto err = OverwriteHEVCAlphaChannelInfoSEI(bitstream); if (err != RGY_ERR_NONE) { return err; } diff --git a/NVEncCore/rgy_output_avcodec.h b/NVEncCore/rgy_output_avcodec.h index 33a46e84..00123aa6 100644 --- a/NVEncCore/rgy_output_avcodec.h +++ b/NVEncCore/rgy_output_avcodec.h @@ -403,6 +403,7 @@ struct AvcodecWriterPrm { bool disableMp4Opt; //mp4出力時のmuxの最適化を無効にする bool debugDirectAV1Out; //AV1出力のデバッグ用 bool HEVCAlphaChannel; //HEVCのalphaチェンネルを使用するか + int HEVCAlphaChannelMode; //HEVCのalphaチェンネルのモード RGYPoolAVPacket *poolPkt; //読み込み側からわたってきたパケットの返却先 RGYPoolAVFrame *poolFrame; //読み込み側からわたってきたパケットの返却先 @@ -443,6 +444,7 @@ struct AvcodecWriterPrm { disableMp4Opt(false), debugDirectAV1Out(false), HEVCAlphaChannel(false), + HEVCAlphaChannelMode(0), poolPkt(nullptr), poolFrame(nullptr) { }