38#define __STDC_CONSTANT_MACROS
80#include <libavutil/hwcontext.h>
81#include <libavutil/hwcontext_vaapi.h>
88#include <libswscale/swscale.h>
92#define MOD_NAME "[lavc] "
99using std::invalid_argument;
104using std::shared_ptr;
110using namespace std::string_literals;
113#define DEFAULT_X26X_RC_BUF_SIZE_FACTOR 2.5
114#define DEFAULT_NVENC_RC_BUF_SIZE_FACTOR 1.5
118 FLW_THRESH = 1920 * 1080 * 30,
119 FLW_UHD_60 = 3840 * 2160 * 60,
120 HOUSEKEEP_INTERVAL = 100,
124constexpr const int DEFAULT_GOP_SIZE = 20;
125constexpr int DEFAULT_SLICE_COUNT = 32;
127constexpr const char *DEFAULT_AMF_RC =
"cqp";
128constexpr const char *DEFAULT_AMF_USAGE =
"ultralowlatency";
129constexpr const char *DEFAULT_AMF_USAGE_AV1 =
"lowlatency";
130constexpr int DEFAULT_CQP = 21;
131constexpr int DEFAULT_CQP_MPJEG = 7;
132constexpr int DEFAULT_CQP_MJPEG_QSV = 80;
133constexpr int DEFAULT_CQP_QSV = 5000;
134constexpr const char *DEFAULT_NVENC_PRESET =
"p4";
135constexpr const char *DEFAULT_NVENC_RC =
"cbr";
136constexpr const char *DEFAULT_NVENC_TUNE =
"ull";
137constexpr const char *DEFAULT_QSV_PRESET =
"medium";
138constexpr const char *DEFAULT_QSV_RC =
"vbr";
139constexpr const char *FALLBACK_NVENC_PRESET =
"llhq";
142get_default_crf(
const char *codec_name)
144 if (strstr(codec_name,
"libx26") == codec_name) {
147 if (strcmp(codec_name,
"libsvtav1") == 0) {
153struct setparam_param {
154 setparam_param(map<string, string> &lo, set<string> &bo) : lavc_opts(lo), blacklist_opts(bo) {}
156 bool have_preset =
false;
157 int periodic_intra = -1;
158 int interlaced_dct = -1;
159 int header_inserter_req = -1;
162 map<string, string> &lavc_opts;
163 set<string> &blacklist_opts;
164 long long int requested_bitrate = 0;
165 double requested_bpp = 0;
166 double requested_crf = -1;
167 int requested_cqp = -1;
171 function<
const char*(bool)> get_prefered_encoder;
173 void (*set_param)(AVCodecContext *,
struct setparam_param *);
174 int capabilities_priority;
177static void libavcodec_check_messages(
struct state_video_compress_libav *s);
178static void libavcodec_compress_done(
struct module *mod);
179static void setparam_default(AVCodecContext *,
struct setparam_param *);
180static void setparam_h264_h265_av1(AVCodecContext *,
struct setparam_param *);
181static void setparam_jpeg(AVCodecContext *,
struct setparam_param *);
182static void setparam_vp8_vp9(AVCodecContext *,
struct setparam_param *);
183static void set_codec_thread_mode(AVCodecContext *codec_ctx,
struct setparam_param *
param);
185static void print_codec_aux_usage(
string const &
name);
186static bool show_coder_help(
string const &
name,
bool encoder =
true);
187static void print_codec_supp_pix_fmts(
const enum AVPixelFormat *
first);
188void usage(
bool full);
189static void cleanup(
struct state_video_compress_libav *s);
191static map<codec_t, codec_params_t> codec_params = {
192 {
H264, codec_params_t{
193 [](
bool is_rgb) {
return is_rgb ?
"libx264rgb" :
"libx264"; },
197 setparam_h264_h265_av1,
200 {
H265, codec_params_t{
201 [](bool) {
return "libx265"; },
203 setparam_h264_h265_av1,
206 {
MJPG, codec_params_t{
212 {
J2K, codec_params_t{
218 {
VP8, codec_params_t{
224 {
VP9, codec_params_t{
230 {
HFYU, codec_params_t{
236 {
FFV1, codec_params_t{
242 {
AV1, codec_params_t{
243 [](bool) {
return is_arm_mac() ?
"libaom-av1" :
"libsvtav1"; },
245 setparam_h264_h265_av1,
261struct state_video_compress_libav {
265 module_data.priv_data =
this;
266 module_data.deleter = libavcodec_compress_done;
269 ~state_video_compress_libav() {
270 av_packet_free(&pkt);
274 struct module module_data;
278 AVPacket *pkt = av_packet_alloc();
280 AVCodecContext *codec_ctx =
nullptr;
285 bool store_orig_format =
false;
286 struct aux_header aux_header;
290 struct setparam_param
params{lavc_opts, blacklist_opts};
292 int requested_gop = DEFAULT_GOP_SIZE;
294 map<string, string> lavc_opts;
295 set<string> blacklist_opts;
298 AVFrame *hwframe =
nullptr;
301 struct SwsContext *sws_ctx =
nullptr;
302 AVFrame *sws_frame =
nullptr;
307 double mov_avg_comp_duration = 0;
308 long mov_avg_frames = 0;
310 int64_t max_pts_diff_reported = 0;
312 map<int64_t, char[VF_METADATA_SIZE]> metadata_storage;
315struct codec_encoders_decoders{
316 std::vector<std::string> encoders;
317 std::vector<std::string> decoders;
322 INCOMP_INTERLACED_DCT,
323 INCOMP_INTRA_REFRESH,
326void incomp_feature_warn(
enum incomp_feature f,
int req_val);
328static codec_encoders_decoders get_codec_encoders_decoders(AVCodecID
id){
329 codec_encoders_decoders res;
330#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 9, 100)
331 const AVCodec *
codec =
nullptr;
333 while ((
codec = av_codec_iterate(&i))) {
334 if (av_codec_is_encoder(
codec) &&
codec->id ==
id) {
337 if (av_codec_is_decoder(
codec) &&
codec->id ==
id) {
342 const AVCodec *
codec =
nullptr;
343 if ((
codec = avcodec_find_encoder(
id))) {
345 if (av_codec_is_encoder(
codec) &&
codec->id ==
id) {
351 if ((
codec = avcodec_find_decoder(
id))) {
353 if (av_codec_is_decoder(
codec) &&
codec->id ==
id) {
363static void get_codec_details(AVCodecID
id,
char *buf,
size_t buflen)
365 auto info = get_codec_encoders_decoders(
id);
368 if(info.encoders.empty() && info.decoders.empty())
371 strncat(buf,
" (", buflen - strlen(buf) - 1);
372 if (!info.encoders.empty()) {
374 for(
const auto& enc : info.encoders){
375 strncat(buf,
" ", buflen - strlen(buf) - 1);
376 strncat(buf, enc.c_str(), buflen - strlen(buf) - 1);
379 if (!info.decoders.empty()) {
380 if (!info.encoders.empty()) {
381 strncat(buf,
"; ", buflen - strlen(buf) - 1);
385 for(
const auto& dec : info.decoders){
386 strncat(buf,
" ", buflen - strlen(buf) - 1);
387 strncat(buf, dec.c_str(), buflen - strlen(buf) - 1);
390 strncat(buf,
")", buflen - strlen(buf) - 1);
393void usage(
bool full) {
394 printf(
"Libavcodec encoder usage:\n");
396 <<
"[:codec=<codec_name>|:encoder=<encoder>]\n\t\t["
397 ":bitrate=<bits_per_sec>|:bpp=<bits_per_pixel>|:"
398 "crf=<crf>|:cqp=<cqp>]\n\t\t[:subsampling=<"
399 "subsampling>][:depth=<depth>"
400 "][:rgb|:yuv][:gop=<gop>]\n\t\t"
401 "[:[disable_]intra_refresh][:threads=<threads>]["
402 ":slices=<slices>][safe]\n\t\t[:<lavc_opt>=<val>]*")
403 <<
"\n\t" <<
SBOLD(
SRED(
"-c libavcodec") <<
":[full]help") <<
"\n";
404 col() <<
"\nwhere\n";
405 col() <<
"\t" <<
SBOLD(
"<encoder>") <<
" specifies encoder (eg. nvenc or libx264 for H.264)\n";
406 col() <<
"\t" <<
SBOLD(
"<codec_name>") <<
" - codec name (default MJPEG) if encoder name is not specified\n";
407 col() <<
"\t" <<
SBOLD(
"[disable_]intra_refresh") <<
", "
408 <<
SBOLD(
"[disable_]interlaced_dct")
409 <<
" - (do not) use Periodic Intra Refresh (H.264/H.265), (do "
410 "not) use interlaced DCT for H.264\n";
411 col() <<
"\t" <<
SBOLD(
"<bits_per_sec>") <<
" specifies requested bitrate\n"
412 <<
"\t\t\t0 means codec default (same as when parameter omitted)\n";
413 col() <<
"\t" <<
SBOLD(
"<bits_per_pixel>") <<
" specifies requested bitrate using compressed bits per pixel\n"
414 <<
"\t\t\tbitrate = frame width * frame height * bits_per_pixel * fps\n";
415 col() <<
"\t" <<
SBOLD(
"<cqp>") <<
" use codec-specific constant QP value, for some codecs like MJPEG this is the only quality setting option\n";
416 col() <<
"\t" <<
SBOLD(
"<crf>") <<
" specifies CRF factor (only for libx264/libx265)\n";
417 col() <<
"\t" <<
SBOLD(
"<subsampling>") <<
" may be one of 444, 422, or 420, default 420 for progresive, 422 for interlaced\n";
418 col() <<
"\t" <<
SBOLD(
"<depth>") <<
" enforce specified compression bit depth\n";
419 col() <<
"\t" <<
SBOLD(
"rgb|yuv") <<
" enforce specified color space compreesion\n";
420 col() <<
"\t" <<
SBOLD(
"<threads>") <<
" can be \"no\", or \"<number>[F][S][n]\" where 'F'/'S' indicate if frame/slice thr. should be used, both can be used (default slice), 'n' means none;\n";
421 col() <<
"\t" <<
" " <<
" use a comma to add also number of conversion threads (eg. \"0S,8\"), default: number of logical cores\n";
422 col() <<
"\t" <<
SBOLD(
"<slices>") <<
" number of slices to use (default: " << DEFAULT_SLICE_COUNT <<
")\n";
423 col() <<
"\t" <<
SBOLD(
"<gop>") <<
" specifies GOP size\n";
424 col() <<
"\t" <<
SBOLD(
"<lavc_opt>") <<
" arbitrary option to be passed directly to libavcodec (eg. preset=veryfast), eventual colons must be backslash-escaped (eg. for x264opts)\n";
425 col() <<
"\t" <<
SBOLD(
"safe") <<
" use opts for (HW) decode compatibility - 420, no intra refresh and interlacing\n";
427 col() <<
"\t" <<
SBOLD(
"header_inserter[=no]")
428 <<
" repeat H.264/HEVC VPS/SPS/PPS hdrs (fixes problems "
430 "contained in the stream)\n";
432 col() <<
"\nSupported codecs:\n";
433 for (
auto &&
param : codec_params) {
435 if (avID == AV_CODEC_ID_NONE) {
439 const AVCodec *
codec;
440 if ((
codec = avcodec_find_encoder(avID))) {
441 strcpy(avail,
"available");
443 strcpy(avail,
"not available");
445 get_codec_details(avID, avail + strlen(avail),
sizeof avail - strlen(avail));
449 col() <<
"\nUse '" <<
SBOLD(
"-c lavc:enc=<enc>:help")
450 <<
"' to display encoder specific options/examples; works\nfor "
451 "decoders as well (use the keyword \"enc[oder]\", anyways).\n";
453 col() <<
"Libavcodec version (linked): " <<
SBOLD(LIBAVCODEC_IDENT) <<
"\n";
454 const char *swscale =
"no";
458 col() <<
"Libswscale supported: " <<
SBOLD(swscale) <<
"\n";
471handle_help(
bool full,
string const &req_encoder,
string const &req_codec)
473 if (req_codec ==
"help") {
474 if (req_encoder.empty()) {
475 MSG(ERROR,
"The encoder needs to be specified "
476 "explictly for input codec listing!\n");
480 avcodec_find_encoder_by_name(req_encoder.c_str());
481 if (
codec !=
nullptr) {
483 print_codec_supp_pix_fmts(
codec->pix_fmts);
485 MSG(ERROR,
"Cannot open encoder: %s\n",
486 req_encoder.c_str());
490 if (!req_encoder.empty()) {
491 show_coder_help(req_encoder);
498ranged_stod(
const char *
val,
double min,
double max)
noexcept(
false)
500 const double dbl = std::stod(
val);
501 if (dbl < min || dbl > max) {
503 string(
"Value ") +
val +
" outside of valid range [" +
504 to_string(min) +
"," + to_string(max) +
"]");
510parse_fmt(
struct state_video_compress_libav *s,
char *
fmt)
noexcept(
false)
524 char *
item, *save_ptr = NULL;
526 while ((
item = strtok_r(
fmt,
":", &save_ptr)) != NULL) {
527 if (strcasecmp(
"help",
item) == 0 || strcmp(
item,
"fullhelp") == 0) {
531 const char *
const codec = strchr(
item,
'=') + 1;
538 s->req_encoder = strchr(
item,
'=') + 1;
540 s->
params.requested_bitrate =
542 if (s->
params.requested_bitrate < 0) {
545 }
else if(strncasecmp(
"bpp=",
item, strlen(
"bpp=")) == 0) {
546 char *bpp_str =
item + strlen(
"bpp=");
549 if (std::isnan(s->
params.requested_bpp)) {
553 }
else if(strncasecmp(
"crf=",
item, strlen(
"crf=")) == 0) {
554 char *crf_str =
item + strlen(
"crf=");
555 s->
params.requested_crf = ranged_stod(crf_str, 0, 63);
560 s->
params.requested_cqp = stoi(strchr(
item,
'=') + 1);
563 atoi(strchr(
item,
'=') + 1);
575 }
else if (strcasecmp(
item,
"rgb") == 0 || strcasecmp(
item,
"yuv") == 0) {
577 }
else if (strstr(
item,
"intra_refresh") !=
nullptr) {
578 s->
params.periodic_intra = strstr(
item,
"disable_") ==
item ? 0 : 1;
579 }
else if (strstr(
item,
"interlaced_dct") !=
nullptr) {
580 s->
params.interlaced_dct = strstr(
item,
"disable_") ==
item ? 0 : 1;
582 char *threads = strchr(
item,
'=') + 1;
583 if (strchr(threads,
',')) {
584 s->conv_thread_count = stoi(strchr(threads,
',') + 1);
585 *strchr(threads,
',') =
'\0';
587 s->
params.thread_mode = threads;
588 }
else if(strncasecmp(
"slices=",
item, strlen(
"slices=")) == 0) {
589 char *slices = strchr(
item,
'=') + 1;
590 s->
params.slices = stoi(slices);
591 }
else if(strncasecmp(
"gop=",
item, strlen(
"gop=")) == 0) {
592 char *gop =
item + strlen(
"gop=");
593 s->requested_gop = atoi(gop);
594 }
else if (strstr(
item,
"header_inserter") ==
item) {
595 s->
params.header_inserter_req =
596 strstr(
item,
"=no") ==
nullptr ? 1 : 0;
597 }
else if (strcmp(
item,
"safe") == 0) {
598 s->
params.periodic_intra = 0;
599 s->
params.periodic_intra = 0;
600 s->
params.interlaced_dct = 0;
603 }
else if (strchr(
item,
'=')) {
604 char *c_val_dup = strdup(strchr(
item,
'=') + 1);
608 s->lavc_opts[
key] = c_val_dup;
618 const string req_codec =
622 if (
show_help != HELP_NONE || req_codec ==
"help") {
623 handle_help(
show_help == HELP_FULL, s->req_encoder, req_codec);
628 s->store_orig_format =
true;
636 module_info.
name =
"libavcodec";
637 module_info.
opts.emplace_back(
module_option{
"Bitrate",
"Bitrate",
"25M",
"quality",
":bitrate=",
false});
638 module_info.
opts.emplace_back(
module_option{
"Crf",
"specifies CRF factor (only for libx264/libx265)",
"23",
"crf",
":crf=",
false});
640 "Do not use Periodic Intra Refresh (H.264/H.265)",
"",
641 "disable_intra_refresh",
":disable_intra_refresh",
true});
643 "may be one of 444, 422, or 420, default 420 for progresive, 422 for interlaced",
645 "subsampling",
":subsampling=",
false});
647 "arbitrary option to be passed directly to libavcodec (eg. preset=veryfast), eventual colons must be backslash-escaped (eg. for x264opts)",
649 "lavc_opt",
":",
false});
651 for (
const auto&
param : codec_params) {
653 if (avID == AV_CODEC_ID_NONE) {
657 if (!(i = avcodec_find_encoder(avID))) {
667 auto coders = get_codec_encoders_decoders(avID);
668 for(
const auto& enc : coders.encoders){
670 encoder{enc,
":encoder=" + enc});
681 " Signalize input pixel format to reciever and try\n");
685#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(58, 9, 100)
688 avcodec_register_all();
691 char *
fmt = strdup(opts);
692 struct state_video_compress_libav *s =
new state_video_compress_libav(
parent);
696 }
catch (invalid_argument &e) {
697 MSG(ERROR,
"Non-numeric argument presented for an option requiring a "
706 return &s->module_data;
710static int vaapi_init(
struct AVCodecContext *s){
714 AVBufferRef *device_ref =
nullptr;
715 AVBufferRef *hw_frames_ctx =
nullptr;
716 int ret = create_hw_device_ctx(AV_HWDEVICE_TYPE_VAAPI, &device_ref);
720 if (s->active_thread_type & FF_THREAD_FRAME)
721 pool_size += s->thread_count;
723 ret = create_hw_frame_ctx(device_ref,
733 s->hw_frames_ctx = hw_frames_ctx;
735 av_buffer_unref(&device_ref);
739 av_buffer_unref(&hw_frames_ctx);
740 av_buffer_unref(&device_ref);
745void print_codec_supp_pix_fmts(
const enum AVPixelFormat *
first) {
747 snprintf(out,
sizeof out,
753void print_pix_fmts(
const list<enum AVPixelFormat>
754 &req_pix_fmts,
const enum AVPixelFormat *
first) {
755 print_codec_supp_pix_fmts(
first);
757 for (
auto &c : req_pix_fmts) {
758 snprintf(out + strlen(out),
sizeof out - strlen(out),
" %s",
759 av_get_pix_fmt_name(c));
775static enum AVPixelFormat get_first_matching_pix_fmt(list<enum AVPixelFormat>::const_iterator &it,
776 list<enum AVPixelFormat>::const_iterator end,
777 const enum AVPixelFormat *codec_pix_fmts)
779 if(codec_pix_fmts == NULL)
780 return AV_PIX_FMT_NONE;
782 for ( ; it != end; it++) {
783 const enum AVPixelFormat *tmp = codec_pix_fmts;
784 enum AVPixelFormat
fmt;
785 while((
fmt = *tmp++) != AV_PIX_FMT_NONE) {
787 enum AVPixelFormat ret = *it++;
793 return AV_PIX_FMT_NONE;
796template<
typename T,
bool log_err = false>
799 if constexpr (std::is_same_v<T, char *> ||
800 std::is_same_v<T, const char *>) {
803 val_str = to_string(
val);
806 const int ret = av_opt_set(priv_data,
key, val_str.c_str(), 0);
808 string err = string(
MOD_NAME) +
"Unable to set " +
desc +
" to " + val_str;
813 desc, val_str.c_str());
818static void set_cqp(
struct AVCodecContext *codec_ctx,
int requested_cqp) {
819 int cqp = requested_cqp;
820 if (requested_cqp == -1) {
821 if (strstr(codec_ctx->codec->name,
"_qsv") !=
nullptr) {
822 cqp = strcmp(codec_ctx->codec->name,
"mjpeg_qsv") == 0 ? DEFAULT_CQP_MJPEG_QSV : DEFAULT_CQP_QSV;
823 }
else if (strcmp(codec_ctx->codec->name,
"mjpeg") == 0) {
824 cqp = DEFAULT_CQP_MPJEG;
829 codec_ctx->flags |= AV_CODEC_FLAG_QSCALE;
831 if (strcmp(codec_ctx->codec->name,
"mjpeg") == 0 ||
832 strcmp(codec_ctx->codec->name,
"libopenh264") == 0) {
833 codec_ctx->qmin = codec_ctx->qmax = cqp;
834 MSG(INFO,
"Setting %s qmin/qmax to %d\n",
835 codec_ctx->codec->name, cqp);
836 }
else if (strstr(codec_ctx->codec->name,
"_qsv") !=
nullptr) {
837 codec_ctx->global_quality = cqp;
847 bool is_vaapi = regex_match(s->codec_ctx->codec->name, regex(
".*_vaapi"));
848 bool is_mjpeg = strstr(s->codec_ctx->codec->name,
"mjpeg") !=
nullptr;
854 const double avg_bpp =
params.requested_bpp > 0.0
858 bool set_bitrate =
false;
859 int_fast64_t bitrate =
860 params.requested_bitrate > 0
861 ?
params.requested_bitrate
864 s->codec_ctx->strict_std_compliance = -2;
867 if (
params.requested_cqp >= 0 ||
868 ((is_vaapi || is_mjpeg) &&
params.requested_crf == -1.0 &&
869 params.requested_bitrate == 0 &&
870 params.requested_bpp == 0.0)) {
871 set_cqp(s->codec_ctx,
params.requested_cqp);
872 }
else if (
params.requested_crf >= 0.0 ||
873 (get_default_crf(s->codec_ctx->codec->name) != 0 &&
874 params.requested_bitrate == 0 &&
875 params.requested_bpp == 0.0)) {
876 const double crf =
params.requested_crf >= 0.0
878 : get_default_crf(s->codec_ctx->codec->name);
881 }
else if (strcmp(s->codec_ctx->codec->name,
"libopenh264") != 0) {
884 if (set_bitrate ||
params.requested_bitrate > 0) {
885 s->codec_ctx->bit_rate = bitrate;
886 s->codec_ctx->bit_rate_tolerance = bitrate /
desc.
fps * 6;
894 s->codec_ctx->time_base = (AVRational){1,(int)
desc.
fps};
895 s->codec_ctx->gop_size = s->requested_gop;
896 s->codec_ctx->max_b_frames = 0;
898 s->codec_ctx->pix_fmt = pix_fmt;
902 set_codec_thread_mode(s->codec_ctx, &
params);
904 params.slices, s->codec_ctx->codec_id == AV_CODEC_ID_FFV1
906 : DEFAULT_SLICE_COUNT);
909 for (
auto const &
item : s->lavc_opts) {
910 if (s->blacklist_opts.count(
item.first) == 1) {
914 s->codec_ctx->priv_data,
item.first.c_str(),
item.second.c_str())) {
923 "* lavc-use-codec=<c>\n"
924 " Restrict codec to use user specified pixel fmt. Use either FFmpeg name\n"
925 " (eg. nv12, yuv422p10le or yuv444p10le) or UltraGrid pixel formats names\n"
926 " (v210, R10k, UYVY etc.). See wiki for more info.\n");
931list<enum AVPixelFormat> get_requested_pix_fmts(
codec_t in_codec,
935 enum AVPixelFormat
fmt = av_get_pix_fmt(
val);
936 if (
fmt != AV_PIX_FMT_NONE) {
947 enum AVPixelFormat pixfmts[AV_PIX_FMT_NB];
949 return { pixfmts, pixfmts + nb_fmts };
952void apply_blacklist([[maybe_unused]] list<enum AVPixelFormat> &formats, [[maybe_unused]]
const char *encoder_name) {
958 if (strstr(encoder_name,
"nvenc") !=
nullptr ||
959 strstr(encoder_name,
"qsv") !=
nullptr) {
960 if (formats.size() == 1) {
964 if (
auto it = std::find(formats.begin(), formats.end(), AV_PIX_FMT_X2RGB10LE); it != formats.end()) {
966 "and current encoder (" << encoder_name <<
") , use '--param lavc-use-codec=x2rgb10le' to enforce.\n";
973static bool try_open_codec(
struct state_video_compress_libav *s,
974 AVPixelFormat &pix_fmt,
977 const AVCodec *
codec)
980 s->codec_ctx = avcodec_alloc_context3(
codec);
986 if (!set_codec_ctx_params(s, pix_fmt,
desc,
ug_codec)) {
987 avcodec_free_context(&s->codec_ctx);
994 if (pix_fmt == AV_PIX_FMT_VAAPI){
997 avcodec_free_context(&s->codec_ctx);
1002 s->hwframe = av_frame_alloc();
1003 av_hwframe_get_buffer(s->codec_ctx->hw_frames_ctx, s->hwframe, 0);
1004 pix_fmt = AV_PIX_FMT_NV12;
1009 if (
const AVPixFmtDescriptor *
desc = av_pix_fmt_desc_get(pix_fmt)) {
1010 s->codec_ctx->colorspace = (
desc->flags & AV_PIX_FMT_FLAG_RGB) != 0U ? AVCOL_SPC_RGB : AVCOL_SPC_BT709;
1011 s->codec_ctx->color_range = (
desc->flags & AV_PIX_FMT_FLAG_RGB) != 0U ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
1016 if (avcodec_open2(s->codec_ctx,
codec, NULL) < 0) {
1017 avcodec_free_context(&s->codec_ctx);
1018 log_msg(
LOG_LEVEL_ERROR,
"[lavc] Could not open codec for pixel format %s\n", av_get_pix_fmt_name(pix_fmt));
1025const AVCodec *get_av_codec(
struct state_video_compress_libav *s,
codec_t *
ug_codec,
bool src_rgb) {
1027 if (!s->req_encoder.empty()) {
1028 const AVCodec *
codec =
1029 avcodec_find_encoder_by_name(s->req_encoder.c_str());
1032 s->req_encoder.c_str());
1037 "Encoder \"%s\" doesn't encode requested codec!\n",
1038 s->req_encoder.c_str());
1050 if (codec_params.find(*
ug_codec) != codec_params.end() && codec_params[*
ug_codec].get_prefered_encoder) {
1051 const char *prefered_encoder = codec_params[*
ug_codec].get_prefered_encoder(
1053 const AVCodec *
codec = avcodec_find_encoder_by_name(prefered_encoder);
1064static bool configure_swscale(
struct state_video_compress_libav *s,
struct video_desc desc,
enum AVPixelFormat sws_out_pixfmt) {
1070 enum AVPixelFormat pixfmts[AV_PIX_FMT_NB];
1072 enum AVPixelFormat sws_in_format = nb_fmts == 0 ? AV_PIX_FMT_UYVY422 : pixfmts[0];
1073 log_msg(
LOG_LEVEL_NOTICE,
MOD_NAME "Attempting to use swscale to convert from %s to %s.\n", av_get_pix_fmt_name(sws_in_format), av_get_pix_fmt_name(sws_out_pixfmt));
1091 s->sws_frame = av_frame_alloc();
1092 if (!s->sws_frame) {
1096 s->sws_frame->width = s->codec_ctx->width;
1097 s->sws_frame->height = s->codec_ctx->height;
1098 s->sws_frame->format = sws_out_pixfmt;
1099 if (
int ret = av_image_alloc(s->sws_frame->data, s->sws_frame->linesize,
1100 s->sws_frame->width, s->sws_frame->height,
1101 sws_out_pixfmt, 32); ret < 0) {
1107 av_get_pix_fmt_name(sws_in_format),
1108 av_get_pix_fmt_name(sws_out_pixfmt));
1114try_open_remaining_pixfmts(state_video_compress_libav *s,
video_desc desc,
1116 set<AVPixelFormat>
const &fmts_tried)
1119 return AV_PIX_FMT_NONE;
1121 unsigned usable_fmt_cnt = 0;
1122 if (
codec->pix_fmts ==
nullptr) {
1123 return AV_PIX_FMT_NONE;
1125 for (
const auto *pix =
codec->pix_fmts; *pix != AV_PIX_FMT_NONE;
1127 usable_fmt_cnt += 1;
1129 if (usable_fmt_cnt == fmts_tried.size()) {
1130 return AV_PIX_FMT_NONE;
1134 <<
". Trying to convert with swscale instead.\n";
1135 for (
const auto *pix =
codec->pix_fmts; *pix != AV_PIX_FMT_NONE;
1137 const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(*pix);
1138 if (fmts_tried.count(*pix) == 1 || fmt_desc ==
nullptr ||
1139 (fmt_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0U) {
1142 AVPixelFormat curr_pix_fmt = *pix;
1144 return curr_pix_fmt;
1147 return AV_PIX_FMT_NONE;
1154 AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
1155 const AVCodec *
codec =
nullptr;
1157 sws_freeContext(s->sws_ctx);
1158 s->sws_ctx =
nullptr;
1159 av_frame_free(&s->sws_frame);
1175 apply_blacklist(requested_pix_fmt,
codec->
name);
1176 auto requested_pix_fmt_it = requested_pix_fmt.cbegin();
1177 set<AVPixelFormat> fmts_tried;
1178 while ((pix_fmt = get_first_matching_pix_fmt(requested_pix_fmt_it, requested_pix_fmt.cend(),
codec->pix_fmts)) != AV_PIX_FMT_NONE) {
1179 fmts_tried.insert(pix_fmt);
1186 print_pix_fmts(requested_pix_fmt,
codec->pix_fmts);
1194 if (pix_fmt == AV_PIX_FMT_NONE) {
1198 get_commandline_param(
"lavc-use-codec") != NULL ?
"Do not enforce encoder codec or use a supported one." :
1199 "Do not enforce subsampling/depth/colospace or use a difffereng configuration that is feasible.");
1206 codec->capabilities, s->codec_ctx->thread_type, s->codec_ctx->thread_count);
1208 incomp_feature_warn(INCOMP_SUBSAMPLING,
1210 incomp_feature_warn(INCOMP_DEPTH,
1211 av_pix_fmt_desc_get(pix_fmt)->comp[0].
depth);
1216 s->mov_avg_frames = s->mov_avg_comp_duration = 0;
1220 if (!configure_swscale(s,
desc, pix_fmt)) {
1227 s->aux_header.buf_len =
1228 sizeof(uint32_t) + s->codec_ctx->extradata_size;
1229 *(uint32_t *) (
void *) s->aux_header.buf =
1230 s->codec_ctx->extradata_size;
1231 memcpy(s->aux_header.buf +
sizeof(uint32_t),
1232 s->codec_ctx->extradata, s->codec_ctx->extradata_size);
1244 enum { REPEAT_INT_SEC = 30 };
1245 constexpr int mov_window = 100;
1247 s->mov_avg_comp_duration = (s->mov_avg_comp_duration * (mov_window - 1) +
duration) / mov_window;
1248 s->mov_avg_frames += 1;
1249 if (s->mov_avg_frames < 2 * mov_window || s->mov_avg_comp_duration < 1 / s->
compressed_desc.fps) {
1253 if (now < s->duration_warn_last_print +
NS_IN_SEC * REPEAT_INT_SEC) {
1256 s->duration_warn_last_print = now;
1258 mov_window, s->mov_avg_comp_duration * 1000, 1000 / s->
compressed_desc.fps);
1260 string quality_hurt =
"latency";
1261 if (regex_match(s->codec_ctx->codec->name, regex(
".*nvenc.*"))) {
1262 if (s->lavc_opts.find(
"delay") == s->lavc_opts.end()) {
1263 hint =
"\"delay=<frames>\" option to NVENC compression (2 suggested)";
1265 }
else if (strcmp(s->codec_ctx->codec->name,
"libaom-av1") == 0) {
1266 if (s->lavc_opts.find(
"cpu-used") == s->lavc_opts.end()) {
1267 hint =
"\"cpu-used=8\" option for quality/speed trade-off to AOM AV1 compression (values 0-8 allowed)";
1268 quality_hurt =
"quality";
1270 }
else if (strcmp(s->codec_ctx->codec->name,
"libsvt_hevc") == 0) {
1271 if (s->lavc_opts.find(
"preset") == s->lavc_opts.end()) {
1273 "\"preset=12\" option for quality/speed trade-off "
1274 "to libsvt_hevc compression (values 0-12 allowed)";
1275 quality_hurt =
"quality";
1277 }
else if ((s->codec_ctx->thread_type & FF_THREAD_SLICE) == 0 && (s->codec_ctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) != 0) {
1278 hint =
"\"threads=<n>FS\" option with small <n> or 0 (nr of logical cores) to compression";
1280 hint =
"\"threads=<n>\" option with small <n> or 0 (nr of logical cores) to compression";
1282 if (!hint.empty()) {
1283 LOG(
LOG_LEVEL_WARNING) <<
MOD_NAME "Consider adding " << hint <<
" to increase throughput at the expense of " << quality_hurt <<
".\n";
1287 bool dst_rgb = av_pix_fmt_desc_get(s->codec_ctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_RGB;
1288 if (src_rgb != dst_rgb && dur_pixfmt_change_ns /
NS_IN_SEC_DBL > s->mov_avg_comp_duration / 4) {
1290 <<
MOD_NAME "Also pixfmt change of last frame took "
1291 <<
NS_TO_MS((
double) dur_pixfmt_change_ns)
1293 "Consider adding \"--conv-policy cds\" to prevent color "
1294 "space conversion.\n";
1298static void write_orig_format(
struct video_frame *compressed_frame,
codec_t orig_pixfmt) {
1299 if (compressed_frame ==
nullptr) {
1304 "Currently cannot store input format to different compression stream than H.264/HEVC\n");
1307 char *data = compressed_frame->
tiles[0].
data;
1308 unsigned int *data_len = &compressed_frame->
tiles[0].
data_len;
1311 memcpy(data + *data_len, sei_nal_prefix,
sizeof sei_nal_prefix);
1312 *data_len +=
sizeof sei_nal_prefix;
1315 memcpy(data + *data_len, sei_nal_prefix,
sizeof sei_nal_prefix);
1316 *data_len +=
sizeof sei_nal_prefix;
1320 unsigned subs_a = (
desc.subsampling / 100 % 10);
1321 unsigned subs_b = (
desc.subsampling / 10 % 10);
1322 unsigned subs_v = subs_a - 1;
1323 unsigned subs_h = !!subs_b;
1325 uint8_t format = ((
desc.depth - 8) / 2) << 4U | subs_v << 2U | subs_h << 1U |
rgb;
1326 memcpy(data + *data_len, &format,
sizeof format);
1327 *data_len +=
sizeof format;
1329 memcpy(data + *data_len, &eob,
sizeof eob);
1330 *data_len +=
sizeof eob;
1334store_metadata(state_video_compress_libav *s,
const struct video_frame *f,
1338 if (pts > HOUSEKEEP_INTERVAL && pts % HOUSEKEEP_INTERVAL == 0) {
1339 s->metadata_storage.erase(
1340 s->metadata_storage.begin(),
1341 s->metadata_storage.lower_bound(pts - HOUSEKEEP_INTERVAL));
1346restore_metadata(state_video_compress_libav *s,
struct video_frame *out,
1349 assert (pts != AV_NOPTS_VALUE);
1350 auto it = s->metadata_storage.find(pts);
1351 if (it != s->metadata_storage.end()) {
1355 MOD_NAME "Metadata for frame not found!\n");
1356 debug_msg(
"Metadata for frame %" PRIu64
" not found!\n", pts);
1361store_sps_pps_vps(state_video_compress_libav *s, AVPacket *pkt)
1367 if (s->aux_header.buf_len > 0) {
1374 const int *nalu_req = is_hevc ? hevc_nalu_req : h264_nalu_req;
1375 const unsigned char *
const first_nal =
1377 const unsigned char *nal = first_nal;
1379 const unsigned char *endptr =
nullptr;
1380 while (nal !=
nullptr) {
1384 if (nalu_req[i] == 0) {
1390 if (nalu_req[i] != 0) {
1394 memcpy(s->aux_header.buf, start_code,
sizeof start_code);
1395 memcpy(s->aux_header.buf +
sizeof start_code, first_nal,
1396 endptr - first_nal);
1397 s->aux_header.buf_len =
sizeof start_code + endptr - first_nal;
1400auto out_vf_from_pkt(state_video_compress_libav *s, AVPacket *pkt) {
1401 shared_ptr<video_frame> out;
1402 if (pkt->size == 0) {
1407 out = shared_ptr<video_frame>(
1409 free(frame->tiles[0].data);
1413 assert(s->codec_ctx->codec_tag != 0);
1417 restore_metadata(s, out.get(), pkt->pts);
1418 out->tiles[0].data_len = s->aux_header.buf_len + pkt->size;
1419 out->tiles[0].data = (
char *) malloc(out->tiles[0].data_len);
1420 memcpy(out->tiles[0].data, s->aux_header.buf, s->aux_header.buf_len);
1421 memcpy(out->tiles[0].data + s->aux_header.buf_len, pkt->data,
1423 if (s->
params.header_inserter_req == 1) {
1424 store_sps_pps_vps(s, pkt);
1427 av_packet_unref(s->pkt);
1432shared_ptr<video_frame>
1433receive_packet(state_video_compress_libav *s)
1435 const int ret = avcodec_receive_packet(s->codec_ctx, s->pkt);
1437 if (ret == AVERROR(EAGAIN)) {
1439 "avcodec_receive_packet: received none packet "
1443 MOD_NAME "Receive packet error", ret);
1448 const int64_t pts_diff = s->cur_pts - s->pkt->pts - 1;
1449 if (pts_diff > s->max_pts_diff_reported) {
1450 MSG(WARNING,
"Frame delayed %" PRId64
" frames by the compression!\n",
1452 s->max_pts_diff_reported = pts_diff;
1455 return out_vf_from_pkt(s, s->pkt);
1458static shared_ptr<video_frame> libavcodec_compress_tile(
struct module *mod, shared_ptr<video_frame>
tx)
1460 auto *s = (state_video_compress_libav *) mod->
priv_data;
1461 list<shared_ptr<void>> cleanup_callbacks;
1463 libavcodec_check_messages(s);
1474 return receive_packet(s);
1487 av_hwframe_transfer_data(s->hwframe,
frame, 0);
1494 sws_scale(s->sws_ctx,
1500 s->sws_frame->linesize);
1501 frame = s->sws_frame;
1507 frame->pts = s->cur_pts++;
1508 store_metadata(s,
tx.get(),
frame->pts);
1509 if (
int ret = avcodec_send_frame(s->codec_ctx,
frame)) {
1514 shared_ptr<video_frame> out = receive_packet(s);
1518 " s, dump+swscale " << (t2 - t1) / (double)
NS_IN_SEC <<
1519 " s, compression " << (t3 - t2) / (double)
NS_IN_SEC <<
" s\n";
1526 if (s->store_orig_format) {
1527 write_orig_format(out.get(),
tx->color_spec);
1533static void cleanup(
struct state_video_compress_libav *s)
1536 int ret = avcodec_send_frame(s->codec_ctx, NULL);
1542 AVPacket *pkt = av_packet_alloc();
1543 ret = avcodec_receive_packet(s->codec_ctx, pkt);
1544 av_packet_unref(pkt);
1545 av_packet_free(&pkt);
1546 if (ret != 0 && ret != AVERROR_EOF) {
1551 }
while (ret != AVERROR_EOF);
1552 avcodec_free_context(&s->codec_ctx);
1555 av_frame_free(&s->hwframe);
1558 sws_freeContext(s->sws_ctx);
1559 s->sws_ctx =
nullptr;
1560 av_frame_free(&s->sws_frame);
1564static void libavcodec_compress_done(
struct module *mod)
1566 struct state_video_compress_libav *s = (
struct state_video_compress_libav *) mod->
priv_data;
1578static void set_codec_thread_mode(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1580 if (
param->thread_mode ==
"no") {
1581 codec_ctx->thread_type = 0;
1582 codec_ctx->thread_count = 1;
1586 int req_thread_count = -1;
1587 int req_thread_type = 0;
1590 req_thread_count = stoi(
param->thread_mode, &endpos);
1591 }
catch(invalid_argument &) {
1593 while (endpos !=
param->thread_mode.size()) {
1594 switch (toupper(
param->thread_mode[endpos])) {
1595 case 'n': req_thread_type = -1;
break;
1596 case 'F': req_thread_type |= FF_THREAD_FRAME;
break;
1597 case 'S': req_thread_type |= FF_THREAD_SLICE;
break;
1603 if (req_thread_type == 0) {
1604 if ((codec_ctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) != 0) {
1605 req_thread_type = FF_THREAD_SLICE;
1607 (codec_ctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) != 0) {
1609 "You may select frame-based paralellism if needed.\n");
1611 }
else if (req_thread_type == -1) {
1612 req_thread_type = 0;
1614 if (((req_thread_type & FF_THREAD_SLICE) != 0 && (codec_ctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) == 0) ||
1615 ((req_thread_type & FF_THREAD_FRAME) != 0 && (codec_ctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) == 0)) {
1618 codec_ctx->thread_type = req_thread_type;
1621 if (req_thread_count != -1) {
1622 codec_ctx->thread_count = req_thread_count;
1625 if (strcmp(codec_ctx->codec->name,
"libaom-av1") == 0 ||
1626 strcmp(codec_ctx->codec->name,
"librav1e") == 0) {
1627 codec_ctx->thread_count = thread::hardware_concurrency();
1628 }
else if (strstr(codec_ctx->codec->name,
"libx26") !=
1629 codec_ctx->codec->name) {
1630 codec_ctx->thread_count = 0;
1632 }
else if (codec_ctx->thread_type != 0) {
1633 codec_ctx->thread_count = thread::hardware_concurrency();
1638static void setparam_default(AVCodecContext *codec_ctx,
struct setparam_param * )
1640 if (codec_ctx->codec->id == AV_CODEC_ID_JPEG2000) {
1647mjpeg_adjust_param(
struct setparam_param *
param)
1651 if (
param->slices == 1) {
1652 if (
param->thread_mode.empty()) {
1654 "setting thread count=1");
1655 param->thread_mode =
"1";
1656 }
else if (strtol(
param->thread_mode.c_str(),
nullptr, 10) !=
1658 snprintf_ch(warn,
"slice=1 with thread count!=1 not "
1661 }
else if (strtol(
param->thread_mode.c_str(),
nullptr, 10) == 1) {
1662 if (
param->slices == -1) {
1664 "setting slices=1");
1666 }
else if (
param->slices > 1) {
1667 snprintf_ch(warn,
"slice>1 with thread count=1 not "
1672 if (strlen(warn) == 0) {
1676 "%s. If seems that FFmpeg JPEG encoder requires "
1677 "both slice and threads to be 1, if any of it "
1678 "is or the JPEG is broken.\n",
1682static void setparam_jpeg(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1684 if (strcmp(codec_ctx->codec->name,
"mjpeg") == 0) {
1686 mjpeg_adjust_param(
param);
1688 if (strcmp(codec_ctx->codec->name,
"mjpeg_qsv") == 0) {
1693static void configure_amf([[maybe_unused]] AVCodecContext *codec_ctx, [[maybe_unused]]
struct setparam_param *
param) {
1695 const char *
const usage = codec_ctx->codec->id == AV_CODEC_ID_AV1
1696 ? DEFAULT_AMF_USAGE_AV1
1697 : DEFAULT_AMF_USAGE;
1699 if (codec_ctx->codec->id == AV_CODEC_ID_AV1 ||
1700 codec_ctx->codec->id == AV_CODEC_ID_HEVC) {
1702 }
else if (
"h264_amf"s == codec_ctx->codec->name) {
1704 if (
param->header_inserter_req == -1) {
1705 MSG(INFO,
"Auto-enabling header inserter for %s.\n",
1706 codec_ctx->codec->name);
1707 param->header_inserter_req = 1;
1713configure_mf(AVCodecContext *codec_ctx,
1714 [[maybe_unused]]
struct setparam_param *
param)
1719 "video_conference");
1724incomp_feature_warn(
enum incomp_feature f,
int req_val)
1726 const char *disable_opt =
nullptr;
1733 "Selected color depth %d b may not be supported by HW "
1736 disable_opt =
":depth=8";
1738 case INCOMP_INTRA_REFRESH:
1739 if (req_val != -1) {
1742 MSG(WARNING,
"Auto-enabling intra-refresh "
1743 "which may not be supported by HW coders.\n");
1744 disable_opt =
":disable_intra_refresh";
1746 case INCOMP_INTERLACED_DCT:
1747 if (req_val != -1) {
1750 MSG(WARNING,
"Auto-enabling interlaced DCT "
1751 "which may not be supported by HW coders.\n");
1752 disable_opt =
":disable_interlaced_dct";
1754 case INCOMP_SUBSAMPLING:
1759 "Selected pixfmt has subsampling %d:%d:%d, "
1760 "which is usually not supported by HW coders\n",
1761 (req_val / 1000), ((req_val / 100) % 10),
1762 ((req_val / 10) % 10));
1763 disable_opt =
":subs=420";
1766 MSG(INFO,
"Use '%s' or ':safe' to disable.\n", disable_opt);
1770 "lavc-rc-buffer-size-factor",
1771 "* lavc-rc-buffer-size-factor=<val>\n"
1772 " Multiplier how much can individual frame overshot average size (default "
1776configure_x264_x265(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1778 const char *preset =
"ultrafast";
1779 if (strstr(codec_ctx->codec->name,
"libx264") ==
1780 codec_ctx->codec->name &&
1783 preset =
"veryfast";
1787 const char *tune = codec_ctx->codec->id == AV_CODEC_ID_H264 ?
"zerolatency,fastdecode" :
"zerolatency";
1791 codec_ctx->rc_max_rate = codec_ctx->bit_rate;
1796 lavc_rc_buffer_size_factor = stof(
val);
1798 codec_ctx->rc_buffer_size = codec_ctx->rc_max_rate /
param->desc.fps * lavc_rc_buffer_size_factor;
1799 codec_ctx->qcompress = codec_ctx->codec->id == AV_CODEC_ID_H265 ? 0.5F : 0.0F;
1805 codec_ctx->max_qdiff = 69;
1810 param->interlaced_dct != 0 &&
1811 codec_ctx->codec_id == AV_CODEC_ID_H264) {
1812 incomp_feature_warn(INCOMP_INTERLACED_DCT,
param->interlaced_dct);
1813 codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
1817 if (
param->lavc_opts.find(
"x265-params") !=
param->lavc_opts.end()) {
1818 x265_params =
param->lavc_opts.at(
"x265-params");
1819 param->blacklist_opts.insert(
"x265-params");
1821 auto x265_params_append = [&](
const string &
key,
const string &
val) {
1822 if (x265_params.find(
key) == string::npos) {
1823 x265_params += (x265_params.empty() ?
"" :
":") +
key +
"=" +
val;
1826 x265_params_append(
"keyint", to_string(codec_ctx->gop_size));
1828 if (
param->periodic_intra != 0) {
1829 incomp_feature_warn(INCOMP_INTRA_REFRESH,
param->periodic_intra);
1830 codec_ctx->refs = 1;
1831 if (
"libx264"s == codec_ctx->codec->name ||
"libx264rgb"s == codec_ctx->codec->name) {
1833 }
else if (
"libx265"s == codec_ctx->codec->name) {
1834 x265_params_append(
"intra-refresh",
"1");
1835 x265_params_append(
"constrained-intra",
"1");
1836 x265_params_append(
"no-open-gop",
"1");
1839 if (
"libx265"s == codec_ctx->codec->name) {
1844static void configure_qsv_h264_hevc(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1847 DEFAULT_QSV_PRESET);
1851 if (
param->periodic_intra != 0) {
1852 incomp_feature_warn(INCOMP_INTRA_REFRESH,
param->periodic_intra);
1858 incomp_feature_warn(INCOMP_INTERLACED_DCT,
param->interlaced_dct);
1859 codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
1863 const char *rc = DEFAULT_QSV_RC;
1864 if (
auto it =
param->lavc_opts.find(
"rc"); it !=
param->lavc_opts.end()) {
1865 rc = it->second.c_str();
1866 param->blacklist_opts.insert(
"rc");
1868 if (strcmp(rc,
"help") == 0) {
1870 <<
SBOLD(
"See codec-specific usage for available RCs (``-c "
1871 "libavcodec:encoder=<enc>:help`).")
1874 }
else if (strcasecmp(rc,
"cbr") == 0) {
1875 codec_ctx->rc_max_rate = codec_ctx->bit_rate;
1877 }
else if (strcasecmp(rc,
"cqp") == 0) {
1878 codec_ctx->flags |= AV_CODEC_FLAG_QSCALE;
1879 }
else if (strcasecmp(rc,
"icq") == 0 || strcasecmp(rc,
"qvbr") == 0) {
1880 codec_ctx->global_quality = codec_ctx->global_quality <= 0 ? DEFAULT_CQP : codec_ctx->global_quality;
1881 codec_ctx->flags &= ~AV_CODEC_FLAG_QSCALE;
1882 if (strcasecmp(rc,
"qvbr") == 0) {
1883 assert(codec_ctx->bit_rate > 0);
1884 codec_ctx->rc_max_rate = 23 * codec_ctx->bit_rate / 20;
1886 }
else if (strcasecmp(rc,
"vbr") == 0) {
1889 rc, PACKAGE_BUGREPORT);
1894static void configure_vaapi(AVCodecContext * ,
struct setparam_param *
param) {
1895 param->thread_mode =
"no";
1899static void configure_aom_av1(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1906static void configure_nvenc(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1908 const char *preset = DEFAULT_NVENC_PRESET;
1914 preset = FALLBACK_NVENC_PRESET;
1916 if (!
param->have_preset) {
1923#ifdef PATCHED_FF_NVENC_NO_INFINITE_GOP
1924 const bool patched_ff =
true;
1926 const bool patched_ff =
false;
1927 if (
param->periodic_intra != 0) {
1932 if ((patched_ff &&
param->periodic_intra != 0) ||
param->periodic_intra == 1) {
1933 incomp_feature_warn(INCOMP_INTRA_REFRESH,
param->periodic_intra);
1941 check_av_opt_set<int>(codec_ctx->priv_data,
"zerolatency", 1,
"zero latency operation (no reordering delay)");
1943 codec_ctx->rc_max_rate = codec_ctx->bit_rate;
1946 lavc_rc_buffer_size_factor = stof(
val);
1950 "To reduce NVENC pulsation, you can try \"--param "
1951 "lavc-rc-buffer-size-factor=0\""
1952 " or a small number. 0 or higher value (than default "
1954 <<
") may cause frame drops on receiver.\n";
1956 codec_ctx->rc_buffer_size =
1957 (int) ((
double) codec_ctx->rc_max_rate /
param->desc.fps *
1958 lavc_rc_buffer_size_factor);
1960 codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
1964static void configure_rav1e(AVCodecContext *codec_ctx,
struct setparam_param * )
1972configure_svt_hevc_vp9(AVCodecContext *codec_ctx,
struct setparam_param *
param)
1976 codec_ctx->priv_data,
"forced-idr",
1977 strcmp(codec_ctx->codec->name,
"libsvt_hevc") == 0 ? 0 : 1);
1979 if (
"libsvt_hevc"s == codec_ctx->codec->name) {
1982 int tile_col_cnt =
param->desc.width >= 1024 ? 4 :
param->desc.width >= 512 ? 2 : 1;
1983 int tile_row_cnt =
param->desc.height >= 256 ? 4 :
param->desc.height >= 128 ? 2 : 1;
1984 if (tile_col_cnt * tile_row_cnt > 1 &&
param->desc.width >= 256 &&
param->desc.height >= 64) {
1990 if (
param->desc.width *
param->desc.height *
param->desc.fps > FLW_UHD_60) {
1998configure_svt_av1(AVCodecContext *codec_ctx,
struct setparam_param *
param) {
1999 const char *preset =
2005#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(59, 21, 100)
2008 if (
param->requested_bitrate > 0) {
2009 if (
param->requested_crf == -1 &&
param->requested_cqp == -1) {
2012 "Bitrate setting without crf/cqp for SVT "
2013 "AV1 is not recommended since it increases "
2014 "latency, prefer CRF or CQP mode if "
2016 MSG(WARNING,
"However, you can specify _both_ crf/cqp "
2017 "and bitrate options to set bitrate "
2020 codec_ctx->rc_max_rate =
param->requested_bitrate;
2021 codec_ctx->bit_rate = 0;
2022 MSG(INFO,
"Setting rc_max_rate to %" PRId64
"\n",
2023 codec_ctx->rc_max_rate);
2027 "fast-decode=1:tile-columns=2:tile-rows=2");
2031 for (
auto const &
val : {
"tile_columns",
"tile_rows" }) {
2033 "tile dimensions for SVT AV1");
2039configure_libopenh264(AVCodecContext *codec_ctx,
2040 struct setparam_param *
param)
2042 if (
param->requested_bitrate != 0 ||
param->requested_bpp != 0) {
2044 }
else if (
param->requested_cqp != -1) {
2045 MSG(WARNING,
"Using quality RC with OpenH264 is currently not recoomended "
2046 "- seems like it performs worse than bitrate or none.\n");
2052 MSG(WARNING,
"Setting frame skipping for OpenH264 when bitrate/quality "
2053 "is set. Do not set if not desired.\n");
2058static void setparam_h264_h265_av1(AVCodecContext *codec_ctx,
struct setparam_param *
param)
2060 if (regex_match(codec_ctx->codec->name, regex(
".*_amf"))) {
2061 configure_amf(codec_ctx,
param);
2062 }
else if (regex_match(codec_ctx->codec->name, regex(
".*_mf"))) {
2063 configure_mf(codec_ctx,
param);
2064 }
else if (regex_match(codec_ctx->codec->name, regex(
".*_vaapi"))) {
2065 configure_vaapi(codec_ctx,
param);
2066 }
else if (strncmp(codec_ctx->codec->name,
"libx264", strlen(
"libx264")) == 0 ||
2067 strcmp(codec_ctx->codec->name,
"libx265") == 0) {
2068 configure_x264_x265(codec_ctx,
param);
2069 }
else if (regex_match(codec_ctx->codec->name, regex(
".*nvenc.*"))) {
2070 configure_nvenc(codec_ctx,
param);
2071 }
else if (strcmp(codec_ctx->codec->name,
"h264_omx") == 0) {
2072 if (
param->header_inserter_req == -1) {
2073 MSG(INFO,
"Auto-enabling header inserter for %s.\n",
2074 codec_ctx->codec->name);
2075 param->header_inserter_req = 1;
2077 }
else if (strcmp(codec_ctx->codec->name,
"h264_qsv") == 0 ||
2078 strcmp(codec_ctx->codec->name,
"hevc_qsv") == 0) {
2079 configure_qsv_h264_hevc(codec_ctx,
param);
2080 }
else if (strcmp(codec_ctx->codec->name,
"libaom-av1") == 0) {
2081 configure_aom_av1(codec_ctx,
param);
2082 }
else if (strcmp(codec_ctx->codec->name,
"librav1e") == 0) {
2083 configure_rav1e(codec_ctx,
param);
2084 }
else if (strcmp(codec_ctx->codec->name,
"libsvtav1") == 0) {
2085 configure_svt_av1(codec_ctx,
param);
2086 }
else if (strstr(codec_ctx->codec->name,
"libsvt") == codec_ctx->codec->name) {
2087 configure_svt_hevc_vp9(codec_ctx,
param);
2088 }
else if (strcmp(codec_ctx->codec->name,
"libopenh264") == 0) {
2089 configure_libopenh264(codec_ctx,
param);
2091 log_msg(
LOG_LEVEL_WARNING,
"[lavc] Warning: Unknown encoder %s. Using default configuration values.\n", codec_ctx->codec->name);
2096get_opt_default_value(
const AVOption *opt)
2098 switch (opt->type) {
2099 case AV_OPT_TYPE_FLOAT:
2100 case AV_OPT_TYPE_DOUBLE:
2101 return to_string(opt->default_val.dbl) +
" (float)";
2102 case AV_OPT_TYPE_CONST:
2103 case AV_OPT_TYPE_INT64:
2104 case AV_OPT_TYPE_INT:
2105 case AV_OPT_TYPE_BOOL:
2106 return to_string(opt->default_val.i64);
2107 case AV_OPT_TYPE_STRING:
2108 return opt->default_val.str ==
nullptr
2110 : string(
"\"") + opt->default_val.str +
"\"";
2120 bool dec_found =
true;
2122 dec_found = show_coder_help(
name,
false);
2125 ? avcodec_find_encoder_by_name(
name.c_str())
2126 : avcodec_find_decoder_by_name(
name.c_str());
2127 if (
codec ==
nullptr) {
2130 "Unable to find neither encoder nor decoder %s!\n",
2136 << (
encoder ?
"encoder" :
"decoder") <<
":\n";
2137 const auto *opt =
codec->priv_class->option;
2138 if (opt ==
nullptr) {
2141 while (opt->name !=
nullptr) {
2143 const char *indent =
"\t\t* ";
2144 if (opt->offset != 0) {
2145 default_val = get_opt_default_value(opt);
2146 if (!default_val.empty()) {
2147 default_val =
"default " + default_val;
2152 if (opt->help !=
nullptr && strlen(opt->help) > 0) {
2153 help_str = opt->help;
2155 if (!default_val.empty()) {
2156 if (help_str.find(
"default") == 0) {
2158 }
else if (!help_str.empty()) {
2162 if (!help_str.empty() || !default_val.empty()) {
2163 help_str =
" - "s + help_str;
2165 col() << indent <<
SBOLD(opt->name) << help_str << default_val <<
"\n";
2168 print_codec_aux_usage(
name);
2175print_codec_aux_usage(
string const &
name)
2177 if (
name ==
"libx264" ||
name ==
"libx265") {
2178 col() <<
"(options for " <<
SBOLD(
name.substr(3) <<
"-params") <<
" should be actually separated by '\\:', not ':' as indicated above)\n";
2180 if (
name ==
"hevc_qsv" ||
name ==
"h264_qsv") {
2181 col() <<
"\n\t- " <<
SBOLD(
"rc") <<
" - [UltraGrid specific] rate control mode: " <<
SBOLD(
"cbr") <<
", " <<
SBOLD(
"cqp") <<
", " <<
SBOLD(
"icq") <<
", " <<
SBOLD(
"qvbr") <<
" or " <<
SBOLD(
"vbr") <<
"\n";
2183 if (
name ==
"libsvtav1") {
2185 "separator (':') must be replaced with '\\:'.\n"
2186 "It is also recommended to consult its default value "
2187 "(see UG output for the encoder).\n");
2190 "\n\t - use SVT AV1 with default RC CRF 35\n");
2192 "\n\t - use SVT AV1 with CRF=30\n");
2194 "\n\t - use SVT AV1 with QP=30\n");
2196 "\n\t - use SVT AV1 with QP=35 and Maximum Bitrate 3 Mbps\n");
2198 "\n\t - use SVT AV1 in VBR mode with 3 Mbps (not "
2199 "recommended at the moment, increases latency)\n");
2203static void setparam_vp8_vp9(AVCodecContext *codec_ctx,
struct setparam_param *
param)
2205 codec_ctx->rc_buffer_size = codec_ctx->bit_rate /
param->desc.fps;
2212static void libavcodec_check_messages(
struct state_video_compress_libav *s)
2234 libavcodec_compress_init,
2236 libavcodec_compress_tile,
2241 get_libavcodec_module_info,
2246 libavcodec_compress_init,
2248 libavcodec_compress_tile,
struct video_frame * frame
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
const char * get_codec_name(codec_t codec)
codec_t get_codec_from_name(const char *name)
static _Bool parse_fmt(const char *cfg, PaTime *latency, int *input_device_idx, char device_name[static STR_LEN])
int color_printf(const char *format,...)
static __device__ vec2 clamp(const vec2 &v, float min_val, float max_val)
void log_msg(int level, const char *format,...)
void log_msg_once(int level, uint32_t id, const char *msg,...)
#define LOG_LEVEL_NOTICE
information that may be interesting
#define LOG_LEVEL_INFO
normal reporting
#define debug_file_dump(key, serialize, data)
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
#define LOG_LEVEL_FATAL
errors that prevent UG run
#define LOG_LEVEL_WARNING
less severe errors
steady_clock::duration duration
void module_init_default(struct module *module_data)
void module_register(struct module *module_data, struct module *parent)
void module_done(struct module *module_data)
#define VIDEO_COMPRESS_ABI_VERSION
const char * get_commandline_param(const char *key)
unsigned int cuda_devices[MAX_CUDA_DEVICES]
#define ADD_TO_PARAM(param, doc)
This file contains functions related to hw acceleration.
int vaapi_init(struct AVCodecContext *s, struct hw_accel_state *state, codec_t out_codec)
codec_t get_av_to_ug_codec(enum AVCodecID av_codec)
const char * lavc_thread_type_to_str(int thread_type)
enum AVCodecID get_ug_to_av_codec(codec_t ug_codec)
const char * get_avpixfmts_names(const enum AVPixelFormat *pixfmts)
void ug_set_av_logging()
Sets specified log level either given explicitly or from UG-wide log_level.
int av_pixfmt_get_subsampling(enum AVPixelFormat fmt)
bool libav_codec_has_extradata(codec_t codec)
void print_libav_error(int verbosity, const char *msg, int rc)
#define AV_CODEC_CAP_OTHER_THREADS
void serialize_video_avframe(const void *f, FILE *out)
@ LIBRARY_CLASS_VIDEO_COMPRESS
#define REGISTER_HIDDEN_MODULE(name, info, lclass, abi)
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
#define DEFAULT_NVENC_RC_BUF_SIZE_FACTOR
#define DEFAULT_X26X_RC_BUF_SIZE_FACTOR
#define snprintf_ch(str,...)
shortcut for snprintf(var, sizeof var...), var must be a char array
#define IF_NOT_UNDEF_ELSE(val, default_val)
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
#define to_fourcc(a, b, c, d)
Creates FourCC word.
@ STR_LEN
"standard" string length placeholder
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct message * check_message(struct module *mod)
#define RESPONSE_INT_SERV_ERR
double unit_evaluate_dbl(const char *str, bool case_sensitive, const char **endptr)
long long unit_evaluate(const char *str, const char **endptr)
const char * format_in_si_units(unsigned long long int val)
#define NALU_HDR_GET_TYPE(nal, is_hevc)
const unsigned char * rtpenc_get_next_nal(const unsigned char *start, long len, const unsigned char **endptr)
const unsigned char * rtpenc_get_first_nal(const unsigned char *src, long src_len, bool hevc)
#define H264_NAL_SEI_PREFIX
#define UG_ORIG_FORMAT_ISO_IEC_11578_GUID
custom orig format byte syntax - highest 1 bit zero, next 2 bits (depth-8)/2, next 3 bits subsampling...
#define HEVC_NAL_SEI_PREFIX
void replace_all(char *in, const char *from, const char *to)
Replaces all occurencies of 'from' to 'to' in string 'in'.
const char * name
displayed name
std::vector< codec > codecs
std::vector< module_option > opts
char * data
Raw tile data. Pointer must be at least 4B aligned.
unsigned int data_len
length of the data
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
void to_lavc_vid_conv_destroy(struct to_lavc_vid_conv **s_p)
int get_available_pix_fmts(codec_t in_codec, struct to_lavc_req_prop req_prop, enum AVPixelFormat fmts[AV_PIX_FMT_NB])
struct AVFrame * to_lavc_vid_conv(struct to_lavc_vid_conv *s, char *in_data)
struct to_lavc_vid_conv * to_lavc_vid_conv_init(codec_t in_pixfmt, int width, int height, enum AVPixelFormat out_pixfmt, int thread_count)
void get_av_pixfmt_details(enum AVPixelFormat av_codec, enum AVColorSpace *colorspace, enum AVColorRange *color_range)
#define TO_LAVC_REQ_PROP_INIT
static time_ns_t get_time_in_ns()
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
@ VIDEO_CODEC_NONE
dummy color spec
@ PRORES
abstract Apple ProRes, must not be used in transmit
@ MJPG
JPEG image, without restart intervals.
T get_map_val_or_default(std::map< key, T > const &map, key const &k, T const &def)
char * wrap_paragraph(char *text)
This is an umbrella header for video functions.
struct pixfmt_desc get_pixfmt_desc(codec_t pixfmt)
bool codec_is_a_rgb(codec_t codec)
Returns TRUE if specified pixelformat is some form of RGB (not YUV).
int get_bits_per_component(codec_t codec)
static const struct codec_info_t codec_info[]
codec_t get_codec_from_fcc(uint32_t fourcc)
API for video compress drivers.
static void check_duration(struct state_libavcodec_decompress *s, double duration_total_sec, double duration_pixfmt_change_sec)
print hint to improve performance if not making it
static int check_av_opt_set(void *state, const char *key, const char *val)
static const struct video_decompress_info libavcodec_info
bool video_desc_eq_excl_param(struct video_desc a, struct video_desc b, unsigned int excluded_params)
Compares two video descriptions.
void vf_store_metadata(const struct video_frame *f, void *s)
void vf_restore_metadata(struct video_frame *f, void *s)