MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
anonymous_namespace{mxwrite.cpp} Namespace Reference

Classes

struct  FfmpegOption

Functions

void append_encoder_options (void *object, std::vector< EncoderOptionInfo > &result, std::set< std::string > &seen)
bool apply_ffmpeg_options (const std::vector< FfmpegOption > &options, AVCodecContext *context, AVFormatContext *output_context)
AVPixelFormat choose_software_pixel_format (const AVCodec *codec, AVPixelFormat requested_format)
uint16_t clamp10 (float v)
bool codec_uses_hardware (const AVCodec *codec)
void convertBt2020Rgba16EncodedToYuv420p10 (const uint16_t *rgba, int src_stride_shorts, uint16_t *y_plane, int y_stride_shorts, uint16_t *u_plane, int u_stride_shorts, uint16_t *v_plane, int v_stride_shorts, int width, int height)
void convertRgbaToBt2020PqYuv420p10 (const uint8_t *rgba, int src_stride_bytes, uint16_t *y_plane, int y_stride_shorts, uint16_t *u_plane, int u_stride_shorts, uint16_t *v_plane, int v_stride_shorts, int width, int height)
const std::string * find_ffmpeg_option (const std::vector< FfmpegOption > &options, const std::string &name)
bool is_codec_name (const std::string &value)
bool is_hardware_pixel_format (AVPixelFormat format)
bool is_nvenc_tune (const std::string &tune)
bool is_reserved_ffmpeg_option (const std::string &name)
bool is_valid_x264_preset (const std::string &p)
bool looks_like_option (const std::string &token)
std::string lowercase_ascii (std::string text)
std::string normalize_ffmpeg_option_name (std::string name)
std::string number_text (double value)
std::string nvenc_preset_to_software (const std::string &preset)
int option_base_type (AVOptionType type)
bool option_has_numeric_range (AVOptionType type)
std::string option_type_name (AVOptionType type)
bool parse_ffmpeg_options (const std::string &text, std::vector< FfmpegOption > &options)
float pqOetf (float L)
bool set_named_encoder_option (void *object, const char *name, const std::string &value)
std::vector< FfmpegOption > software_fallback_options (const std::vector< FfmpegOption > &options, bool use_hevc_codec)
float srgbEotf (float v)
std::vector< AVPixelFormat > supported_pixel_formats (const AVCodec *codec)
bool tokenize_ffmpeg_options (const std::string &text, std::vector< std::string > &tokens, std::string &error)
const char * x264_preset_to_nvenc (const std::string &p)

Variables

constexpr float kPqC1 = 3424.0f / 4096.0f
constexpr float kPqC2 = (2413.0f / 4096.0f) * 32.0f
constexpr float kPqC3 = (2392.0f / 4096.0f) * 32.0f
constexpr float kPqM1 = 2610.0f / 16384.0f
constexpr float kPqM2 = (2523.0f / 4096.0f) * 128.0f
constexpr float kSdrRefFraction = 100.0f / 10000.0f

Function Documentation

◆ append_encoder_options()

void anonymous_namespace{mxwrite.cpp}::append_encoder_options ( void * object,
std::vector< EncoderOptionInfo > & result,
std::set< std::string > & seen )

Definition at line 876 of file mxwrite.cpp.

876 {
877 if (!object) {
878 return;
879 }
880 for (const AVOption *option = nullptr; (option = av_opt_next(object, option));) {
881 if (option->type == AV_OPT_TYPE_CONST || (option->flags & AV_OPT_FLAG_ENCODING_PARAM) == 0 || (option->flags & AV_OPT_FLAG_VIDEO_PARAM) == 0 || (option->flags & (AV_OPT_FLAG_READONLY | AV_OPT_FLAG_DEPRECATED)) != 0 || !option->name || !seen.insert(option->name).second) {
882 continue;
883 }
884
885 EncoderOptionInfo info;
886 info.name = option->name;
887 info.type = option_type_name(option->type);
888 info.help = option->help ? option->help : "";
889 if (option_has_numeric_range(option->type)) {
890 info.minimum = number_text(option->min);
891 info.maximum = number_text(option->max);
892 }
893
894 uint8_t *value = nullptr;
895 if (av_opt_get(object, option->name, 0, &value) >= 0 && value) {
896 info.default_value = reinterpret_cast<char *>(value);
897 }
898 av_free(value);
899
900 if (option->unit) {
901 std::vector<std::string> choices;
902 for (const AVOption *choice = nullptr; (choice = av_opt_next(object, choice));) {
903 if (choice->type == AV_OPT_TYPE_CONST && choice->unit && choice->name && std::string_view(choice->unit) == option->unit) {
904 choices.emplace_back(choice->name);
905 }
906 }
907 for (size_t index = 0; index < choices.size(); ++index) {
908 if (index > 0) {
909 info.choices += ", ";
910 }
911 info.choices += choices[index];
912 }
913 }
914 result.push_back(std::move(info));
915 }
916 }
bool option_has_numeric_range(AVOptionType type)
Definition mxwrite.cpp:861
std::string number_text(double value)
Definition mxwrite.cpp:870
std::string option_type_name(AVOptionType type)
Definition mxwrite.cpp:809
std::string minimum
Minimum value for numeric options.
Definition mxwrite.hpp:53
std::string name
Option name accepted by EncodeOptions::ffmpeg_options.
Definition mxwrite.hpp:50
std::string help
Human-readable FFmpeg option description.
Definition mxwrite.hpp:56
std::string choices
Comma-separated named values for enum-like options.
Definition mxwrite.hpp:55
std::string type
FFmpeg option type.
Definition mxwrite.hpp:51
std::string maximum
Maximum value for numeric options.
Definition mxwrite.hpp:54
std::string default_value
Encoder default, when it can be represented as text.
Definition mxwrite.hpp:52

◆ apply_ffmpeg_options()

bool anonymous_namespace{mxwrite.cpp}::apply_ffmpeg_options ( const std::vector< FfmpegOption > & options,
AVCodecContext * context,
AVFormatContext * output_context )

Definition at line 618 of file mxwrite.cpp.

618 {
619 for (const FfmpegOption &option : options) {
620 if (is_reserved_ffmpeg_option(option.name)) {
621 continue;
622 }
623
624 int result = AVERROR_OPTION_NOT_FOUND;
625 if (context->priv_data) {
626 result = av_opt_set(context->priv_data, option.name.c_str(), option.value.c_str(), 0);
627 }
628 if (result == AVERROR_OPTION_NOT_FOUND) {
629 result = av_opt_set(context, option.name.c_str(), option.value.c_str(), 0);
630 }
631 if (result == AVERROR_OPTION_NOT_FOUND && output_context->priv_data) {
632 result = av_opt_set(output_context->priv_data, option.name.c_str(), option.value.c_str(), 0);
633 }
634 if (result < 0) {
635 char error_text[AV_ERROR_MAX_STRING_SIZE] = {};
636 av_strerror(result, error_text, sizeof(error_text));
637 std::cerr << "MXWrite: FFmpeg option '-" << option.name << " " << option.value << "' was rejected: " << error_text << ".\n";
638 return false;
639 }
640 }
641 return true;
642 }
bool is_reserved_ffmpeg_option(const std::string &name)
Definition mxwrite.cpp:616

◆ choose_software_pixel_format()

AVPixelFormat anonymous_namespace{mxwrite.cpp}::choose_software_pixel_format ( const AVCodec * codec,
AVPixelFormat requested_format )

Definition at line 763 of file mxwrite.cpp.

763 {
764 const std::vector<AVPixelFormat> formats = supported_pixel_formats(codec);
765 auto is_usable = [](AVPixelFormat format) { return !is_hardware_pixel_format(format) && sws_isSupportedOutput(format); };
766
767 if (requested_format != AV_PIX_FMT_NONE) {
768 if (!is_usable(requested_format)) {
769 return AV_PIX_FMT_NONE;
770 }
771 if (formats.empty() || std::find(formats.begin(), formats.end(), requested_format) != formats.end()) {
772 return requested_format;
773 }
774 return AV_PIX_FMT_NONE;
775 }
776
777 static constexpr AVPixelFormat preferred_formats[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGBA};
778 if (formats.empty()) {
779 return AV_PIX_FMT_YUV420P;
780 }
781 for (AVPixelFormat preferred : preferred_formats) {
782 if (std::find(formats.begin(), formats.end(), preferred) != formats.end() && is_usable(preferred)) {
783 return preferred;
784 }
785 }
786 for (AVPixelFormat format : formats) {
787 if (is_usable(format)) {
788 return format;
789 }
790 }
791 return AV_PIX_FMT_NONE;
792 }
std::vector< AVPixelFormat > supported_pixel_formats(const AVCodec *codec)
Definition mxwrite.cpp:735
bool is_hardware_pixel_format(AVPixelFormat format)
Definition mxwrite.cpp:758

◆ clamp10()

uint16_t anonymous_namespace{mxwrite.cpp}::clamp10 ( float v)
inline

Definition at line 54 of file mxwrite.cpp.

54 {
55 if (v < 0.0f)
56 v = 0.0f;
57 if (v > 1023.0f)
58 v = 1023.0f;
59 return static_cast<uint16_t>(v + 0.5f);
60 }

◆ codec_uses_hardware()

bool anonymous_namespace{mxwrite.cpp}::codec_uses_hardware ( const AVCodec * codec)

Definition at line 794 of file mxwrite.cpp.

794 {
795 if (!codec) {
796 return false;
797 }
798 if ((codec->capabilities & (AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_HYBRID)) != 0) {
799 return true;
800 }
801 for (int index = 0; avcodec_get_hw_config(codec, index); ++index) {
802 return true;
803 }
804 const std::string name = codec->name ? lowercase_ascii(codec->name) : std::string{};
805 static constexpr std::string_view hardware_markers[] = {"_nvenc", "_qsv", "_vaapi", "_amf", "_v4l2m2m", "_videotoolbox", "_mediafoundation", "_vulkan"};
806 return std::any_of(std::begin(hardware_markers), std::end(hardware_markers), [&name](std::string_view marker) { return name.find(marker) != std::string::npos; });
807 }
std::string lowercase_ascii(std::string text)
Definition mxwrite.cpp:463

◆ convertBt2020Rgba16EncodedToYuv420p10()

void anonymous_namespace{mxwrite.cpp}::convertBt2020Rgba16EncodedToYuv420p10 ( const uint16_t * rgba,
int src_stride_shorts,
uint16_t * y_plane,
int y_stride_shorts,
uint16_t * u_plane,
int u_stride_shorts,
uint16_t * v_plane,
int v_stride_shorts,
int width,
int height )

Definition at line 139 of file mxwrite.cpp.

139 {
140 constexpr float kKr = 0.2627f;
141 constexpr float kKg = 0.6780f;
142 constexpr float kKb = 0.0593f;
143 constexpr float kPbDiv = 1.0f / 1.8814f;
144 constexpr float kPrDiv = 1.0f / 1.4746f;
145 constexpr float kInv65535 = 1.0f / 65535.0f;
146
147 for (int y = 0; y < height; y += 2) {
148 const int y1 = std::min(y + 1, height - 1);
149 const uint16_t *row0 = rgba + y * src_stride_shorts;
150 const uint16_t *row1 = rgba + y1 * src_stride_shorts;
151 uint16_t *yr0 = y_plane + y * y_stride_shorts;
152 uint16_t *yr1 = y_plane + y1 * y_stride_shorts;
153 uint16_t *ur = u_plane + (y / 2) * u_stride_shorts;
154 uint16_t *vr = v_plane + (y / 2) * v_stride_shorts;
155
156 for (int x = 0; x < width; x += 2) {
157 const int x1 = std::min(x + 1, width - 1);
158
159 auto load = [&](const uint16_t *px, float &Y, float &U, float &V) {
160 const float rp = px[0] * kInv65535;
161 const float gp = px[1] * kInv65535;
162 const float bp = px[2] * kInv65535;
163 Y = kKr * rp + kKg * gp + kKb * bp;
164 U = (bp - Y) * kPbDiv;
165 V = (rp - Y) * kPrDiv;
166 };
167
168 float Y00, U00, V00;
169 float Y01, U01, V01;
170 float Y10, U10, V10;
171 float Y11, U11, V11;
172 load(row0 + x * 4, Y00, U00, V00);
173 load(row0 + x1 * 4, Y01, U01, V01);
174 load(row1 + x * 4, Y10, U10, V10);
175 load(row1 + x1 * 4, Y11, U11, V11);
176
177 yr0[x] = clamp10(Y00 * 876.0f + 64.0f);
178 yr0[x1] = clamp10(Y01 * 876.0f + 64.0f);
179 yr1[x] = clamp10(Y10 * 876.0f + 64.0f);
180 yr1[x1] = clamp10(Y11 * 876.0f + 64.0f);
181
182 const float Uavg = 0.25f * (U00 + U01 + U10 + U11);
183 const float Vavg = 0.25f * (V00 + V01 + V10 + V11);
184 ur[x / 2] = clamp10(Uavg * 896.0f + 512.0f);
185 vr[x / 2] = clamp10(Vavg * 896.0f + 512.0f);
186 }
187 }
188 }

◆ convertRgbaToBt2020PqYuv420p10()

void anonymous_namespace{mxwrite.cpp}::convertRgbaToBt2020PqYuv420p10 ( const uint8_t * rgba,
int src_stride_bytes,
uint16_t * y_plane,
int y_stride_shorts,
uint16_t * u_plane,
int u_stride_shorts,
uint16_t * v_plane,
int v_stride_shorts,
int width,
int height )

Definition at line 66 of file mxwrite.cpp.

66 {
67 // BT.2020 non-constant luminance RGB->YUV (limited range).
68 // E'Y = 0.2627*R + 0.6780*G + 0.0593*B
69 // E'Pb = (B - Y) / 1.8814
70 // E'Pr = (R - Y) / 1.4746
71 // Limited 10-bit: Y: 0..1 -> 64..940 (range 876), UV: -0.5..0.5 -> 64..960 (range 896, center 512).
72 constexpr float kKr = 0.2627f;
73 constexpr float kKg = 0.6780f;
74 constexpr float kKb = 0.0593f;
75 constexpr float kPbDiv = 1.0f / 1.8814f;
76 constexpr float kPrDiv = 1.0f / 1.4746f;
77
78 for (int y = 0; y < height; y += 2) {
79 const int y1 = std::min(y + 1, height - 1);
80 const uint8_t *row0 = rgba + y * src_stride_bytes;
81 const uint8_t *row1 = rgba + y1 * src_stride_bytes;
82 uint16_t *yr0 = y_plane + y * y_stride_shorts;
83 uint16_t *yr1 = y_plane + y1 * y_stride_shorts;
84 uint16_t *ur = u_plane + (y / 2) * u_stride_shorts;
85 uint16_t *vr = v_plane + (y / 2) * v_stride_shorts;
86
87 for (int x = 0; x < width; x += 2) {
88 const int x1 = std::min(x + 1, width - 1);
89
90 // Load 2x2 block of sRGB 8-bit pixels.
91 auto loadPq = [](const uint8_t *px, float &Y, float &U, float &V) {
92 // sRGB 8-bit -> linear [0,1]
93 const float r = srgbEotf(px[0] * (1.0f / 255.0f));
94 const float g = srgbEotf(px[1] * (1.0f / 255.0f));
95 const float b = srgbEotf(px[2] * (1.0f / 255.0f));
96 // Scale SDR linear [0,1] (reference 100 nits) to PQ fractional.
97 const float rL = r * kSdrRefFraction;
98 const float gL = g * kSdrRefFraction;
99 const float bL = b * kSdrRefFraction;
100 // PQ encode per channel (RGB PQ).
101 const float rp = pqOetf(rL);
102 const float gp = pqOetf(gL);
103 const float bp = pqOetf(bL);
104 // BT.2020 RGB' -> YUV'.
105 Y = kKr * rp + kKg * gp + kKb * bp;
106 U = (bp - Y) * kPbDiv;
107 V = (rp - Y) * kPrDiv;
108 };
109
110 float Y00, U00, V00;
111 float Y01, U01, V01;
112 float Y10, U10, V10;
113 float Y11, U11, V11;
114 loadPq(row0 + x * 4, Y00, U00, V00);
115 loadPq(row0 + x1 * 4, Y01, U01, V01);
116 loadPq(row1 + x * 4, Y10, U10, V10);
117 loadPq(row1 + x1 * 4, Y11, U11, V11);
118
119 // Y: per-pixel, limited-range 10-bit.
120 yr0[x] = clamp10(Y00 * 876.0f + 64.0f);
121 yr0[x1] = clamp10(Y01 * 876.0f + 64.0f);
122 yr1[x] = clamp10(Y10 * 876.0f + 64.0f);
123 yr1[x1] = clamp10(Y11 * 876.0f + 64.0f);
124
125 // UV: 4:2:0 average of 2x2 block.
126 const float Uavg = 0.25f * (U00 + U01 + U10 + U11);
127 const float Vavg = 0.25f * (V00 + V01 + V10 + V11);
128 ur[x / 2] = clamp10(Uavg * 896.0f + 512.0f);
129 vr[x / 2] = clamp10(Vavg * 896.0f + 512.0f);
130 }
131 }
132 }
constexpr float kSdrRefFraction
Definition mxwrite.cpp:39

◆ find_ffmpeg_option()

const std::string * anonymous_namespace{mxwrite.cpp}::find_ffmpeg_option ( const std::vector< FfmpegOption > & options,
const std::string & name )

Definition at line 607 of file mxwrite.cpp.

607 {
608 for (auto option = options.rbegin(); option != options.rend(); ++option) {
609 if (option->name == name) {
610 return &option->value;
611 }
612 }
613 return nullptr;
614 }

◆ is_codec_name()

bool anonymous_namespace{mxwrite.cpp}::is_codec_name ( const std::string & value)

Definition at line 560 of file mxwrite.cpp.

560 {
561 const std::string codec = lowercase_ascii(value);
562 return codec == "h265_nvenc" || codec == "h264" || codec == "h265" || codec == "hevc" || codec == "nvenc" || codec == "software" || codec == "auto" || avcodec_find_encoder_by_name(codec.c_str()) != nullptr;
563 }

◆ is_hardware_pixel_format()

bool anonymous_namespace{mxwrite.cpp}::is_hardware_pixel_format ( AVPixelFormat format)

Definition at line 758 of file mxwrite.cpp.

758 {
759 const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(format);
760 return descriptor && (descriptor->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
761 }

◆ is_nvenc_tune()

bool anonymous_namespace{mxwrite.cpp}::is_nvenc_tune ( const std::string & tune)

Definition at line 664 of file mxwrite.cpp.

664{ return tune == "hq" || tune == "uhq" || tune == "ll" || tune == "ull" || tune == "lossless"; }

◆ is_reserved_ffmpeg_option()

bool anonymous_namespace{mxwrite.cpp}::is_reserved_ffmpeg_option ( const std::string & name)

Definition at line 616 of file mxwrite.cpp.

616{ return name == "c" || name == "codec" || name == "vcodec" || name == "pix_fmt" || name == "pixel_format"; }

◆ is_valid_x264_preset()

bool anonymous_namespace{mxwrite.cpp}::is_valid_x264_preset ( const std::string & p)

Definition at line 455 of file mxwrite.cpp.

455 {
456 static const char *presets[] = {"ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo"};
457 for (const char *n : presets)
458 if (p == n)
459 return true;
460 return false;
461 }

◆ looks_like_option()

bool anonymous_namespace{mxwrite.cpp}::looks_like_option ( const std::string & token)

Definition at line 481 of file mxwrite.cpp.

481 {
482 if (token.size() < 2 || token.front() != '-') {
483 return false;
484 }
485 const unsigned char next = static_cast<unsigned char>(token[1]);
486 return !std::isdigit(next) && token[1] != '.';
487 }

◆ lowercase_ascii()

std::string anonymous_namespace{mxwrite.cpp}::lowercase_ascii ( std::string text)

Definition at line 463 of file mxwrite.cpp.

463 {
464 std::transform(text.begin(), text.end(), text.begin(), [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
465 return text;
466 }

◆ normalize_ffmpeg_option_name()

std::string anonymous_namespace{mxwrite.cpp}::normalize_ffmpeg_option_name ( std::string name)

Definition at line 545 of file mxwrite.cpp.

545 {
546 while (!name.empty() && name.front() == '-') {
547 name.erase(name.begin());
548 }
549
550 const size_t stream_specifier = name.find(':');
551 if (stream_specifier != std::string::npos) {
552 const std::string suffix = name.substr(stream_specifier + 1);
553 if (suffix == "v" || suffix.starts_with("v:")) {
554 name.erase(stream_specifier);
555 }
556 }
557 return name;
558 }

◆ number_text()

std::string anonymous_namespace{mxwrite.cpp}::number_text ( double value)

Definition at line 870 of file mxwrite.cpp.

870 {
871 std::ostringstream stream;
872 stream << std::setprecision(12) << value;
873 return stream.str();
874 }

◆ nvenc_preset_to_software()

std::string anonymous_namespace{mxwrite.cpp}::nvenc_preset_to_software ( const std::string & preset)

Definition at line 666 of file mxwrite.cpp.

666 {
667 if (preset == "p1")
668 return "ultrafast";
669 if (preset == "p2")
670 return "superfast";
671 if (preset == "p3")
672 return "veryfast";
673 if (preset == "p4")
674 return "fast";
675 if (preset == "p5")
676 return "medium";
677 if (preset == "p6")
678 return "slow";
679 if (preset == "p7")
680 return "veryslow";
681 return preset;
682 }

◆ option_base_type()

int anonymous_namespace{mxwrite.cpp}::option_base_type ( AVOptionType type)

Definition at line 473 of file mxwrite.cpp.

473 {
474#if LIBAVUTIL_VERSION_MAJOR >= 60
475 return static_cast<int>(type) & ~AV_OPT_TYPE_FLAG_ARRAY;
476#else
477 return static_cast<int>(type);
478#endif
479 }

◆ option_has_numeric_range()

bool anonymous_namespace{mxwrite.cpp}::option_has_numeric_range ( AVOptionType type)

Definition at line 861 of file mxwrite.cpp.

861 {
862 const int base_type = option_base_type(type);
863 return base_type == AV_OPT_TYPE_FLAGS || base_type == AV_OPT_TYPE_INT || base_type == AV_OPT_TYPE_INT64 || base_type == AV_OPT_TYPE_DOUBLE || base_type == AV_OPT_TYPE_FLOAT || base_type == AV_OPT_TYPE_UINT64 || base_type == AV_OPT_TYPE_BOOL
864#if LIBAVUTIL_VERSION_MAJOR >= 60
865 || base_type == AV_OPT_TYPE_UINT
866#endif
867 ;
868 }
int option_base_type(AVOptionType type)
Definition mxwrite.cpp:473

◆ option_type_name()

std::string anonymous_namespace{mxwrite.cpp}::option_type_name ( AVOptionType type)

Definition at line 809 of file mxwrite.cpp.

809 {
810 const int base_type = option_base_type(type);
811 switch (base_type) {
812 case AV_OPT_TYPE_FLAGS:
813 return "flags";
814 case AV_OPT_TYPE_INT:
815 return "integer";
816 case AV_OPT_TYPE_INT64:
817 return "integer64";
818 case AV_OPT_TYPE_DOUBLE:
819 return "double";
820 case AV_OPT_TYPE_FLOAT:
821 return "float";
822 case AV_OPT_TYPE_STRING:
823 return "string";
824 case AV_OPT_TYPE_RATIONAL:
825 return "rational";
826 case AV_OPT_TYPE_BINARY:
827 return "binary";
828 case AV_OPT_TYPE_DICT:
829 return "dictionary";
830 case AV_OPT_TYPE_UINT64:
831 return "unsigned64";
832 case AV_OPT_TYPE_IMAGE_SIZE:
833 return "size";
834 case AV_OPT_TYPE_PIXEL_FMT:
835 return "pixel-format";
836 case AV_OPT_TYPE_SAMPLE_FMT:
837 return "sample-format";
838 case AV_OPT_TYPE_VIDEO_RATE:
839 return "frame-rate";
840 case AV_OPT_TYPE_DURATION:
841 return "duration";
842 case AV_OPT_TYPE_COLOR:
843 return "color";
844 case AV_OPT_TYPE_BOOL:
845 return "boolean";
846#if LIBAVUTIL_VERSION_MAJOR >= 57
847 case AV_OPT_TYPE_CHLAYOUT:
848#else
849 case AV_OPT_TYPE_CHANNEL_LAYOUT:
850#endif
851 return "channel-layout";
852#if LIBAVUTIL_VERSION_MAJOR >= 60
853 case AV_OPT_TYPE_UINT:
854 return "unsigned";
855#endif
856 default:
857 return "value";
858 }
859 }

◆ parse_ffmpeg_options()

bool anonymous_namespace{mxwrite.cpp}::parse_ffmpeg_options ( const std::string & text,
std::vector< FfmpegOption > & options )

Definition at line 565 of file mxwrite.cpp.

565 {
566 std::vector<std::string> tokens;
567 std::string error;
568 if (!tokenize_ffmpeg_options(text, tokens, error)) {
569 std::cerr << "MXWrite: invalid extra FFmpeg parameters: " << error << ".\n";
570 return false;
571 }
572
573 for (size_t index = 0; index < tokens.size(); ++index) {
574 std::string token = tokens[index];
575 if (!looks_like_option(token)) {
576 if (index == 0 && is_codec_name(token)) {
577 options.push_back({"codec", token});
578 } else {
579 std::cerr << "MXWrite: ignoring non-option extra parameter '" << token << "' (filenames are selected by Writer::open).\n";
580 }
581 continue;
582 }
583
584 while (!token.empty() && token.front() == '-') {
585 token.erase(token.begin());
586 }
587 const size_t equals = token.find('=');
588 std::string name = normalize_ffmpeg_option_name(token.substr(0, equals));
589 std::string value;
590 if (equals != std::string::npos) {
591 value = token.substr(equals + 1);
592 } else if (index + 1 < tokens.size() && !looks_like_option(tokens[index + 1])) {
593 value = tokens[++index];
594 } else {
595 value = "1";
596 }
597
598 if (name.empty()) {
599 std::cerr << "MXWrite: invalid empty FFmpeg option name.\n";
600 return false;
601 }
602 options.push_back({std::move(name), std::move(value)});
603 }
604 return true;
605 }
bool looks_like_option(const std::string &token)
Definition mxwrite.cpp:481
bool is_codec_name(const std::string &value)
Definition mxwrite.cpp:560
std::string normalize_ffmpeg_option_name(std::string name)
Definition mxwrite.cpp:545
bool tokenize_ffmpeg_options(const std::string &text, std::vector< std::string > &tokens, std::string &error)
Definition mxwrite.cpp:489

◆ pqOetf()

float anonymous_namespace{mxwrite.cpp}::pqOetf ( float L)
inline

Definition at line 46 of file mxwrite.cpp.

46 {
47 // L in [0,1] where 1.0 == 10000 nits; returns PQ code value in [0,1].
48 const float Lm = std::pow(std::max(0.0f, L), kPqM1);
49 const float num = kPqC1 + kPqC2 * Lm;
50 const float den = 1.0f + kPqC3 * Lm;
51 return std::pow(num / den, kPqM2);
52 }

◆ set_named_encoder_option()

bool anonymous_namespace{mxwrite.cpp}::set_named_encoder_option ( void * object,
const char * name,
const std::string & value )

Definition at line 644 of file mxwrite.cpp.

644 {
645 if (!object || value.empty()) {
646 return false;
647 }
648 const AVOption *option = av_opt_find(object, name, nullptr, 0, 0);
649 if (!option) {
650 return false;
651 }
652 const int base_type = option_base_type(option->type);
653 const bool textual = base_type == AV_OPT_TYPE_STRING || base_type == AV_OPT_TYPE_DICT || base_type == AV_OPT_TYPE_BINARY;
654 const bool numeric_text = std::isdigit(static_cast<unsigned char>(value.front())) || value.front() == '-' || value.front() == '+' || value.front() == '.';
655 if (!textual && !numeric_text) {
656 const AVOption *named_value = av_opt_find(object, value.c_str(), option->unit, 0, 0);
657 if (!named_value || named_value->type != AV_OPT_TYPE_CONST) {
658 return false;
659 }
660 }
661 return av_opt_set(object, name, value.c_str(), 0) >= 0;
662 }

◆ software_fallback_options()

std::vector< FfmpegOption > anonymous_namespace{mxwrite.cpp}::software_fallback_options ( const std::vector< FfmpegOption > & options,
bool use_hevc_codec )

Definition at line 684 of file mxwrite.cpp.

684 {
685 std::vector<FfmpegOption> translated;
686 bool enable_lossless = false;
687
688 for (const FfmpegOption &option : options) {
689 FfmpegOption value = option;
690 if (value.name == "preset") {
692 } else if (value.name == "tune") {
693 const std::string tune = lowercase_ascii(value.value);
694 if (tune == "lossless") {
695 enable_lossless = true;
696 continue;
697 }
698 if (tune == "hq" || tune == "uhq") {
699 continue;
700 }
701 if (tune == "ll" || tune == "ull") {
702 value.value = "zerolatency";
703 }
704 } else if (value.name == "profile" && lowercase_ascii(value.value) == "rext") {
705 value.value = use_hevc_codec ? "main444-8" : "high444";
706 } else if (value.name == "rgb_mode" || value.name == "rc") {
707 continue;
708 } else if (value.name == "cq") {
709 value.name = "crf";
710 }
711 translated.push_back(std::move(value));
712 }
713
714 if (enable_lossless) {
715 if (use_hevc_codec) {
716 bool appended = false;
717 for (FfmpegOption &option : translated) {
718 if (option.name == "x265-params") {
719 if (!option.value.empty())
720 option.value += ':';
721 option.value += "lossless=1";
722 appended = true;
723 }
724 }
725 if (!appended) {
726 translated.push_back({"x265-params", "lossless=1"});
727 }
728 } else {
729 translated.push_back({"qp", "0"});
730 }
731 }
732 return translated;
733 }
std::string nvenc_preset_to_software(const std::string &preset)
Definition mxwrite.cpp:666

◆ srgbEotf()

float anonymous_namespace{mxwrite.cpp}::srgbEotf ( float v)
inline

Definition at line 41 of file mxwrite.cpp.

41 {
42 // sRGB non-linear -> linear light.
43 return (v <= 0.04045f) ? (v / 12.92f) : std::pow((v + 0.055f) / 1.055f, 2.4f);
44 }

◆ supported_pixel_formats()

std::vector< AVPixelFormat > anonymous_namespace{mxwrite.cpp}::supported_pixel_formats ( const AVCodec * codec)

Definition at line 735 of file mxwrite.cpp.

735 {
736 std::vector<AVPixelFormat> formats;
737 if (!codec) {
738 return formats;
739 }
740
741#if LIBAVCODEC_VERSION_MAJOR >= 61
742 const void *configurations = nullptr;
743 int configuration_count = 0;
744 if (avcodec_get_supported_config(nullptr, codec, AV_CODEC_CONFIG_PIX_FORMAT, 0, &configurations, &configuration_count) >= 0 && configurations) {
745 const auto *pixel_formats = static_cast<const AVPixelFormat *>(configurations);
746 formats.assign(pixel_formats, pixel_formats + configuration_count);
747 }
748#else
749 if (codec->pix_fmts) {
750 for (const AVPixelFormat *format = codec->pix_fmts; *format != AV_PIX_FMT_NONE; ++format) {
751 formats.push_back(*format);
752 }
753 }
754#endif
755 return formats;
756 }

◆ tokenize_ffmpeg_options()

bool anonymous_namespace{mxwrite.cpp}::tokenize_ffmpeg_options ( const std::string & text,
std::vector< std::string > & tokens,
std::string & error )

Definition at line 489 of file mxwrite.cpp.

489 {
490 std::string token;
491 bool token_started = false;
492 bool escaped = false;
493 char quote = '\0';
494
495 for (char ch : text) {
496 if (escaped) {
497 token.push_back(ch);
498 token_started = true;
499 escaped = false;
500 continue;
501 }
502 if (ch == '\\' && quote != '\'') {
503 escaped = true;
504 token_started = true;
505 continue;
506 }
507 if (quote != '\0') {
508 if (ch == quote) {
509 quote = '\0';
510 } else {
511 token.push_back(ch);
512 }
513 token_started = true;
514 continue;
515 }
516 if (ch == '\'' || ch == '"') {
517 quote = ch;
518 token_started = true;
519 } else if (std::isspace(static_cast<unsigned char>(ch))) {
520 if (token_started) {
521 tokens.push_back(token);
522 token.clear();
523 token_started = false;
524 }
525 } else {
526 token.push_back(ch);
527 token_started = true;
528 }
529 }
530
531 if (escaped) {
532 error = "trailing escape character";
533 return false;
534 }
535 if (quote != '\0') {
536 error = "unterminated quote";
537 return false;
538 }
539 if (token_started) {
540 tokens.push_back(token);
541 }
542 return true;
543 }

◆ x264_preset_to_nvenc()

const char * anonymous_namespace{mxwrite.cpp}::x264_preset_to_nvenc ( const std::string & p)

Definition at line 436 of file mxwrite.cpp.

436 {
437 if (p == "ultrafast")
438 return "p1";
439 if (p == "superfast")
440 return "p2";
441 if (p == "veryfast" || p == "faster")
442 return "p3";
443 if (p == "fast")
444 return "p4";
445 if (p == "medium" || p.empty())
446 return "p5";
447 if (p == "slow" || p == "slower")
448 return "p6";
449 if (p == "veryslow")
450 return "p7";
451 // Allow passing NVENC preset names through directly.
452 return p.c_str();
453 }

Variable Documentation

◆ kPqC1

float anonymous_namespace{mxwrite.cpp}::kPqC1 = 3424.0f / 4096.0f
constexpr

Definition at line 35 of file mxwrite.cpp.

◆ kPqC2

float anonymous_namespace{mxwrite.cpp}::kPqC2 = (2413.0f / 4096.0f) * 32.0f
constexpr

Definition at line 36 of file mxwrite.cpp.

◆ kPqC3

float anonymous_namespace{mxwrite.cpp}::kPqC3 = (2392.0f / 4096.0f) * 32.0f
constexpr

Definition at line 37 of file mxwrite.cpp.

◆ kPqM1

float anonymous_namespace{mxwrite.cpp}::kPqM1 = 2610.0f / 16384.0f
constexpr

Definition at line 33 of file mxwrite.cpp.

◆ kPqM2

float anonymous_namespace{mxwrite.cpp}::kPqM2 = (2523.0f / 4096.0f) * 128.0f
constexpr

Definition at line 34 of file mxwrite.cpp.

◆ kSdrRefFraction

float anonymous_namespace{mxwrite.cpp}::kSdrRefFraction = 100.0f / 10000.0f
constexpr

Definition at line 39 of file mxwrite.cpp.