Skip to content

Commit

Permalink
--dolby-vision-rpu使用時にレターボックス部分をcropをした場合にそれを反映させるオプションを追加。 ( #222, -…
Browse files Browse the repository at this point in the history
…-dolby-vision-rpu-prm crop )
  • Loading branch information
rigaya committed Nov 20, 2024
1 parent 4684fcd commit 8ae3895
Show file tree
Hide file tree
Showing 17 changed files with 215 additions and 64 deletions.
5 changes: 5 additions & 0 deletions QSVEnc/QSVEnc_readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ API v1.1 … Intel Media SDK v2.0


【どうでもいいメモ】
2024.11.xx (7.74)
- --dolby-vision-profileで対象外のプロファイルも読み込めていた問題を修正。
- --dolby-vision-rpu使用時にレターボックス部分をcropをした場合にそれを反映させるオプションを追加。 ( --dolby-vision-rpu-prm crop )
- --dolby-visionに関するモード制限を解除。

2024.11.12 (7.73)
- --dolby-vision-rpu copyを使用して長時間のエンコードを行うと、エンコード速度が著しく低下していくのを改善し、速度を維持し続けられるように。
- AV1出力時に--dhdr10-infoを使用した時の出力を改善。
Expand Down
16 changes: 16 additions & 0 deletions QSVEncC_Options.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
- [--dolby-vision-profile \<string\> \[HEVC, AV1\]](#--dolby-vision-profile-string-hevc-av1)
- [--dolby-vision-rpu \<string\> \[HEVC, AV1\]](#--dolby-vision-rpu-string-hevc-av1)
- [--dolby-vision-rpu copy \[HEVC, AV1\]](#--dolby-vision-rpu-copy-hevc-av1)
- [--dolby-vision-rpu-prm \<param1\>=\<value1\>\[,\<param2\>=\<value2\>\]...](#--dolby-vision-rpu-prm-param1value1param2value2)
- [--aud](#--aud)
- [--pic-struct](#--pic-struct)
- [--buf-period](#--buf-period)
Expand Down Expand Up @@ -952,6 +953,21 @@ Interleave Dolby Vision RPU metadata copied from HEVC input file. Recommended to
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-rpu-prm &lt;param1&gt;=&lt;value1&gt;[,&lt;param2&gt;=&lt;value2&gt;]...

Set parameters for ```--dolby-vision-rpu```.

- **parameters**

- crop=&lt;bool&gt;

Set active area offsets to 0 (no letterbox bars).

- Examples
```
Example: --dolby-vision-rpu-prm crop=true
```

### --aud
Insert Access Unit Delimiter NAL.

Expand Down
16 changes: 16 additions & 0 deletions QSVEncC_Options.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
- [--dolby-vision-profile \<string\> \[HEVC, AV1\]](#--dolby-vision-profile-string-hevc-av1)
- [--dolby-vision-rpu \<string\> \[HEVC, AV1\]](#--dolby-vision-rpu-string-hevc-av1)
- [--dolby-vision-rpu copy \[HEVC, AV1\]](#--dolby-vision-rpu-copy-hevc-av1)
- [--dolby-vision-rpu-prm \<param1\>=\<value1\>\[,\<param2\>=\<value2\>\]...](#--dolby-vision-rpu-prm-param1value1param2value2)
- [--aud](#--aud)
- [--pic-struct](#--pic-struct)
- [--buf-period](#--buf-period)
Expand Down Expand Up @@ -976,6 +977,21 @@ HEVCの入力ファイルから読み取ったdolby visionのmetadataを出力
avhw読み込みでは、フレームの並び替えにタイムスタンプを使用するため、タイムスタンプの取得できないraw ESのような入力ファイルでは使用できません。
こうした場合には、avsw読み込みを使用してください。

### --dolby-vision-rpu-prm &lt;param1&gt;=&lt;value1&gt;[,&lt;param2&gt;=&lt;value2&gt;]...

```--dolby-vision-rpu```用のパラメータを指定する。

- **パラメータ**

- crop=&lt;bool&gt;

RPUのactive area offsetsを0に設定する (レターボックスなしの意味)。

- 使用例
```
例: --dolby-vision-rpu-prm crop=true
```


### --aud
Access Unit Delimiter NALを挿入する。
Expand Down
2 changes: 1 addition & 1 deletion QSVPipeline/qsv_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4160,7 +4160,7 @@ RGY_ERR CQSVPipeline::CreatePipeline() {
}
}
if (m_pmfxENC) {
m_pipelineTasks.push_back(std::make_unique<PipelineTaskMFXEncode>(&m_device->mfxSession(), 1, m_pmfxENC.get(), m_mfxVer, m_encParams, m_timecode.get(), m_encTimestamp.get(), m_outputTimebase, m_dynamicRC, m_hdr10plus.get(), m_hdr10plusMetadataCopy, m_pQSVLog));
m_pipelineTasks.push_back(std::make_unique<PipelineTaskMFXEncode>(&m_device->mfxSession(), 1, m_pmfxENC.get(), m_mfxVer, m_encParams, m_timecode.get(), m_encTimestamp.get(), m_outputTimebase, m_dynamicRC, m_hdr10plus.get(), m_hdr10plusMetadataCopy || m_dovirpuMetadataCopy, m_pQSVLog));
} else {
m_pipelineTasks.push_back(std::make_unique<PipelineTaskOutputRaw>(&m_device->mfxSession(), 1, m_mfxVer, m_pQSVLog));
}
Expand Down
70 changes: 59 additions & 11 deletions QSVPipeline/rgy_bitstream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@

#include <regex>
#include "rgy_util.h"
#include "rgy_def.h"
#include "rgy_bitstream.h"
#include "rgy_memmem.h"
#include "rgy_libdovi.h"

std::vector<uint8_t> unnal(const uint8_t *ptr, size_t len) {
std::vector<uint8_t> data;
Expand Down Expand Up @@ -459,6 +461,52 @@ std::vector<uint8_t> RGYHDRMetadata::gen_obu() const {
return data;
}

int convert_dovi_rpu(std::vector<uint8_t>& data, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm) {
#if ENABLE_LIBDOVI
if (!prm) {
return 0;
}
if (data.size() == 0) {
return 0;
}
if (prm->convertProfile || prm->activeAreaOffsets.enable || prm->removeMapping) {
std::unique_ptr<DoviRpuOpaque, decltype(&dovi_rpu_free)> rpu(dovi_parse_rpu(data.data(), data.size()), dovi_rpu_free);
if (!rpu) {
return 1;
}
std::unique_ptr<const DoviRpuDataHeader, decltype(&dovi_rpu_free_header)> header(dovi_rpu_get_header(rpu.get()), dovi_rpu_free_header);
if (!header) {
return 1;
}
const auto dovi_profile = header->guessed_profile;
if (prm->convertProfile
&& dovi_profile == 7
&& (doviProfileDst == RGY_DOVI_PROFILE_81 || doviProfileDst == RGY_DOVI_PROFILE_COPY)) {
const int ret = dovi_convert_rpu_with_mode(rpu.get(), 2);
if (ret != 0) {
return 1;
}
}
if (prm->activeAreaOffsets.enable) {
dovi_rpu_set_active_area_offsets(rpu.get(),
prm->activeAreaOffsets.left, prm->activeAreaOffsets.right, prm->activeAreaOffsets.top, prm->activeAreaOffsets.bottom);
}
if (prm->removeMapping) {
dovi_rpu_remove_mapping(rpu.get());
}
std::unique_ptr<const DoviData, decltype(&dovi_data_free)> rpu_data(dovi_write_rpu(rpu.get()), dovi_data_free);
if (!rpu_data) {
return 1;
}
data.resize(rpu_data->len);
memcpy(data.data(), rpu_data->data, rpu_data->len);
}
return 0;
#else
return (prm) ? 1 : 0;
#endif // ENABLE_LIBDOVI
}

DOVIRpu::DOVIRpu() : m_find_header(get_find_header_func()), m_filepath(), m_fp(nullptr, fp_deleter()), m_buffer(), m_datasize(0), m_dataoffset(0), m_count(0), m_rpus() {};
DOVIRpu::~DOVIRpu() { m_fp.reset(); };

Expand Down Expand Up @@ -497,7 +545,7 @@ int DOVIRpu::fillBuffer() {
return bytes_read;
}

int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes) {
int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm) {
if (m_datasize <= 4) {
if (fillBuffer() == 0) {
return 1; //EOF
Expand Down Expand Up @@ -532,14 +580,14 @@ int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes) {
memcpy(bytes.data(), dataptr, next_size);
m_dataoffset += next_size;
m_datasize -= next_size;
return 0;
return convert_dovi_rpu(bytes, doviProfileDst, prm);
}

int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes, const int64_t id) {
int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id) {
bytes.clear();
for (; m_count <= id; m_count++) {
std::vector<uint8_t> rpu;
if (int ret = get_next_rpu(rpu); ret != 0) {
if (int ret = get_next_rpu(rpu, doviProfileDst, prm); ret != 0) {
return ret;
}
m_rpus[m_count] = rpu;
Expand All @@ -553,9 +601,9 @@ int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes, const int64_t id) {
return 0;
}

int DOVIRpu::get_next_rpu_nal(std::vector<uint8_t>& bytes, const int64_t id) {
int DOVIRpu::get_next_rpu_nal(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id) {
std::vector<uint8_t> rpu;
if (int ret = get_next_rpu(rpu, id); ret != 0) {
if (int ret = get_next_rpu(rpu, doviProfileDst, prm, id); ret != 0) {
return ret;
}
//to_nal(rpu); // get_next_rpuはすでにこの処理を実施済みのものを返す
Expand All @@ -573,9 +621,9 @@ int DOVIRpu::get_next_rpu_nal(std::vector<uint8_t>& bytes, const int64_t id) {
return 0;
}

int DOVIRpu::get_next_rpu_obu(std::vector<uint8_t>& bytes, const int64_t id) {
int DOVIRpu::get_next_rpu_obu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id) {
std::vector<uint8_t> tmp;
if (int ret = get_next_rpu(tmp, id); ret != 0) {
if (int ret = get_next_rpu(tmp, doviProfileDst, prm, id); ret != 0) {
return ret;
}

Expand All @@ -592,10 +640,10 @@ int DOVIRpu::get_next_rpu_obu(std::vector<uint8_t>& bytes, const int64_t id) {
return 0;
}

int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes, const int64_t id, const RGY_CODEC codec) {
int DOVIRpu::get_next_rpu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id, const RGY_CODEC codec) {
switch (codec) {
case RGY_CODEC_HEVC: return get_next_rpu_nal(bytes, id);
case RGY_CODEC_AV1: return get_next_rpu_obu(bytes, id);
case RGY_CODEC_HEVC: return get_next_rpu_nal(bytes, doviProfileDst, prm, id);
case RGY_CODEC_AV1: return get_next_rpu_obu(bytes, doviProfileDst, prm, id);
default: return 1;
}
}
Expand Down
12 changes: 7 additions & 5 deletions QSVPipeline/rgy_bitstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,22 +320,24 @@ static const uint8_t av1_itut_t35_header_dovirpu[] = {

const DOVIProfile *getDOVIProfile(const int id);

int convert_dovi_rpu(std::vector<uint8_t>& data, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm);

class DOVIRpu {
public:
static const uint8_t rpu_header[4];

DOVIRpu();
~DOVIRpu();
int init(const TCHAR *rpu_file);
int get_next_rpu_nal(std::vector<uint8_t>& bytes, const int64_t id);
int get_next_rpu_obu(std::vector<uint8_t>& bytes, const int64_t id);
int get_next_rpu(std::vector<uint8_t>& bytes, const int64_t id, const RGY_CODEC codec);
int get_next_rpu_nal(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id);
int get_next_rpu_obu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id);
int get_next_rpu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id, const RGY_CODEC codec);
const tstring& get_filepath() const;

protected:
int fillBuffer();
int get_next_rpu(std::vector<uint8_t>& bytes);
int get_next_rpu(std::vector<uint8_t>& bytes, const int64_t id);
int get_next_rpu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm);
int get_next_rpu(std::vector<uint8_t>& bytes, const RGYDOVIProfile doviProfileDst, const RGYDOVIRpuConvertParam *prm, const int64_t id);

decltype(find_header_c)* m_find_header;
tstring m_filepath;
Expand Down
48 changes: 47 additions & 1 deletion QSVPipeline/rgy_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6155,6 +6155,37 @@ int parse_one_common_option(const TCHAR *option_name, const TCHAR *strInput[], i
}
return 0;
}
if (IS_OPTION("dolby-vision-rpu-prm")) {
i++;
const auto paramList = std::vector<std::string>{ "crop" };
for (const auto &param : split(strInput[i], _T(","))) {
auto pos = param.find_first_of(_T("="));
if (pos != std::string::npos) {
auto param_arg = tolowercase(param.substr(0, pos));
auto param_val = param.substr(pos + 1);
if (param_arg == _T("crop")) {
bool b = false;
if (!cmd_string_to_bool(&b, param_val)) {
common->doviRpuParams.activeAreaOffsets.enable = b;
} else {
print_cmd_error_invalid_value(tstring(option_name) + _T(" ") + param_arg + _T("="), param_val);
return 1;
}
continue;
}
print_cmd_error_unknown_opt_param(option_name, param_arg, paramList);
return 1;
} else {
if (param == _T("crop")) {
common->doviRpuParams.activeAreaOffsets.enable = true;
continue;
}
print_cmd_error_unknown_opt_param(option_name, param, paramList);
return 1;
}
}
return 0;
}
#endif //#if ENABLE_DOVI_METADATA_OPTIONS
if (IS_OPTION("timecode")) {
common->timecode = true;
Expand Down Expand Up @@ -8200,6 +8231,16 @@ tstring gen_cmd(const RGYParamCommon *param, const RGYParamCommon *defaultPrm, b
} else {
OPT_STR_PATH(_T("--dolby-vision-rpu"), doviRpuFile);
}

if (param->doviRpuParams != defaultPrm->doviRpuParams) {
tmp.str(tstring());
if (param->doviRpuParams.activeAreaOffsets.enable) {
tmp << ",crop=on";
}
if (!tmp.str().empty()) {
cmd << _T(" --dolby-vision-rpu-prm ") << tmp.str().substr(1);
}
}
if (param->timecode || param->timecodeFile.length() > 0) {
cmd << (param->timecode ? _T("--timecode ") : _T("--no-timecode "));
if (param->timecodeFile.length() > 0) {
Expand Down Expand Up @@ -8451,7 +8492,12 @@ tstring gen_cmd_help_common() {
str += print_list_options(_T("--dolby-vision-profile <int>"), list_dovi_profile, 0);
str += strsprintf(
_T(" --dolby-vision-rpu <string> Copy dolby vision metadata from input rpu file.\n")
_T(" --dolby-vision-rpu copy Copy dolby vision metadata from input file.\n"));
_T(" --dolby-vision-rpu copy Copy dolby vision metadata from input file.\n")
_T(" --dolby-vision-rpu-prm <param1>=<value>[,<param2>=<value>][...]\n")
_T(" parameters for --dolby-vision-rpu.\n")
_T(" params\n")
_T(" crop=<bool> Set active area offsets to 0 (no letterbox bars).\n")
);
#endif //#if ENABLE_DOVI_METADATA_OPTIONS
str += strsprintf(
_T(" --input-analyze <int> set time (sec) which reader analyze input file.\n")
Expand Down
33 changes: 33 additions & 0 deletions QSVPipeline/rgy_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,39 @@ const CX_DESC list_dovi_profile_parse[] = {
{ NULL, 0 }
};

struct RGYDOVIRpuActiveAreaOffsets {
bool enable;
uint16_t left, top, right, bottom;

RGYDOVIRpuActiveAreaOffsets() : enable(false), left(0), top(0), right(0), bottom(0) {};
bool operator==(const RGYDOVIRpuActiveAreaOffsets &x) const {
return enable == x.enable
&& left == x.left
&& top == x.top
&& right == x.right
&& bottom == x.bottom;
}
bool operator!=(const RGYDOVIRpuActiveAreaOffsets &x) const {
return !(*this == x);
}
};

class RGYDOVIRpuConvertParam {
public:
bool convertProfile;
bool removeMapping;
RGYDOVIRpuActiveAreaOffsets activeAreaOffsets;
RGYDOVIRpuConvertParam() : convertProfile(true), removeMapping(false), activeAreaOffsets() {};
virtual ~RGYDOVIRpuConvertParam() {};
bool operator==(const RGYDOVIRpuConvertParam &x) const {
return convertProfile == x.convertProfile
&& removeMapping == x.removeMapping
&& activeAreaOffsets == x.activeAreaOffsets;
}
bool operator!=(const RGYDOVIRpuConvertParam &x) const {
return !(*this == x);
}
};

// 1st luma line > |X X ... |3 4 X ... X が輝度ピクセル位置
// | |1 2 1-6 are possible chroma positions
Expand Down
Loading

0 comments on commit 8ae3895

Please sign in to comment.