MXVK Vulkan Framework 0.33.1
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< FfmpegOptionsoftware_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 930 of file mxwrite.cpp.

931 {
932 if (!object) {
933 return;
934 }
935 for (const AVOption *option = nullptr; (option = av_opt_next(object, option));) {
936 if (option->type == AV_OPT_TYPE_CONST ||
937 (option->flags & AV_OPT_FLAG_ENCODING_PARAM) == 0 ||
938 (option->flags & AV_OPT_FLAG_VIDEO_PARAM) == 0 ||
939 (option->flags & (AV_OPT_FLAG_READONLY | AV_OPT_FLAG_DEPRECATED)) != 0 ||
940 !option->name || !seen.insert(option->name).second) {
941 continue;
942 }
943
944 EncoderOptionInfo info;
945 info.name = option->name;
946 info.type = option_type_name(option->type);
947 info.help = option->help ? option->help : "";
948 if (option_has_numeric_range(option->type)) {
949 info.minimum = number_text(option->min);
950 info.maximum = number_text(option->max);
951 }
952
953 uint8_t *value = nullptr;
954 if (av_opt_get(object, option->name, 0, &value) >= 0 && value) {
955 info.default_value = reinterpret_cast<char *>(value);
956 }
957 av_free(value);
958
959 if (option->unit) {
960 std::vector<std::string> choices;
961 for (const AVOption *choice = nullptr; (choice = av_opt_next(object, choice));) {
962 if (choice->type == AV_OPT_TYPE_CONST && choice->unit && choice->name &&
963 std::string_view(choice->unit) == option->unit) {
964 choices.emplace_back(choice->name);
965 }
966 }
967 for (size_t index = 0; index < choices.size(); ++index) {
968 if (index > 0) {
969 info.choices += ", ";
970 }
971 info.choices += choices[index];
972 }
973 }
974 result.push_back(std::move(info));
975 }
976 }
bool option_has_numeric_range(AVOptionType type)
Definition mxwrite.cpp:912
std::string number_text(double value)
Definition mxwrite.cpp:924
std::string option_type_name(AVOptionType type)
Definition mxwrite.cpp:860
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 643 of file mxwrite.cpp.

644 {
645 for (const FfmpegOption &option : options) {
646 if (is_reserved_ffmpeg_option(option.name)) {
647 continue;
648 }
649
650 int result = AVERROR_OPTION_NOT_FOUND;
651 if (context->priv_data) {
652 result = av_opt_set(context->priv_data, option.name.c_str(), option.value.c_str(), 0);
653 }
654 if (result == AVERROR_OPTION_NOT_FOUND) {
655 result = av_opt_set(context, option.name.c_str(), option.value.c_str(), 0);
656 }
657 if (result == AVERROR_OPTION_NOT_FOUND && output_context->priv_data) {
658 result = av_opt_set(output_context->priv_data, option.name.c_str(), option.value.c_str(), 0);
659 }
660 if (result < 0) {
661 char error_text[AV_ERROR_MAX_STRING_SIZE] = {};
662 av_strerror(result, error_text, sizeof(error_text));
663 std::cerr << "MXWrite: FFmpeg option '-" << option.name << " " << option.value
664 << "' was rejected: " << error_text << ".\n";
665 return false;
666 }
667 }
668 return true;
669 }
bool is_reserved_ffmpeg_option(const std::string &name)
Definition mxwrite.cpp:638

◆ choose_software_pixel_format()

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

Definition at line 801 of file mxwrite.cpp.

802 {
803 const std::vector<AVPixelFormat> formats = supported_pixel_formats(codec);
804 auto is_usable = [](AVPixelFormat format) {
805 return !is_hardware_pixel_format(format) && sws_isSupportedOutput(format);
806 };
807
808 if (requested_format != AV_PIX_FMT_NONE) {
809 if (!is_usable(requested_format)) {
810 return AV_PIX_FMT_NONE;
811 }
812 if (formats.empty() ||
813 std::find(formats.begin(), formats.end(), requested_format) != formats.end()) {
814 return requested_format;
815 }
816 return AV_PIX_FMT_NONE;
817 }
818
819 static constexpr AVPixelFormat preferred_formats[] = {
820 AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, AV_PIX_FMT_YUV422P,
821 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE,
822 AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGBA};
823 if (formats.empty()) {
824 return AV_PIX_FMT_YUV420P;
825 }
826 for (AVPixelFormat preferred : preferred_formats) {
827 if (std::find(formats.begin(), formats.end(), preferred) != formats.end() &&
828 is_usable(preferred)) {
829 return preferred;
830 }
831 }
832 for (AVPixelFormat format : formats) {
833 if (is_usable(format)) {
834 return format;
835 }
836 }
837 return AV_PIX_FMT_NONE;
838 }
std::vector< AVPixelFormat > supported_pixel_formats(const AVCodec *codec)
Definition mxwrite.cpp:770
bool is_hardware_pixel_format(AVPixelFormat format)
Definition mxwrite.cpp:796

◆ clamp10()

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

Definition at line 55 of file mxwrite.cpp.

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

◆ codec_uses_hardware()

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

Definition at line 840 of file mxwrite.cpp.

840 {
841 if (!codec) {
842 return false;
843 }
844 if ((codec->capabilities & (AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_HYBRID)) != 0) {
845 return true;
846 }
847 for (int index = 0; avcodec_get_hw_config(codec, index); ++index) {
848 return true;
849 }
850 const std::string name = codec->name ? lowercase_ascii(codec->name) : std::string{};
851 static constexpr std::string_view hardware_markers[] = {
852 "_nvenc", "_qsv", "_vaapi", "_amf", "_v4l2m2m", "_videotoolbox",
853 "_mediafoundation", "_vulkan"};
854 return std::any_of(std::begin(hardware_markers), std::end(hardware_markers),
855 [&name](std::string_view marker) {
856 return name.find(marker) != std::string::npos;
857 });
858 }
std::string lowercase_ascii(std::string text)
Definition mxwrite.cpp:478

◆ 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 146 of file mxwrite.cpp.

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

◆ 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 67 of file mxwrite.cpp.

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

629 {
630 for (auto option = options.rbegin(); option != options.rend(); ++option) {
631 if (option->name == name) {
632 return &option->value;
633 }
634 }
635 return nullptr;
636 }

◆ is_codec_name()

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

Definition at line 578 of file mxwrite.cpp.

578 {
579 const std::string codec = lowercase_ascii(value);
580 return codec == "h265_nvenc" || codec == "h264" || codec == "h265" ||
581 codec == "hevc" || codec == "nvenc" || codec == "software" || codec == "auto" ||
582 avcodec_find_encoder_by_name(codec.c_str()) != nullptr;
583 }

◆ is_hardware_pixel_format()

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

Definition at line 796 of file mxwrite.cpp.

796 {
797 const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(format);
798 return descriptor && (descriptor->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
799 }

◆ is_nvenc_tune()

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

Definition at line 695 of file mxwrite.cpp.

695 {
696 return tune == "hq" || tune == "uhq" || tune == "ll" || tune == "ull" ||
697 tune == "lossless";
698 }

◆ is_reserved_ffmpeg_option()

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

Definition at line 638 of file mxwrite.cpp.

638 {
639 return name == "c" || name == "codec" || name == "vcodec" || name == "pix_fmt" ||
640 name == "pixel_format";
641 }

◆ is_valid_x264_preset()

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

Definition at line 468 of file mxwrite.cpp.

468 {
469 static const char *presets[] = {
470 "ultrafast", "superfast", "veryfast", "faster", "fast",
471 "medium", "slow", "slower", "veryslow", "placebo"};
472 for (const char *n : presets)
473 if (p == n)
474 return true;
475 return false;
476 }

◆ looks_like_option()

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

Definition at line 498 of file mxwrite.cpp.

498 {
499 if (token.size() < 2 || token.front() != '-') {
500 return false;
501 }
502 const unsigned char next = static_cast<unsigned char>(token[1]);
503 return !std::isdigit(next) && token[1] != '.';
504 }

◆ lowercase_ascii()

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

Definition at line 478 of file mxwrite.cpp.

478 {
479 std::transform(text.begin(), text.end(), text.begin(), [](unsigned char ch) {
480 return static_cast<char>(std::tolower(ch));
481 });
482 return text;
483 }

◆ normalize_ffmpeg_option_name()

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

Definition at line 563 of file mxwrite.cpp.

563 {
564 while (!name.empty() && name.front() == '-') {
565 name.erase(name.begin());
566 }
567
568 const size_t stream_specifier = name.find(':');
569 if (stream_specifier != std::string::npos) {
570 const std::string suffix = name.substr(stream_specifier + 1);
571 if (suffix == "v" || suffix.starts_with("v:")) {
572 name.erase(stream_specifier);
573 }
574 }
575 return name;
576 }

◆ number_text()

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

Definition at line 924 of file mxwrite.cpp.

924 {
925 std::ostringstream stream;
926 stream << std::setprecision(12) << value;
927 return stream.str();
928 }

◆ nvenc_preset_to_software()

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

Definition at line 700 of file mxwrite.cpp.

700 {
701 if (preset == "p1")
702 return "ultrafast";
703 if (preset == "p2")
704 return "superfast";
705 if (preset == "p3")
706 return "veryfast";
707 if (preset == "p4")
708 return "fast";
709 if (preset == "p5")
710 return "medium";
711 if (preset == "p6")
712 return "slow";
713 if (preset == "p7")
714 return "veryslow";
715 return preset;
716 }

◆ option_base_type()

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

Definition at line 490 of file mxwrite.cpp.

490 {
491#if LIBAVUTIL_VERSION_MAJOR >= 60
492 return static_cast<int>(type) & ~AV_OPT_TYPE_FLAG_ARRAY;
493#else
494 return static_cast<int>(type);
495#endif
496 }

◆ option_has_numeric_range()

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

Definition at line 912 of file mxwrite.cpp.

912 {
913 const int base_type = option_base_type(type);
914 return base_type == AV_OPT_TYPE_FLAGS || base_type == AV_OPT_TYPE_INT ||
915 base_type == AV_OPT_TYPE_INT64 || base_type == AV_OPT_TYPE_DOUBLE ||
916 base_type == AV_OPT_TYPE_FLOAT || base_type == AV_OPT_TYPE_UINT64 ||
917 base_type == AV_OPT_TYPE_BOOL
918#if LIBAVUTIL_VERSION_MAJOR >= 60
919 || base_type == AV_OPT_TYPE_UINT
920#endif
921 ;
922 }
int option_base_type(AVOptionType type)
Definition mxwrite.cpp:490

◆ option_type_name()

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

Definition at line 860 of file mxwrite.cpp.

860 {
861 const int base_type = option_base_type(type);
862 switch (base_type) {
863 case AV_OPT_TYPE_FLAGS:
864 return "flags";
865 case AV_OPT_TYPE_INT:
866 return "integer";
867 case AV_OPT_TYPE_INT64:
868 return "integer64";
869 case AV_OPT_TYPE_DOUBLE:
870 return "double";
871 case AV_OPT_TYPE_FLOAT:
872 return "float";
873 case AV_OPT_TYPE_STRING:
874 return "string";
875 case AV_OPT_TYPE_RATIONAL:
876 return "rational";
877 case AV_OPT_TYPE_BINARY:
878 return "binary";
879 case AV_OPT_TYPE_DICT:
880 return "dictionary";
881 case AV_OPT_TYPE_UINT64:
882 return "unsigned64";
883 case AV_OPT_TYPE_IMAGE_SIZE:
884 return "size";
885 case AV_OPT_TYPE_PIXEL_FMT:
886 return "pixel-format";
887 case AV_OPT_TYPE_SAMPLE_FMT:
888 return "sample-format";
889 case AV_OPT_TYPE_VIDEO_RATE:
890 return "frame-rate";
891 case AV_OPT_TYPE_DURATION:
892 return "duration";
893 case AV_OPT_TYPE_COLOR:
894 return "color";
895 case AV_OPT_TYPE_BOOL:
896 return "boolean";
897#if LIBAVUTIL_VERSION_MAJOR >= 57
898 case AV_OPT_TYPE_CHLAYOUT:
899#else
900 case AV_OPT_TYPE_CHANNEL_LAYOUT:
901#endif
902 return "channel-layout";
903#if LIBAVUTIL_VERSION_MAJOR >= 60
904 case AV_OPT_TYPE_UINT:
905 return "unsigned";
906#endif
907 default:
908 return "value";
909 }
910 }

◆ parse_ffmpeg_options()

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

Definition at line 585 of file mxwrite.cpp.

585 {
586 std::vector<std::string> tokens;
587 std::string error;
588 if (!tokenize_ffmpeg_options(text, tokens, error)) {
589 std::cerr << "MXWrite: invalid extra FFmpeg parameters: " << error << ".\n";
590 return false;
591 }
592
593 for (size_t index = 0; index < tokens.size(); ++index) {
594 std::string token = tokens[index];
595 if (!looks_like_option(token)) {
596 if (index == 0 && is_codec_name(token)) {
597 options.push_back({"codec", token});
598 } else {
599 std::cerr << "MXWrite: ignoring non-option extra parameter '" << token
600 << "' (filenames are selected by Writer::open).\n";
601 }
602 continue;
603 }
604
605 while (!token.empty() && token.front() == '-') {
606 token.erase(token.begin());
607 }
608 const size_t equals = token.find('=');
609 std::string name = normalize_ffmpeg_option_name(token.substr(0, equals));
610 std::string value;
611 if (equals != std::string::npos) {
612 value = token.substr(equals + 1);
613 } else if (index + 1 < tokens.size() && !looks_like_option(tokens[index + 1])) {
614 value = tokens[++index];
615 } else {
616 value = "1";
617 }
618
619 if (name.empty()) {
620 std::cerr << "MXWrite: invalid empty FFmpeg option name.\n";
621 return false;
622 }
623 options.push_back({std::move(name), std::move(value)});
624 }
625 return true;
626 }
bool looks_like_option(const std::string &token)
Definition mxwrite.cpp:498
bool is_codec_name(const std::string &value)
Definition mxwrite.cpp:578
std::string normalize_ffmpeg_option_name(std::string name)
Definition mxwrite.cpp:563
bool tokenize_ffmpeg_options(const std::string &text, std::vector< std::string > &tokens, std::string &error)
Definition mxwrite.cpp:506

◆ pqOetf()

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

Definition at line 47 of file mxwrite.cpp.

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

◆ 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 671 of file mxwrite.cpp.

671 {
672 if (!object || value.empty()) {
673 return false;
674 }
675 const AVOption *option = av_opt_find(object, name, nullptr, 0, 0);
676 if (!option) {
677 return false;
678 }
679 const int base_type = option_base_type(option->type);
680 const bool textual = base_type == AV_OPT_TYPE_STRING ||
681 base_type == AV_OPT_TYPE_DICT ||
682 base_type == AV_OPT_TYPE_BINARY;
683 const bool numeric_text = std::isdigit(static_cast<unsigned char>(value.front())) ||
684 value.front() == '-' || value.front() == '+' ||
685 value.front() == '.';
686 if (!textual && !numeric_text) {
687 const AVOption *named_value = av_opt_find(object, value.c_str(), option->unit, 0, 0);
688 if (!named_value || named_value->type != AV_OPT_TYPE_CONST) {
689 return false;
690 }
691 }
692 return av_opt_set(object, name, value.c_str(), 0) >= 0;
693 }

◆ 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 718 of file mxwrite.cpp.

719 {
720 std::vector<FfmpegOption> translated;
721 bool enable_lossless = false;
722
723 for (const FfmpegOption &option : options) {
724 FfmpegOption value = option;
725 if (value.name == "preset") {
727 } else if (value.name == "tune") {
728 const std::string tune = lowercase_ascii(value.value);
729 if (tune == "lossless") {
730 enable_lossless = true;
731 continue;
732 }
733 if (tune == "hq" || tune == "uhq") {
734 continue;
735 }
736 if (tune == "ll" || tune == "ull") {
737 value.value = "zerolatency";
738 }
739 } else if (value.name == "profile" && lowercase_ascii(value.value) == "rext") {
740 value.value = use_hevc_codec ? "main444-8" : "high444";
741 } else if (value.name == "rgb_mode" || value.name == "rc") {
742 continue;
743 } else if (value.name == "cq") {
744 value.name = "crf";
745 }
746 translated.push_back(std::move(value));
747 }
748
749 if (enable_lossless) {
750 if (use_hevc_codec) {
751 bool appended = false;
752 for (FfmpegOption &option : translated) {
753 if (option.name == "x265-params") {
754 if (!option.value.empty())
755 option.value += ':';
756 option.value += "lossless=1";
757 appended = true;
758 }
759 }
760 if (!appended) {
761 translated.push_back({"x265-params", "lossless=1"});
762 }
763 } else {
764 translated.push_back({"qp", "0"});
765 }
766 }
767 return translated;
768 }
std::string nvenc_preset_to_software(const std::string &preset)
Definition mxwrite.cpp:700

◆ 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)
44 : std::pow((v + 0.055f) / 1.055f, 2.4f);
45 }

◆ supported_pixel_formats()

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

Definition at line 770 of file mxwrite.cpp.

770 {
771 std::vector<AVPixelFormat> formats;
772 if (!codec) {
773 return formats;
774 }
775
776#if LIBAVCODEC_VERSION_MAJOR >= 61
777 const void *configurations = nullptr;
778 int configuration_count = 0;
779 if (avcodec_get_supported_config(nullptr, codec, AV_CODEC_CONFIG_PIX_FORMAT, 0,
780 &configurations, &configuration_count) >= 0 &&
781 configurations) {
782 const auto *pixel_formats = static_cast<const AVPixelFormat *>(configurations);
783 formats.assign(pixel_formats, pixel_formats + configuration_count);
784 }
785#else
786 if (codec->pix_fmts) {
787 for (const AVPixelFormat *format = codec->pix_fmts;
788 *format != AV_PIX_FMT_NONE; ++format) {
789 formats.push_back(*format);
790 }
791 }
792#endif
793 return formats;
794 }

◆ 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 506 of file mxwrite.cpp.

507 {
508 std::string token;
509 bool token_started = false;
510 bool escaped = false;
511 char quote = '\0';
512
513 for (char ch : text) {
514 if (escaped) {
515 token.push_back(ch);
516 token_started = true;
517 escaped = false;
518 continue;
519 }
520 if (ch == '\\' && quote != '\'') {
521 escaped = true;
522 token_started = true;
523 continue;
524 }
525 if (quote != '\0') {
526 if (ch == quote) {
527 quote = '\0';
528 } else {
529 token.push_back(ch);
530 }
531 token_started = true;
532 continue;
533 }
534 if (ch == '\'' || ch == '"') {
535 quote = ch;
536 token_started = true;
537 } else if (std::isspace(static_cast<unsigned char>(ch))) {
538 if (token_started) {
539 tokens.push_back(token);
540 token.clear();
541 token_started = false;
542 }
543 } else {
544 token.push_back(ch);
545 token_started = true;
546 }
547 }
548
549 if (escaped) {
550 error = "trailing escape character";
551 return false;
552 }
553 if (quote != '\0') {
554 error = "unterminated quote";
555 return false;
556 }
557 if (token_started) {
558 tokens.push_back(token);
559 }
560 return true;
561 }

◆ x264_preset_to_nvenc()

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

Definition at line 449 of file mxwrite.cpp.

449 {
450 if (p == "ultrafast")
451 return "p1";
452 if (p == "superfast")
453 return "p2";
454 if (p == "veryfast" || p == "faster")
455 return "p3";
456 if (p == "fast")
457 return "p4";
458 if (p == "medium" || p.empty())
459 return "p5";
460 if (p == "slow" || p == "slower")
461 return "p6";
462 if (p == "veryslow")
463 return "p7";
464 // Allow passing NVENC preset names through directly.
465 return p.c_str();
466 }

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.