UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
libavcodec.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-2024 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#define __STDC_CONSTANT_MACROS
39
40#include <array>
41#include <cassert>
42#include <cinttypes>
43#include <cmath>
44#include <cstdint>
45#include <cstring> // for strcmp, strlen, strstr, strchr
46#include <list>
47#include <map>
48#include <regex>
49#include <set>
50#include <stdexcept>
51#include <string>
52#include <thread>
53#include <type_traits>
54#include <vector>
55
56#include "config.h"
57#include "debug.h"
58#include "host.h"
59#include "lib_common.h"
63#include "messaging.h"
64#include "module.h"
65#include "rtp/rtpdec_h264.h"
66#include "rtp/rtpenc_h264.h"
67#include "tv.h"
68#include "ug_runtime_error.hpp"
69#include "utils/color_out.h"
70#include "utils/macros.h"
71#include "utils/misc.h"
72#include "utils/string.h" // replace_all
73#include "utils/text.h"
74#include "video.h"
75#include "video_compress.h"
76
77#ifdef HWACC_VAAPI
78extern "C"
79{
80#include <libavutil/hwcontext.h>
81#include <libavutil/hwcontext_vaapi.h>
82}
84#endif
85
86#ifdef HAVE_SWSCALE
87extern "C"{
88#include <libswscale/swscale.h>
89}
90#endif
91
92#define MOD_NAME "[lavc] "
93
94using std::array;
95using std::clamp;
96using std::cout;
97using std::function;
98using std::list;
99using std::invalid_argument;
100using std::map;
101using std::min;
102using std::regex;
103using std::set;
104using std::shared_ptr;
105using std::stof;
106using std::stoi;
107using std::string;
108using std::thread;
109using std::to_string;
110using namespace std::string_literals;
111
112// NOLINTNEXTLINE(*-macro-usage): for correct TOSTRING expansion
113#define DEFAULT_X26X_RC_BUF_SIZE_FACTOR 2.5
114#define DEFAULT_NVENC_RC_BUF_SIZE_FACTOR 1.5 // NOLINT: ditto
115
116namespace {
117enum {
118 FLW_THRESH = 1920 * 1080 * 30, //< in px/sec
119 FLW_UHD_60 = 3840 * 2160 * 60,
120 HOUSEKEEP_INTERVAL = 100, //< for metadata_storage
121};
122
123constexpr const codec_t DEFAULT_CODEC = MJPG;
124constexpr const int DEFAULT_GOP_SIZE = 20;
125constexpr int DEFAULT_SLICE_COUNT = 32;
126
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";
140
141double
142get_default_crf(const char *codec_name)
143{
144 if (strstr(codec_name, "libx26") == codec_name) {
145 return 22.0;
146 }
147 if (strcmp(codec_name, "libsvtav1") == 0) {
148 return 35.0; // 35 is libsvtav1 default
149 }
150 return 0;
151}
152
153struct setparam_param {
154 setparam_param(map<string, string> &lo, set<string> &bo) : lavc_opts(lo), blacklist_opts(bo) {}
155 struct video_desc desc {};
156 bool have_preset = false;
157 int periodic_intra = -1;
158 int interlaced_dct = -1;
159 int header_inserter_req = -1;
160 string thread_mode;
161 int slices = -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;
168};
169
170typedef struct {
171 function<const char*(bool)> get_prefered_encoder;
172 double avg_bpp;
173 void (*set_param)(AVCodecContext *, struct setparam_param *);
174 int capabilities_priority;
175} codec_params_t;
176
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);
184
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);
190
191static map<codec_t, codec_params_t> codec_params = {
192 { H264, codec_params_t{
193 [](bool is_rgb) { return is_rgb ? "libx264rgb" : "libx264"; },
194 0.07 * 2 /* for H.264: 1 - low motion, 2 - medium motion, 4 - high motion */
195 * 2, // take into consideration that our H.264 is less effective due to specific preset/tune
196 // note - not used for libx264, which uses CRF by default
197 setparam_h264_h265_av1,
198 100
199 }},
200 { H265, codec_params_t{
201 [](bool) { return "libx265"; },
202 0.04 * 2 * 2, // note - not used for libx265, which uses CRF by default
203 setparam_h264_h265_av1,
204 101
205 }},
206 { MJPG, codec_params_t{
207 nullptr,
208 1.2,
209 setparam_jpeg,
210 102
211 }},
212 { J2K, codec_params_t{
213 nullptr,
214 1.0,
215 setparam_default,
216 500
217 }},
218 { VP8, codec_params_t{
219 nullptr,
220 0.4,
221 setparam_vp8_vp9,
222 103
223 }},
224 { VP9, codec_params_t{
225 nullptr,
226 0.4,
227 setparam_vp8_vp9,
228 104
229 }},
230 { HFYU, codec_params_t{
231 nullptr,
232 0,
233 setparam_default,
234 501
235 }},
236 { FFV1, codec_params_t{
237 nullptr,
238 0,
239 setparam_default,
240 502
241 }},
242 { AV1, codec_params_t{
243 [](bool) { return is_arm_mac() ? "libaom-av1" : "libsvtav1"; },
244 0.1,
245 setparam_h264_h265_av1,
246 600
247 }},
248 { PRORES, codec_params_t{
249 nullptr,
250 0.5,
251 setparam_default,
252 300,
253 }},
254};
255
256struct aux_header {
257 char buf[1024]{};
258 size_t buf_len = 0;
259};
260
261struct state_video_compress_libav {
262 state_video_compress_libav(struct module *parent) {
263 module_init_default(&module_data);
264 module_data.cls = MODULE_CLASS_DATA;
265 module_data.priv_data = this;
266 module_data.deleter = libavcodec_compress_done;
267 module_register(&module_data, parent);
268 }
269 ~state_video_compress_libav() {
270 av_packet_free(&pkt);
271 to_lavc_vid_conv_destroy(&pixfmt_conversion);
272 }
273
274 struct module module_data;
275
276 struct video_desc saved_desc{};
277 struct to_lavc_vid_conv *pixfmt_conversion = nullptr;
278 AVPacket *pkt = av_packet_alloc();
279 // for every core - parts of the above
280 AVCodecContext *codec_ctx = nullptr;
281 int64_t cur_pts = 0;
282
283 codec_t requested_codec_id = VIDEO_CODEC_NONE;
284 struct to_lavc_req_prop req_conv_prop{ TO_LAVC_REQ_PROP_INIT };
285 bool store_orig_format = false;
286 struct aux_header aux_header;
287
288 struct video_desc compressed_desc{};
289
290 struct setparam_param params{lavc_opts, blacklist_opts};
291 string req_encoder;
292 int requested_gop = DEFAULT_GOP_SIZE;
293
294 map<string, string> lavc_opts;
295 set<string> blacklist_opts;
296
297 bool hwenc = false;
298 AVFrame *hwframe = nullptr;
299
300#ifdef HAVE_SWSCALE
301 struct SwsContext *sws_ctx = nullptr;
302 AVFrame *sws_frame = nullptr;
303#endif
304
305 int conv_thread_count = clamp<unsigned int>(thread::hardware_concurrency(), 1, INT_MAX);
306
307 double mov_avg_comp_duration = 0;
308 long mov_avg_frames = 0;
309 time_ns_t duration_warn_last_print = 0;
310 int64_t max_pts_diff_reported = 0;
311
312 map<int64_t, char[VF_METADATA_SIZE]> metadata_storage;
313};
314
315struct codec_encoders_decoders{
316 std::vector<std::string> encoders;
317 std::vector<std::string> decoders;
318};
319
320enum incomp_feature {
321 INCOMP_DEPTH,
322 INCOMP_INTERLACED_DCT,
323 INCOMP_INTRA_REFRESH,
324 INCOMP_SUBSAMPLING,
325};
326void incomp_feature_warn(enum incomp_feature f, int req_val);
327
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;
332 void *i = 0;
333 while ((codec = av_codec_iterate(&i))) {
334 if (av_codec_is_encoder(codec) && codec->id == id) {
335 res.encoders.emplace_back(codec->name);
336 }
337 if (av_codec_is_decoder(codec) && codec->id == id) {
338 res.decoders.emplace_back(codec->name);
339 }
340 }
341#else
342 const AVCodec *codec = nullptr;
343 if ((codec = avcodec_find_encoder(id))) {
344 do {
345 if (av_codec_is_encoder(codec) && codec->id == id) {
346 res.encoders.emplace_back(codec->name);
347 }
348 } while ((codec = av_codec_next(codec)));
349 }
350
351 if ((codec = avcodec_find_decoder(id))) {
352 do {
353 if (av_codec_is_decoder(codec) && codec->id == id) {
354 res.decoders.emplace_back(codec->name);
355 }
356 } while ((codec = av_codec_next(codec)));
357 }
358#endif
359
360 return res;
361}
362
363static void get_codec_details(AVCodecID id, char *buf, size_t buflen)
364{
365 auto info = get_codec_encoders_decoders(id);
366 assert(buflen > 0);
367 buf[0] = '\0';
368 if(info.encoders.empty() && info.decoders.empty())
369 return;
370
371 strncat(buf, " (", buflen - strlen(buf) - 1);
372 if (!info.encoders.empty()) {
373 strncat(buf, TERM_BOLD "encoders:" TERM_RESET, buflen - strlen(buf) - 1);
374 for(const auto& enc : info.encoders){
375 strncat(buf, " ", buflen - strlen(buf) - 1);
376 strncat(buf, enc.c_str(), buflen - strlen(buf) - 1);
377 }
378 }
379 if (!info.decoders.empty()) {
380 if (!info.encoders.empty()) {
381 strncat(buf, "; ", buflen - strlen(buf) - 1);
382 }
383 strncat(buf, TERM_BOLD "decoders:" TERM_RESET, buflen - strlen(buf) - 1);
384
385 for(const auto& dec : info.decoders){
386 strncat(buf, " ", buflen - strlen(buf) - 1);
387 strncat(buf, dec.c_str(), buflen - strlen(buf) - 1);
388 }
389 }
390 strncat(buf, ")", buflen - strlen(buf) - 1);
391}
392
393void usage(bool full) {
394 printf("Libavcodec encoder usage:\n");
395 col() << "\t" SBOLD(SRED("-c libavcodec")
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";
426 if (full) {
427 col() << "\t" << SBOLD("header_inserter[=no]")
428 << " repeat H.264/HEVC VPS/SPS/PPS hdrs (fixes problems "
429 "when not "
430 "contained in the stream)\n";
431 }
432 col() << "\nSupported codecs:\n";
433 for (auto && param : codec_params) {
434 enum AVCodecID avID = get_ug_to_av_codec(param.first);
435 if (avID == AV_CODEC_ID_NONE) { // old FFMPEG -> codec id is flushed to 0 in compat
436 continue;
437 }
438 char avail[1024];
439 const AVCodec *codec;
440 if ((codec = avcodec_find_encoder(avID))) {
441 strcpy(avail, "available");
442 } else {
443 strcpy(avail, "not available");
444 }
445 get_codec_details(avID, avail + strlen(avail), sizeof avail - strlen(avail));
446 col() << "\t" << SBOLD(get_codec_name(param.first)) << " - " << avail << "\n";
447
448 }
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";
452 col() << "\n";
453 col() << "Libavcodec version (linked): " << SBOLD(LIBAVCODEC_IDENT) << "\n";
454 const char *swscale = "no";
455#ifdef HAVE_SWSCALE
456 swscale = "yes";
457#endif
458 col() << "Libswscale supported: " << SBOLD(swscale) << "\n";
459}
460
470void
471handle_help(bool full, string const &req_encoder, string const &req_codec)
472{
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");
477 return;
478 }
479 const auto *codec =
480 avcodec_find_encoder_by_name(req_encoder.c_str());
481 if (codec != nullptr) {
482 cout << "\n";
483 print_codec_supp_pix_fmts(codec->pix_fmts);
484 } else {
485 MSG(ERROR, "Cannot open encoder: %s\n",
486 req_encoder.c_str());
487 }
488 return;
489 }
490 if (!req_encoder.empty()) {
491 show_coder_help(req_encoder);
492 return;
493 }
494 usage(full);
495}
496
497double
498ranged_stod(const char *val, double min, double max) noexcept(false)
499{
500 const double dbl = std::stod(val);
501 if (dbl < min || dbl > max) {
502 throw ug_runtime_error(
503 string("Value ") + val + " outside of valid range [" +
504 to_string(min) + "," + to_string(max) + "]");
505 }
506 return dbl;
507}
508
509int
510parse_fmt(struct state_video_compress_libav *s, char *fmt) noexcept(false)
511{
512 if (!fmt) {
513 return 0;
514 }
515
516 enum {
517 HELP_NONE,
518 HELP_NORMAL,
519 HELP_FULL,
520 } show_help = HELP_NONE;
521
522 // replace all '\:' with 2xDEL
524 char *item, *save_ptr = NULL;
525
526 while ((item = strtok_r(fmt, ":", &save_ptr)) != NULL) {
527 if (strcasecmp("help", item) == 0 || strcmp(item, "fullhelp") == 0) {
528 show_help = strcmp(item, "fullhelp") == 0 ? HELP_FULL
529 : HELP_NORMAL;
530 } else if (IS_KEY_PREFIX(item, "codec")) {
531 const char *const codec = strchr(item, '=') + 1;
532 s->requested_codec_id = get_codec_from_name(codec);
533 if (s->requested_codec_id == VIDEO_CODEC_NONE) {
534 log_msg(LOG_LEVEL_ERROR, "[lavc] Unable to find codec: \"%s\"\n", codec);
535 return -1;
536 }
537 } else if (IS_KEY_PREFIX(item, "encoder")) {
538 s->req_encoder = strchr(item, '=') + 1;
539 } else if (IS_KEY_PREFIX(item, "bitrate")) {
540 s->params.requested_bitrate =
541 unit_evaluate(strchr(item, '=') + 1, nullptr);
542 if (s->params.requested_bitrate < 0) {
543 return -1;
544 }
545 } else if(strncasecmp("bpp=", item, strlen("bpp=")) == 0) {
546 char *bpp_str = item + strlen("bpp=");
547 s->params.requested_bpp =
548 unit_evaluate_dbl(bpp_str, false, nullptr);
549 if (std::isnan(s->params.requested_bpp)) {
550 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Wrong bitrate: " << bpp_str << "\n";
551 return -1;
552 }
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);
556 } else if (strstr(item, "cqp=") == item || strstr(item, "q=") == item) {
557 if (strstr(item, "q=") == item) {
558 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Option \"q=\" is deprecated, use \"cqp=\" instead.\n");
559 }
560 s->params.requested_cqp = stoi(strchr(item, '=') + 1);
561 } else if (IS_KEY_PREFIX(item, "subsampling")) {
562 s->req_conv_prop.subsampling =
563 atoi(strchr(item, '=') + 1);
564 if (s->req_conv_prop.subsampling < 1000) {
565 s->req_conv_prop.subsampling *= 10; // 420->4200
566 }
567 if (s->req_conv_prop.subsampling != 4440 &&
568 s->req_conv_prop.subsampling != 4220 &&
569 s->req_conv_prop.subsampling != 4200) {
570 log_msg(LOG_LEVEL_ERROR, "[lavc] Supported subsampling is 444, 422, or 420.\n");
571 return -1;
572 }
573 } else if (IS_KEY_PREFIX(item, "depth")) {
574 s->req_conv_prop.depth = atoi(strchr(item, '=') + 1);
575 } else if (strcasecmp(item, "rgb") == 0 || strcasecmp(item, "yuv") == 0) {
576 s->req_conv_prop.rgb = strcasecmp(item, "rgb") == 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;
581 } else if (IS_KEY_PREFIX(item, "threads")) {
582 char *threads = strchr(item, '=') + 1;
583 if (strchr(threads, ',')) {
584 s->conv_thread_count = stoi(strchr(threads, ',') + 1);
585 *strchr(threads, ',') = '\0';
586 }
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;
601 s->req_conv_prop.depth = 8;
602 s->req_conv_prop.subsampling = SUBS_420;
603 } else if (strchr(item, '=')) {
604 char *c_val_dup = strdup(strchr(item, '=') + 1);
605 replace_all(c_val_dup, DELDEL, ":");
606 string key, val;
607 key = string(item, strchr(item, '='));
608 s->lavc_opts[key] = c_val_dup;
609 free(c_val_dup);
610 } else {
611 log_msg(LOG_LEVEL_ERROR, "[lavc] Error: unknown option %s.\n",
612 item);
613 return -1;
614 }
615 fmt = NULL;
616 }
617
618 const string req_codec =
619 get_commandline_param("lavc-use-codec") != nullptr
620 ? get_commandline_param("lavc-use-codec")
621 : "";
622 if (show_help != HELP_NONE || req_codec == "help") {
623 handle_help(show_help == HELP_FULL, s->req_encoder, req_codec);
624 return 1;
625 }
626
627 if (get_commandline_param("keep-pixfmt") != nullptr) {
628 s->store_orig_format = true;
629 }
630
631 return 0;
632}
633
634static compress_module_info get_libavcodec_module_info(){
635 compress_module_info module_info;
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});
639 module_info.opts.emplace_back(module_option{"Disable intra refresh",
640 "Do not use Periodic Intra Refresh (H.264/H.265)", "",
641 "disable_intra_refresh", ":disable_intra_refresh", true});
642 module_info.opts.emplace_back(module_option{"Subsampling",
643 "may be one of 444, 422, or 420, default 420 for progresive, 422 for interlaced",
644 "422",
645 "subsampling", ":subsampling=", false});
646 module_info.opts.emplace_back(module_option{"Lavc opt",
647 "arbitrary option to be passed directly to libavcodec (eg. preset=veryfast), eventual colons must be backslash-escaped (eg. for x264opts)",
648 "",
649 "lavc_opt", ":", false});
650
651 for (const auto& param : codec_params) {
652 enum AVCodecID avID = get_ug_to_av_codec(param.first);
653 if (avID == AV_CODEC_ID_NONE) { // old FFMPEG -> codec id is flushed to 0 in compat
654 continue;
655 }
656 const AVCodec *i;
657 if (!(i = avcodec_find_encoder(avID))) {
658 continue;
659 }
660
663 codec_info.priority = param.second.capabilities_priority;
664 codec_info.encoders.emplace_back(
665 encoder{"default", ":codec=" + codec_info.name});
666
667 auto coders = get_codec_encoders_decoders(avID);
668 for(const auto& enc : coders.encoders){
669 codec_info.encoders.emplace_back(
670 encoder{enc, ":encoder=" + enc});
671 }
672
673 module_info.codecs.emplace_back(std::move(codec_info));
674 }
675
676 return module_info;
677}
678
679ADD_TO_PARAM("keep-pixfmt",
680 "* keep-pixfmt\n"
681 " Signalize input pixel format to reciever and try\n");
682struct module * libavcodec_compress_init(struct module *parent, const char *opts)
683{
685#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(58, 9, 100)
686 /* register all the codecs (you can also register only the codec
687 * you wish to have smaller code */
688 avcodec_register_all();
689#endif
690
691 char *fmt = strdup(opts);
692 struct state_video_compress_libav *s = new state_video_compress_libav(parent);
693 int ret = -1;
694 try {
695 ret = parse_fmt(s, fmt);
696 } catch (invalid_argument &e) {
697 MSG(ERROR, "Non-numeric argument presented for an option requiring a "
698 "number!\n");
699 }
700 free(fmt);
701 if (ret != 0) {
702 module_done(&s->module_data);
703 return ret > 0 ? static_cast<module*>(INIT_NOERR) : NULL;
704 }
705
706 return &s->module_data;
707}
708
709#ifdef HWACC_VAAPI
710static int vaapi_init(struct AVCodecContext *s){
711
712 int pool_size = 20; //Default in ffmpeg examples
713
714 AVBufferRef *device_ref = nullptr;
715 AVBufferRef *hw_frames_ctx = nullptr;
716 int ret = create_hw_device_ctx(AV_HWDEVICE_TYPE_VAAPI, &device_ref);
717 if(ret < 0)
718 goto fail;
719
720 if (s->active_thread_type & FF_THREAD_FRAME)
721 pool_size += s->thread_count;
722
723 ret = create_hw_frame_ctx(device_ref,
724 s->width,
725 s->height,
726 AV_PIX_FMT_VAAPI,
727 AV_PIX_FMT_NV12,
728 pool_size,
729 &hw_frames_ctx);
730 if(ret < 0)
731 goto fail;
732
733 s->hw_frames_ctx = hw_frames_ctx;
734
735 av_buffer_unref(&device_ref);
736 return 0;
737
738fail:
739 av_buffer_unref(&hw_frames_ctx);
740 av_buffer_unref(&device_ref);
741 return ret;
742}
743#endif
744
745void print_codec_supp_pix_fmts(const enum AVPixelFormat *first) {
746 char out[STR_LEN];
747 snprintf(out, sizeof out,
748 MOD_NAME "Codec supported pixel formats: " TBOLD("%s"),
751}
752
753void print_pix_fmts(const list<enum AVPixelFormat>
754 &req_pix_fmts, const enum AVPixelFormat *first) {
755 print_codec_supp_pix_fmts(first);
756 char out[STR_LEN] = MOD_NAME "Supported pixel formats:" TERM_BOLD;
757 for (auto &c : req_pix_fmts) {
758 snprintf(out + strlen(out), sizeof out - strlen(out), " %s",
759 av_get_pix_fmt_name(c));
760 }
762}
763
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)
778{
779 if(codec_pix_fmts == NULL)
780 return AV_PIX_FMT_NONE;
781
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) {
786 if (fmt == *it) {
787 enum AVPixelFormat ret = *it++;
788 return ret;
789 }
790 }
791 }
792
793 return AV_PIX_FMT_NONE;
794}
795
796template<typename T, bool log_err = false>
797static inline bool check_av_opt_set(void *priv_data, const char *key, T val, const char *desc = nullptr) {
798 string val_str;
799 if constexpr (std::is_same_v<T, char *> ||
800 std::is_same_v<T, const char *>) {
801 val_str = val;
802 } else {
803 val_str = to_string(val);
804 }
805 desc = desc ? desc : key;
806 const int ret = av_opt_set(priv_data, key, val_str.c_str(), 0);
807 if (ret != 0) {
808 string err = string(MOD_NAME) + "Unable to set " + desc + " to " + val_str;
809 print_libav_error(log_err ? LOG_LEVEL_ERROR : LOG_LEVEL_WARNING, err.c_str(), ret);
810 return false;
811 }
812 log_msg(LOG_LEVEL_INFO, MOD_NAME "Setting codec parameter %s to %s\n",
813 desc, val_str.c_str());
814 return true;
815}
816
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;
825 } else {
826 cqp = DEFAULT_CQP;
827 }
828 }
829 codec_ctx->flags |= AV_CODEC_FLAG_QSCALE;
830
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;
838 LOG(LOG_LEVEL_INFO) << MOD_NAME "Setting QSV global_quality to " << cqp << "\n";
839 } else {
840 check_av_opt_set<int, true>(codec_ctx->priv_data, "qp", cqp,
841 "CQP");
842 }
843}
844
845bool set_codec_ctx_params(struct state_video_compress_libav *s, AVPixelFormat pix_fmt, struct video_desc desc, codec_t ug_codec)
846{
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;
849
850 // make a copy because set_param callbacks may adjust parameters
851 struct setparam_param params = s->params;
852
853 // average bit per pixel
854 const double avg_bpp = params.requested_bpp > 0.0
855 ? params.requested_bpp
856 : codec_params[ug_codec].avg_bpp;
857
858 bool set_bitrate = false;
859 int_fast64_t bitrate =
860 params.requested_bitrate > 0
861 ? params.requested_bitrate
862 : (long long) (desc.width * desc.height * avg_bpp * desc.fps);
863
864 s->codec_ctx->strict_std_compliance = -2;
865
866 // set quality
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
877 ? params.requested_crf
878 : get_default_crf(s->codec_ctx->codec->name);
879 check_av_opt_set<double, true>(s->codec_ctx->priv_data, "crf",
880 crf, "CRF");
881 } else if (strcmp(s->codec_ctx->codec->name, "libopenh264") != 0) {
882 set_bitrate = true;
883 }
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;
887 LOG(LOG_LEVEL_INFO) << MOD_NAME << "Setting bitrate to " << format_in_si_units(bitrate) << "bps.\n";
888 }
889
890 /* resolution must be a multiple of two */
891 s->codec_ctx->width = desc.width;
892 s->codec_ctx->height = desc.height;
893 /* frames per second */
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;
897
898 s->codec_ctx->pix_fmt = pix_fmt;
899 s->codec_ctx->bits_per_raw_sample = min<int>(get_bits_per_component(ug_codec), av_pix_fmt_desc_get(pix_fmt)->comp[0].depth);
900
901 codec_params[ug_codec].set_param(s->codec_ctx, &params);
902 set_codec_thread_mode(s->codec_ctx, &params);
903 s->codec_ctx->slices = IF_NOT_UNDEF_ELSE(
904 params.slices, s->codec_ctx->codec_id == AV_CODEC_ID_FFV1
905 ? 16
906 : DEFAULT_SLICE_COUNT);
907
908 // set user supplied parameters
909 for (auto const &item : s->lavc_opts) {
910 if (s->blacklist_opts.count(item.first) == 1) {
911 continue;
912 }
914 s->codec_ctx->priv_data, item.first.c_str(), item.second.c_str())) {
915 return false;
916 }
917 }
918
919 return true;
920}
921
922ADD_TO_PARAM("lavc-use-codec",
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,
932 struct to_lavc_req_prop req_conv_prop) {
933 if (get_commandline_param("lavc-use-codec")) {
934 const char *val = get_commandline_param("lavc-use-codec");
935 enum AVPixelFormat fmt = av_get_pix_fmt(val);
936 if (fmt != AV_PIX_FMT_NONE) {
937 return { fmt };
938 }
939 req_conv_prop.force_conv_to = get_codec_from_name(val);
940 if (!req_conv_prop.force_conv_to) {
941 LOG(LOG_LEVEL_FATAL) << MOD_NAME << "Wrong codec string: " << val << ".\n";
942 exit_uv(1);
943 return {};
944 }
945 }
946
947 enum AVPixelFormat pixfmts[AV_PIX_FMT_NB];
948 int nb_fmts = get_available_pix_fmts(in_codec, req_conv_prop, pixfmts);
949 return { pixfmts, pixfmts + nb_fmts };
950}
951
952void apply_blacklist([[maybe_unused]] list<enum AVPixelFormat> &formats, [[maybe_unused]] const char *encoder_name) {
953#if X2RGB10LE_PRESENT
954 // blacklist AV_PIX_FMT_X2RGB10LE for NVENC - with current FFmpeg (13d04e3), it produces 10-bit 4:2:0 YUV (FF
955 // macro IS_YUV444 and IS_GBRP should contain the codec - if set 1st one, picture is ok 444 YUV, second produces
956 // incorrect colors). Anyways, even for the case #1 it is perhaps better to keep it blacklisted to allow
957 // selection of gbrp16, which doesn't convert to YUV.
958 if (strstr(encoder_name, "nvenc") != nullptr ||
959 strstr(encoder_name, "qsv") != nullptr) {
960 if (formats.size() == 1) {
961 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Only one codec remaining, not blacklisting x2rgb10le!\n";
962 return;
963 }
964 if (auto it = std::find(formats.begin(), formats.end(), AV_PIX_FMT_X2RGB10LE); it != formats.end()) {
965 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Blacklisting x2rgb10le because there has been issues with this pixfmt "
966 "and current encoder (" << encoder_name << ") , use '--param lavc-use-codec=x2rgb10le' to enforce.\n";
967 formats.erase(it);
968 }
969 }
970#endif
971}
972
973static bool try_open_codec(struct state_video_compress_libav *s,
974 AVPixelFormat &pix_fmt,
975 struct video_desc desc,
977 const AVCodec *codec)
978{
979 // avcodec_alloc_context3 allocates context and sets default value
980 s->codec_ctx = avcodec_alloc_context3(codec);
981 if (!s->codec_ctx) {
982 log_msg(LOG_LEVEL_ERROR, "Could not allocate video codec context\n");
983 return false;
984 }
985
986 if (!set_codec_ctx_params(s, pix_fmt, desc, ug_codec)) {
987 avcodec_free_context(&s->codec_ctx);
988 s->codec_ctx = NULL;
989 return false;
990 }
991
992 log_msg(LOG_LEVEL_VERBOSE, "[lavc] Trying pixfmt: %s\n", av_get_pix_fmt_name(pix_fmt));
993#ifdef HWACC_VAAPI
994 if (pix_fmt == AV_PIX_FMT_VAAPI){
995 int ret = vaapi_init(s->codec_ctx);
996 if (ret != 0) {
997 avcodec_free_context(&s->codec_ctx);
998 s->codec_ctx = NULL;
999 return false;
1000 }
1001 s->hwenc = true;
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;
1005 log_msg(LOG_LEVEL_INFO, MOD_NAME "Using VA-API with sw format %s\n", av_get_pix_fmt_name(pix_fmt));
1006 }
1007#endif
1008
1009 if (const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get(pix_fmt)) { // defaults
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;
1012 }
1013 get_av_pixfmt_details(pix_fmt, &s->codec_ctx->colorspace, &s->codec_ctx->color_range);
1014
1015 /* open it */
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));
1019 return false;
1020 }
1021
1022 return true;
1023}
1024
1025const AVCodec *get_av_codec(struct state_video_compress_libav *s, codec_t *ug_codec, bool src_rgb) {
1026 // Open encoder specified by user if given
1027 if (!s->req_encoder.empty()) {
1028 const AVCodec *codec =
1029 avcodec_find_encoder_by_name(s->req_encoder.c_str());
1030 if (!codec) {
1031 log_msg(LOG_LEVEL_ERROR, "[lavc] Warning: requested encoder \"%s\" not found!\n",
1032 s->req_encoder.c_str());
1033 return nullptr;
1034 }
1035 if (s->requested_codec_id != VIDEO_CODEC_NONE && s->requested_codec_id != get_av_to_ug_codec(codec->id)) {
1036 MSG(ERROR,
1037 "Encoder \"%s\" doesn't encode requested codec!\n",
1038 s->req_encoder.c_str());
1039 return nullptr;
1040 }
1042 if (*ug_codec == VIDEO_CODEC_NONE) {
1043 log_msg(LOG_LEVEL_WARNING, "[lavc] Requested encoder not supported in UG!\n");
1044 return nullptr;
1045 }
1046 return codec;
1047 }
1048
1049 // Else, try to open prefered encoder for requested codec
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(
1052 src_rgb);
1053 const AVCodec *codec = avcodec_find_encoder_by_name(prefered_encoder);
1054 if (!codec) {
1055 log_msg(LOG_LEVEL_WARNING, "[lavc] Warning: prefered encoder \"%s\" not found! Trying default encoder.\n",
1056 prefered_encoder);
1057 }
1058 return codec;
1059 }
1060 // Finally, try to open any encoder for requested codec
1061 return avcodec_find_encoder(get_ug_to_av_codec(*ug_codec));
1062}
1063
1064static bool configure_swscale(struct state_video_compress_libav *s, struct video_desc desc, enum AVPixelFormat sws_out_pixfmt) {
1065#ifndef HAVE_SWSCALE
1066 UNUSED(s), UNUSED(desc), UNUSED(sws_out_pixfmt);
1067 return false;
1068#else
1069 //get all AVPixelFormats we can convert to and pick the first
1070 enum AVPixelFormat pixfmts[AV_PIX_FMT_NB];
1071 int nb_fmts = get_available_pix_fmts(desc.color_spec, s->req_conv_prop, pixfmts);
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));
1074 if ((s->pixfmt_conversion = to_lavc_vid_conv_init(desc.color_spec, desc.width, desc.height, sws_in_format, s->conv_thread_count)) == nullptr) {
1075 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Failed to get sws input conversion.\n"); // shouldn't happen normally, but user may choose imposible codec
1076 return false;
1077 }
1078
1079 s->sws_ctx = getSwsContext(desc.width,
1080 desc.height,
1081 sws_in_format,
1082 desc.width,
1083 desc.height,
1084 sws_out_pixfmt,
1085 SWS_POINT);
1086 if(!s->sws_ctx){
1087 log_msg(LOG_LEVEL_ERROR, "[lavc] Unable to init sws context.\n");
1088 return false;
1089 }
1090
1091 s->sws_frame = av_frame_alloc();
1092 if (!s->sws_frame) {
1093 log_msg(LOG_LEVEL_ERROR, "Could not allocate sws frame\n");
1094 return false;
1095 }
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) {
1102 log_msg(LOG_LEVEL_ERROR, "Could not allocate raw picture buffer for sws\n");
1103 return false;
1104 }
1105
1106 log_msg(LOG_LEVEL_NOTICE, "[lavc] Using swscale to convert %s to %s.\n",
1107 av_get_pix_fmt_name(sws_in_format),
1108 av_get_pix_fmt_name(sws_out_pixfmt));
1109 return true;
1110#endif //HAVE_SWSCALE
1111}
1112
1113AVPixelFormat
1114try_open_remaining_pixfmts(state_video_compress_libav *s, video_desc desc,
1115 codec_t ug_codec, const AVCodec *codec,
1116 set<AVPixelFormat> const &fmts_tried)
1117{
1118#ifndef HAVE_SWSCALE
1119 return AV_PIX_FMT_NONE;
1120#endif
1121 unsigned usable_fmt_cnt = 0;
1122 if (codec->pix_fmts == nullptr) {
1123 return AV_PIX_FMT_NONE;
1124 }
1125 for (const auto *pix = codec->pix_fmts; *pix != AV_PIX_FMT_NONE;
1126 ++pix) {
1127 usable_fmt_cnt += 1;
1128 }
1129 if (usable_fmt_cnt == fmts_tried.size()) {
1130 return AV_PIX_FMT_NONE; // no format to try
1131 }
1132 LOG(LOG_LEVEL_WARNING) << MOD_NAME "No direct decoder format for: "
1134 << ". Trying to convert with swscale instead.\n";
1135 for (const auto *pix = codec->pix_fmts; *pix != AV_PIX_FMT_NONE;
1136 ++pix) {
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) {
1140 continue;
1141 }
1142 AVPixelFormat curr_pix_fmt = *pix;
1143 if (try_open_codec(s, curr_pix_fmt, desc, ug_codec, codec)) {
1144 return curr_pix_fmt;
1145 }
1146 }
1147 return AV_PIX_FMT_NONE;
1148}
1149
1150static bool configure_with(struct state_video_compress_libav *s, struct video_desc desc)
1151{
1152 s->saved_desc = {};
1153 codec_t ug_codec = s->requested_codec_id == VIDEO_CODEC_NONE ? DEFAULT_CODEC : s->requested_codec_id;
1154 AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
1155 const AVCodec *codec = nullptr;
1156#ifdef HAVE_SWSCALE
1157 sws_freeContext(s->sws_ctx);
1158 s->sws_ctx = nullptr;
1159 av_frame_free(&s->sws_frame);
1160#endif //HAVE_SWSCALE
1161
1162 s->params.desc = desc;
1163
1164 if ((codec = get_av_codec(s, &ug_codec, codec_is_a_rgb(desc.color_spec))) == nullptr) {
1165 return false;
1166 }
1167 log_msg(LOG_LEVEL_NOTICE, "[lavc] Using codec: %s, encoder: %s\n",
1169
1170 // Try to open the codec context
1171 // It is done in a loop because some pixel formats that are reported
1172 // by codec can actually fail (typically YUV444 in hevc_nvenc for Maxwell
1173 // cards).
1174 list<enum AVPixelFormat> requested_pix_fmt = get_requested_pix_fmts(desc.color_spec, s->req_conv_prop);
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);
1180 if(try_open_codec(s, pix_fmt, desc, ug_codec, codec)){
1181 break;
1182 }
1183 }
1184
1185 if (pix_fmt == AV_PIX_FMT_NONE || log_level >= LOG_LEVEL_VERBOSE) {
1186 print_pix_fmts(requested_pix_fmt, codec->pix_fmts);
1187 }
1188
1189 if (pix_fmt == AV_PIX_FMT_NONE && get_commandline_param("lavc-use-codec") == NULL) {
1190 pix_fmt = try_open_remaining_pixfmts(s, desc, ug_codec, codec,
1191 fmts_tried);
1192 }
1193
1194 if (pix_fmt == AV_PIX_FMT_NONE) {
1195 log_msg(LOG_LEVEL_WARNING, "[lavc] Unable to find suitable pixel format for: %s.\n", get_codec_name(desc.color_spec));
1196 if (s->req_conv_prop.subsampling != 0 || s->req_conv_prop.depth != 0 || s->req_conv_prop.rgb != -1 || get_commandline_param("lavc-use-codec") != NULL) {
1197 log_msg(LOG_LEVEL_ERROR, "[lavc] Requested parameters not supported. %s\n",
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.");
1200
1201 }
1202 return false;
1203 }
1204
1205 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Codec %s capabilities: 0x%08X using thread type %d, count %d\n", codec->name,
1206 codec->capabilities, s->codec_ctx->thread_type, s->codec_ctx->thread_count);
1207 log_msg(LOG_LEVEL_INFO, "[lavc] Selected pixfmt: %s\n", av_get_pix_fmt_name(pix_fmt));
1208 incomp_feature_warn(INCOMP_SUBSAMPLING,
1209 av_pixfmt_get_subsampling(pix_fmt));
1210 incomp_feature_warn(INCOMP_DEPTH,
1211 av_pix_fmt_desc_get(pix_fmt)->comp[0].depth);
1212
1213 s->compressed_desc = desc;
1214 s->compressed_desc.color_spec = ug_codec;
1215 s->compressed_desc.tile_count = 1;
1216 s->mov_avg_frames = s->mov_avg_comp_duration = 0;
1217
1218 to_lavc_vid_conv_destroy(&s->pixfmt_conversion);
1219 if ((s->pixfmt_conversion = to_lavc_vid_conv_init(desc.color_spec, desc.width, desc.height, pix_fmt, s->conv_thread_count)) == nullptr) {
1220 if (!configure_swscale(s, desc, pix_fmt)) {
1221 return false;
1222 }
1223 }
1224
1225 // we need to store extradata for HuffYUV/FFV1 in the beginning
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);
1233 }
1234
1235 s->saved_desc = desc;
1236 LOG(LOG_LEVEL_DEBUG) << MOD_NAME "Successfully reconfigured to " << desc << "\n";
1237
1238 return true;
1239}
1240
1242static void check_duration(struct state_video_compress_libav *s, time_ns_t dur_pixfmt_change_ns, time_ns_t dur_total_ns)
1243{
1244 enum { REPEAT_INT_SEC = 30 };
1245 constexpr int mov_window = 100;
1246 double duration = dur_total_ns / NS_IN_SEC_DBL;
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) {
1250 return;
1251 }
1252 const time_ns_t now = get_time_in_ns();
1253 if (now < s->duration_warn_last_print + NS_IN_SEC * REPEAT_INT_SEC) {
1254 return;
1255 }
1256 s->duration_warn_last_print = now;
1257 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Average compression time of last %d frames is %f ms but time per frame is only %f ms!\n",
1258 mov_window, s->mov_avg_comp_duration * 1000, 1000 / s->compressed_desc.fps);
1259 string hint;
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)";
1264 }
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";
1269 }
1270 } else if (strcmp(s->codec_ctx->codec->name, "libsvt_hevc") == 0) {
1271 if (s->lavc_opts.find("preset") == s->lavc_opts.end()) {
1272 hint =
1273 "\"preset=12\" option for quality/speed trade-off "
1274 "to libsvt_hevc compression (values 0-12 allowed)";
1275 quality_hurt = "quality";
1276 }
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";
1279 } else if (s->codec_ctx->thread_count == 1 && (s->codec_ctx->codec->capabilities & AV_CODEC_CAP_OTHER_THREADS) != 0) {
1280 hint = "\"threads=<n>\" option with small <n> or 0 (nr of logical cores) to compression";
1281 }
1282 if (!hint.empty()) {
1283 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Consider adding " << hint << " to increase throughput at the expense of " << quality_hurt << ".\n";
1284 }
1285
1286 bool src_rgb = codec_is_a_rgb(s->saved_desc.color_spec);
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)
1292 << " ms.\n"
1293 "Consider adding \"--conv-policy cds\" to prevent color "
1294 "space conversion.\n";
1295 }
1296}
1297
1298static void write_orig_format(struct video_frame *compressed_frame, codec_t orig_pixfmt) {
1299 if (compressed_frame == nullptr) {
1300 return;
1301 }
1302 if (compressed_frame->color_spec != H264 && compressed_frame->color_spec != H265) {
1303 log_msg_once(LOG_LEVEL_ERROR, to_fourcc('L', 'W', 'P', 'T'), MOD_NAME
1304 "Currently cannot store input format to different compression stream than H.264/HEVC\n");
1305 return;
1306 }
1307 char *data = compressed_frame->tiles[0].data;
1308 unsigned int *data_len = &compressed_frame->tiles[0].data_len;
1309 if (compressed_frame->color_spec == H264) {
1310 unsigned char sei_nal_prefix[] = { START_CODE_3B, H264_NAL_SEI_PREFIX, sizeof (unsigned char []) { UG_ORIG_FORMAT_ISO_IEC_11578_GUID } + 1, UG_ORIG_FORMAT_ISO_IEC_11578_GUID };
1311 memcpy(data + *data_len, sei_nal_prefix, sizeof sei_nal_prefix);
1312 *data_len += sizeof sei_nal_prefix;
1313 } else {
1314 unsigned char sei_nal_prefix[] = { START_CODE_3B, HEVC_NAL_SEI_PREFIX, sizeof (unsigned char []) { UG_ORIG_FORMAT_ISO_IEC_11578_GUID } + 1, UG_ORIG_FORMAT_ISO_IEC_11578_GUID };
1315 memcpy(data + *data_len, sei_nal_prefix, sizeof sei_nal_prefix);
1316 *data_len += sizeof sei_nal_prefix;
1317 }
1318
1319 struct pixfmt_desc desc = get_pixfmt_desc(orig_pixfmt);
1320 unsigned subs_a = (desc.subsampling / 100 % 10);
1321 unsigned subs_b = (desc.subsampling / 10 % 10);
1322 unsigned subs_v = subs_a - 1; // [4 2 1] -> [3 1 0]
1323 unsigned subs_h = !!subs_b; // 1 - vertically subsampled, 0 - not
1324 unsigned rgb = desc.rgb;
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;
1328 uint8_t eob = 0x80; // ? end of bytestream ? (doesn't work without)
1329 memcpy(data + *data_len, &eob, sizeof eob);
1330 *data_len += sizeof eob;
1331}
1332
1333void
1334store_metadata(state_video_compress_libav *s, const struct video_frame *f,
1335 int64_t pts)
1336{
1337 // batch remove frames older than HOUSEKEEP_INTERVAL
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));
1342 }
1343 vf_store_metadata(f, s->metadata_storage[pts]);
1344}
1345void
1346restore_metadata(state_video_compress_libav *s, struct video_frame *out,
1347 int64_t pts)
1348{
1349 assert (pts != AV_NOPTS_VALUE);
1350 auto it = s->metadata_storage.find(pts);
1351 if (it != s->metadata_storage.end()) {
1352 vf_restore_metadata(out, it->second);
1353 } else {
1354 log_msg_once(LOG_LEVEL_WARNING, to_fourcc('l', 'c', 'm', 'd'),
1355 MOD_NAME "Metadata for frame not found!\n");
1356 debug_msg("Metadata for frame %" PRIu64 " not found!\n", pts);
1357 }
1358}
1359
1360void
1361store_sps_pps_vps(state_video_compress_libav *s, AVPacket *pkt)
1362{
1363 if (s->compressed_desc.color_spec != H264 &&
1364 s->compressed_desc.color_spec != H265) {
1365 return;
1366 }
1367 if (s->aux_header.buf_len > 0) {
1368 return;
1369 }
1370 const bool is_hevc = s->compressed_desc.color_spec == H265;
1371 const int h264_nalu_req[] = { NAL_H264_SPS, NAL_H264_PPS, 0 };
1372 const int hevc_nalu_req[] = { NAL_HEVC_VPS, NAL_HEVC_SPS, NAL_HEVC_PPS,
1373 0 };
1374 const int *nalu_req = is_hevc ? hevc_nalu_req : h264_nalu_req;
1375 const unsigned char *const first_nal =
1376 rtpenc_get_first_nal(s->pkt->data, s->pkt->size, is_hevc);
1377 const unsigned char *nal = first_nal;
1378 int i = 0;
1379 const unsigned char *endptr = nullptr;
1380 while (nal != nullptr) {
1381 if (NALU_HDR_GET_TYPE(nal[0], is_hevc) != nalu_req[i++]) {
1382 return;
1383 }
1384 if (nalu_req[i] == 0) { // correct seq of NALU
1385 break;
1386 }
1387 nal = rtpenc_get_next_nal(nal, pkt->size - (nal - pkt->data),
1388 &endptr);
1389 }
1390 if (nalu_req[i] != 0) {
1391 return;
1392 }
1393 const char start_code[] = { START_CODE_4B };
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;
1398}
1399
1400auto out_vf_from_pkt(state_video_compress_libav *s, AVPacket *pkt) {
1401 shared_ptr<video_frame> out;
1402 if (pkt->size == 0) { // videotoolbox returns sometimes frames with
1403 // pkt->size == 0 but got_output == true
1404 return out;
1405 }
1406
1407 out = shared_ptr<video_frame>(
1409 free(frame->tiles[0].data);
1410 vf_free(frame);
1411 });
1412 if (s->compressed_desc.color_spec == PRORES) {
1413 assert(s->codec_ctx->codec_tag != 0);
1414 out->color_spec = get_codec_from_fcc(s->codec_ctx->codec_tag);
1415 }
1416
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,
1422 pkt->size);
1423 if (s->params.header_inserter_req == 1) {
1424 store_sps_pps_vps(s, pkt);
1425 }
1426
1427 av_packet_unref(s->pkt);
1428
1429 return out;
1430}
1431
1432shared_ptr<video_frame>
1433receive_packet(state_video_compress_libav *s)
1434{
1435 const int ret = avcodec_receive_packet(s->codec_ctx, s->pkt);
1436 if (ret != 0) {
1437 if (ret == AVERROR(EAGAIN)) {
1438 MSG(DEBUG,
1439 "avcodec_receive_packet: received none packet "
1440 "(EAGAIN)\n");
1441 } else {
1443 MOD_NAME "Receive packet error", ret);
1444 }
1445 return {};
1446 }
1447
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",
1451 pts_diff);
1452 s->max_pts_diff_reported = pts_diff;
1453 }
1454
1455 return out_vf_from_pkt(s, s->pkt);
1456}
1457
1458static shared_ptr<video_frame> libavcodec_compress_tile(struct module *mod, shared_ptr<video_frame> tx)
1459{
1460 auto *s = (state_video_compress_libav *) mod->priv_data;
1461 list<shared_ptr<void>> cleanup_callbacks; // at function exit handlers
1462
1463 libavcodec_check_messages(s);
1464
1467 cleanup(s);
1468 if (!configure_with(s, video_desc_from_frame(tx.get()))) {
1469 return {};
1470 }
1471 }
1472
1473 if (!tx) { // reading further encoded frames
1474 return receive_packet(s);
1475 }
1476
1478 struct AVFrame *frame = to_lavc_vid_conv(s->pixfmt_conversion, tx->tiles[0].data);
1479 if (!frame) {
1480 return {};
1481 }
1483
1485#ifdef HWACC_VAAPI
1486 if(s->hwenc){
1487 av_hwframe_transfer_data(s->hwframe, frame, 0);
1488 frame = s->hwframe;
1489 }
1490#endif
1491
1492#ifdef HAVE_SWSCALE
1493 if(s->sws_ctx){
1494 sws_scale(s->sws_ctx,
1495 frame->data,
1496 frame->linesize,
1497 0,
1498 frame->height,
1499 s->sws_frame->data,
1500 s->sws_frame->linesize);
1501 frame = s->sws_frame;
1502 }
1503#endif //HAVE_SWSCALE
1505
1506 /* encode the image */
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)) {
1510 print_libav_error(LOG_LEVEL_WARNING, "[lavc] Error encoding frame", ret);
1511 return {};
1512 }
1513
1514 shared_ptr<video_frame> out = receive_packet(s);
1516 LOG(LOG_LEVEL_DEBUG2) << MOD_NAME << "duration pixfmt change: "
1517 << (t1 - t0) / NS_IN_SEC_DBL <<
1518 " s, dump+swscale " << (t2 - t1) / (double) NS_IN_SEC <<
1519 " s, compression " << (t3 - t2) / (double) NS_IN_SEC << " s\n";
1520 check_duration(s, t1 - t0, t3 - t0);
1521
1522 if (!out) {
1523 return {};
1524 }
1525
1526 if (s->store_orig_format) {
1527 write_orig_format(out.get(), tx->color_spec);
1528 }
1529
1530 return out;
1531}
1532
1533static void cleanup(struct state_video_compress_libav *s)
1534{
1535 if(s->codec_ctx) {
1536 int ret = avcodec_send_frame(s->codec_ctx, NULL);
1537 if (ret != 0) {
1538 log_msg(LOG_LEVEL_WARNING, "[lavc] Unexpected return value %d\n",
1539 ret);
1540 }
1541 do {
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) {
1547 log_msg(LOG_LEVEL_WARNING, "[lavc] Unexpected return value %d\n",
1548 ret);
1549 break;
1550 }
1551 } while (ret != AVERROR_EOF);
1552 avcodec_free_context(&s->codec_ctx);
1553 }
1554
1555 av_frame_free(&s->hwframe);
1556
1557#ifdef HAVE_SWSCALE
1558 sws_freeContext(s->sws_ctx);
1559 s->sws_ctx = nullptr;
1560 av_frame_free(&s->sws_frame);
1561#endif //HAVE_SWSCALE
1562}
1563
1564static void libavcodec_compress_done(struct module *mod)
1565{
1566 struct state_video_compress_libav *s = (struct state_video_compress_libav *) mod->priv_data;
1567
1568 cleanup(s);
1569
1570 delete s;
1571}
1572
1578static void set_codec_thread_mode(AVCodecContext *codec_ctx, struct setparam_param *param)
1579{
1580 if (param->thread_mode == "no") { // disable threading (which may have been enabled previously
1581 codec_ctx->thread_type = 0;
1582 codec_ctx->thread_count = 1;
1583 return;
1584 }
1585
1586 int req_thread_count = -1;
1587 int req_thread_type = 0;
1588 size_t endpos = 0;
1589 try { // just a number
1590 req_thread_count = stoi(param->thread_mode, &endpos);
1591 } catch(invalid_argument &) { // not a number
1592 }
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;
1598 default: log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown thread mode: '%c'.\n", param->thread_mode[endpos]);
1599 }
1600 endpos += 1;
1601 }
1602
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;
1606 } else if ((codec_ctx->codec->capabilities & AV_CODEC_CAP_OTHER_THREADS) == 0 &&
1607 (codec_ctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) != 0) {
1608 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Slice-based or external multithreading not available, encoding won't be parallel. "
1609 "You may select frame-based paralellism if needed.\n");
1610 }
1611 } else if (req_thread_type == -1) {
1612 req_thread_type = 0;
1613 }
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)) {
1616 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Codec doesn't support specified thread mode.\n");
1617 } else {
1618 codec_ctx->thread_type = req_thread_type;
1619 }
1620
1621 if (req_thread_count != -1) {
1622 codec_ctx->thread_count = req_thread_count;
1623 } else if ((codec_ctx->codec->capabilities & AV_CODEC_CAP_OTHER_THREADS) != 0) {
1624 // do not enable MT for eg. libx265 - libx265 uses frame threads
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;
1631 }
1632 } else if (codec_ctx->thread_type != 0) {
1633 codec_ctx->thread_count = thread::hardware_concurrency();
1634 }
1635 log_msg(LOG_LEVEL_INFO, MOD_NAME "Setting thread count to %d, type: %s\n", codec_ctx->thread_count, lavc_thread_type_to_str(codec_ctx->thread_type));
1636}
1637
1638static void setparam_default(AVCodecContext *codec_ctx, struct setparam_param * /* param */)
1639{
1640 if (codec_ctx->codec->id == AV_CODEC_ID_JPEG2000) {
1641 log_msg(LOG_LEVEL_WARNING, "[lavc] J2K support is experimental and may be broken!\n");
1642 }
1643}
1644
1646static void
1647mjpeg_adjust_param(struct setparam_param *param)
1648{
1649 char warn[STR_LEN];
1650 warn[0] = '\0';
1651 if (param->slices == 1) {
1652 if (param->thread_mode.empty()) {
1653 snprintf_ch(warn, "MJPEG requested slice=1, "
1654 "setting thread count=1");
1655 param->thread_mode = "1";
1656 } else if (strtol(param->thread_mode.c_str(), nullptr, 10) !=
1657 1) {
1658 snprintf_ch(warn, "slice=1 with thread count!=1 not "
1659 "recommended");
1660 }
1661 } else if (strtol(param->thread_mode.c_str(), nullptr, 10) == 1) {
1662 if (param->slices == -1) {
1663 snprintf_ch(warn, "MJPEG requested threads=1, "
1664 "setting slices=1");
1665 param->slices = 1;
1666 } else if (param->slices > 1) {
1667 snprintf_ch(warn, "slice>1 with thread count=1 not "
1668 "recommended");
1669 }
1670 }
1671
1672 if (strlen(warn) == 0) {
1673 return;
1674 }
1675 MSG(WARNING,
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",
1679 warn);
1680}
1681
1682static void setparam_jpeg(AVCodecContext *codec_ctx, struct setparam_param *param)
1683{
1684 if (strcmp(codec_ctx->codec->name, "mjpeg") == 0) {
1685 check_av_opt_set<const char *>(codec_ctx->priv_data, "huffman", "default", "Huffman tables");
1686 mjpeg_adjust_param(param);
1687 }
1688 if (strcmp(codec_ctx->codec->name, "mjpeg_qsv") == 0) {
1689 check_av_opt_set<int>(codec_ctx->priv_data, "async_depth", 1);
1690 }
1691}
1692
1693static void configure_amf([[maybe_unused]] AVCodecContext *codec_ctx, [[maybe_unused]] struct setparam_param *param) {
1694 check_av_opt_set(codec_ctx->priv_data, "rc", DEFAULT_AMF_RC);
1695 const char *const usage = codec_ctx->codec->id == AV_CODEC_ID_AV1
1696 ? DEFAULT_AMF_USAGE_AV1
1697 : DEFAULT_AMF_USAGE;
1698 check_av_opt_set(codec_ctx->priv_data, "usage", usage);
1699 if (codec_ctx->codec->id == AV_CODEC_ID_AV1 ||
1700 codec_ctx->codec->id == AV_CODEC_ID_HEVC) {
1701 check_av_opt_set<const char *>(codec_ctx->priv_data, "header_insertion_mode", "gop", "header_insertion_mode for AMF");
1702 } else if ("h264_amf"s == codec_ctx->codec->name) {
1703 check_av_opt_set<int>(codec_ctx->priv_data, "header_spacing", 1);
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;
1708 }
1709 }
1710}
1711
1712void
1713configure_mf(AVCodecContext *codec_ctx,
1714 [[maybe_unused]] struct setparam_param *param)
1715{
1716 check_av_opt_set<const char *>(codec_ctx->priv_data, "rate_control",
1717 "cbr");
1718 check_av_opt_set<const char *>(codec_ctx->priv_data, "scenario",
1719 "video_conference");
1720 check_av_opt_set<int>(codec_ctx->priv_data, "hw_encoding", 1);
1721}
1722
1723void
1724incomp_feature_warn(enum incomp_feature f, int req_val)
1725{
1726 const char *disable_opt = nullptr;
1727 switch (f) {
1728 case INCOMP_DEPTH:
1729 if (req_val == 8) {
1730 return;
1731 }
1732 MSG(WARNING,
1733 "Selected color depth %d b may not be supported by HW "
1734 "coders.\n",
1735 req_val);
1736 disable_opt = ":depth=8";
1737 break;
1738 case INCOMP_INTRA_REFRESH:
1739 if (req_val != -1) {
1740 return;
1741 }
1742 MSG(WARNING, "Auto-enabling intra-refresh "
1743 "which may not be supported by HW coders.\n");
1744 disable_opt = ":disable_intra_refresh";
1745 break;
1746 case INCOMP_INTERLACED_DCT:
1747 if (req_val != -1) {
1748 return;
1749 }
1750 MSG(WARNING, "Auto-enabling interlaced DCT "
1751 "which may not be supported by HW coders.\n");
1752 disable_opt = ":disable_interlaced_dct";
1753 break;
1754 case INCOMP_SUBSAMPLING:
1755 if (req_val == SUBS_420) {
1756 return;
1757 }
1758 MSG(WARNING,
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";
1764 break;
1765 }
1766 MSG(INFO, "Use '%s' or ':safe' to disable.\n", disable_opt);
1767}
1768
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 "
1773 "x264/5: " TOSTRING(DEFAULT_X26X_RC_BUF_SIZE_FACTOR) ", nvenc: " TOSTRING(
1775static void
1776configure_x264_x265(AVCodecContext *codec_ctx, struct setparam_param *param)
1777{
1778 const char *preset = "ultrafast";
1779 if (strstr(codec_ctx->codec->name, "libx264") ==
1780 codec_ctx->codec->name &&
1781 (param->desc.width * param->desc.height * param->desc.fps <=
1782 FLW_THRESH)) {
1783 preset = "veryfast";
1784 }
1785 check_av_opt_set<const char *>(codec_ctx->priv_data, "preset", preset);
1786
1787 const char *tune = codec_ctx->codec->id == AV_CODEC_ID_H264 ? "zerolatency,fastdecode" : "zerolatency"; // x265 supports only single tune parameter
1788 check_av_opt_set<const char *>(codec_ctx->priv_data, "tune", tune);
1789
1790 // try to keep frame sizes as even as possible
1791 codec_ctx->rc_max_rate = codec_ctx->bit_rate;
1792 //codec_ctx->rc_min_rate = s->codec_ctx->bit_rate / 4 * 3;
1793 //codec_ctx->rc_buffer_aggressivity = 1.0;
1794 double lavc_rc_buffer_size_factor = DEFAULT_X26X_RC_BUF_SIZE_FACTOR;
1795 if (const char *val = get_commandline_param("lavc-rc-buffer-size-factor")) {
1796 lavc_rc_buffer_size_factor = stof(val);
1797 }
1798 codec_ctx->rc_buffer_size = codec_ctx->rc_max_rate / param->desc.fps * lavc_rc_buffer_size_factor; // "emulate" CBR. Note that factor less than 8 used to cause encoder buffer overflows and artifacts in stream.
1799 codec_ctx->qcompress = codec_ctx->codec->id == AV_CODEC_ID_H265 ? 0.5F : 0.0F;
1800 //codec_ctx->qblur = 0.0f;
1801 //codec_ctx->rc_min_vbv_overflow_use = 1.0f;
1802 //codec_ctx->rc_max_available_vbv_use = 1.0f;
1803 codec_ctx->qmin = IF_NOT_UNDEF_ELSE(codec_ctx->qmin, 0); // qmin,qmax set to -1 by default
1804 codec_ctx->qmax = IF_NOT_UNDEF_ELSE(codec_ctx->qmax, 69);
1805 codec_ctx->max_qdiff = 69;
1806 //codec_ctx->rc_qsquish = 0;
1807 //codec_ctx->scenechange_threshold = 100;
1808
1809 if (param->desc.interlacing == INTERLACED_MERGED &&
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;
1814 }
1815
1816 string x265_params;
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");
1820 }
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;
1824 }
1825 };
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) {
1832 check_av_opt_set<const char *>(codec_ctx->priv_data, "intra-refresh", "1");
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");
1837 }
1838 }
1839 if ("libx265"s == codec_ctx->codec->name) {
1840 check_av_opt_set<const char *>(codec_ctx->priv_data, "x265-params", x265_params.c_str());
1841 }
1842}
1843
1844static void configure_qsv_h264_hevc(AVCodecContext *codec_ctx, struct setparam_param *param)
1845{
1846 check_av_opt_set<const char *>(codec_ctx->priv_data, "preset",
1847 DEFAULT_QSV_PRESET);
1848 check_av_opt_set<const char *>(codec_ctx->priv_data, "scenario", "livestreaming");
1849 check_av_opt_set<int>(codec_ctx->priv_data, "async_depth", 1);
1850
1851 if (param->periodic_intra != 0) {
1852 incomp_feature_warn(INCOMP_INTRA_REFRESH, param->periodic_intra);
1853 check_av_opt_set<const char *>(codec_ctx->priv_data, "int_ref_type", "vertical");
1854 check_av_opt_set<int>(codec_ctx->priv_data, "int_ref_cycle_size", 20);
1855 }
1856
1857 if (param->desc.interlacing == INTERLACED_MERGED && param->interlaced_dct != 0) {
1858 incomp_feature_warn(INCOMP_INTERLACED_DCT, param->interlaced_dct);
1859 codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
1860 }
1861
1862 // rate control
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");
1867 }
1868 if (strcmp(rc, "help") == 0) {
1869 col() << "\n\n"
1870 << SBOLD("See codec-specific usage for available RCs (``-c "
1871 "libavcodec:encoder=<enc>:help`).")
1872 << "\n\n\n";
1873 exit_uv(0);
1874 } else if (strcasecmp(rc, "cbr") == 0) {
1875 codec_ctx->rc_max_rate = codec_ctx->bit_rate;
1876 // no look-ahead and rc_max_rate == bit_rate result in use of CBR for QSV
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; // 115%; if rc_max_rate == bit_rate, FF would set CBR
1885 }
1886 } else if (strcasecmp(rc, "vbr") == 0) { // no options needed
1887 } else {
1888 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown/unsupported RC %s. Please report to %s if you need some mode added.\n",
1889 rc, PACKAGE_BUGREPORT);
1890 exit_uv(1);
1891 }
1892}
1893
1894static void configure_vaapi(AVCodecContext * /* codec_ctx */, struct setparam_param *param) {
1895 param->thread_mode = "no"; // VA-API doesn't support threads
1896 // interesting options: "b_depth" (not used - we are not using B-frames), "idr_interval" - set to 0 by default
1897}
1898
1899static void configure_aom_av1(AVCodecContext *codec_ctx, struct setparam_param *param)
1900{
1901 auto && usage = get_map_val_or_default<string, string>(param->lavc_opts, "usage", "realtime");
1902 check_av_opt_set<const char *>(codec_ctx->priv_data, "usage", usage.c_str());
1903 check_av_opt_set<const char *>(codec_ctx->priv_data, "tiles", "8x8");
1904}
1905
1906static void configure_nvenc(AVCodecContext *codec_ctx, struct setparam_param *param)
1907{
1908 const char *preset = DEFAULT_NVENC_PRESET;
1909
1910 // important: if "tune" is not supported, then FALLBACK_NVENC_PRESET must be used (it is correlated). If unsupported preset
1911 // were given, setting would succeed but would cause runtime errors.
1912 if (!check_av_opt_set<const char *>(codec_ctx->priv_data, "tune", DEFAULT_NVENC_TUNE, "NVENC tune")) {
1913 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Possibly old libavcodec or compiled with old NVIDIA NVENC headers.\n";
1914 preset = FALLBACK_NVENC_PRESET;
1915 }
1916 if (!param->have_preset) {
1917 if (check_av_opt_set<const char *>(codec_ctx->priv_data, "preset", preset, "NVENC preset")) {
1918 LOG(LOG_LEVEL_INFO) << MOD_NAME "Setting NVENC preset to " << preset << ".\n";
1919 }
1920 }
1921
1922 check_av_opt_set(codec_ctx->priv_data, "forced-idr", 1);
1923#ifdef PATCHED_FF_NVENC_NO_INFINITE_GOP
1924 const bool patched_ff = true;
1925#else
1926 const bool patched_ff = false;
1927 if (param->periodic_intra != 0) {
1928 LOG(LOG_LEVEL_WARNING) << MOD_NAME "FFmpeg not patched, " << (param->periodic_intra != 1 ? "not " : "") << "enabling Intra Refresh.\n";
1929 }
1930#endif
1931
1932 if ((patched_ff && param->periodic_intra != 0) || param->periodic_intra == 1) {
1933 incomp_feature_warn(INCOMP_INTRA_REFRESH, param->periodic_intra);
1934 check_av_opt_set<int>(codec_ctx->priv_data, "intra-refresh", 1);
1935 }
1936
1937 check_av_opt_set<const char *>(codec_ctx->priv_data, "rc", DEFAULT_NVENC_RC);
1938 check_av_opt_set<int>(codec_ctx->priv_data, "spatial_aq", 0);
1939 check_av_opt_set<int>(codec_ctx->priv_data, "gpu", cuda_devices[0]);
1940 check_av_opt_set<int>(codec_ctx->priv_data, "delay", 0); // 2'd increase throughput 2x at expense of higher latency
1941 check_av_opt_set<int>(codec_ctx->priv_data, "zerolatency", 1, "zero latency operation (no reordering delay)");
1942 check_av_opt_set<const char *>(codec_ctx->priv_data, "b_ref_mode", "disabled", 0);
1943 codec_ctx->rc_max_rate = codec_ctx->bit_rate;
1944 double lavc_rc_buffer_size_factor = DEFAULT_NVENC_RC_BUF_SIZE_FACTOR;
1945 if (const char *val = get_commandline_param("lavc-rc-buffer-size-factor")) {
1946 lavc_rc_buffer_size_factor = stof(val);
1947 } else {
1949 << MOD_NAME
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";
1955 }
1956 codec_ctx->rc_buffer_size =
1957 (int) ((double) codec_ctx->rc_max_rate / param->desc.fps *
1958 lavc_rc_buffer_size_factor);
1959 if (param->desc.interlacing == INTERLACED_MERGED && param->interlaced_dct == 1) {
1960 codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
1961 }
1962}
1963
1964static void configure_rav1e(AVCodecContext *codec_ctx, struct setparam_param * /*param*/)
1965{
1966 check_av_opt_set<const char *>(codec_ctx->priv_data, "rav1e-params", "low_latency=true");
1967 check_av_opt_set<const char *>(codec_ctx->priv_data, "speed", "10");
1968 check_av_opt_set<const char *>(codec_ctx->priv_data, "tiles", "64");
1969}
1970
1971static void
1972configure_svt_hevc_vp9(AVCodecContext *codec_ctx, struct setparam_param *param)
1973{
1974 // see FFMPEG modules' sources for semantics
1976 codec_ctx->priv_data, "forced-idr",
1977 strcmp(codec_ctx->codec->name, "libsvt_hevc") == 0 ? 0 : 1);
1978
1979 if ("libsvt_hevc"s == codec_ctx->codec->name) {
1980 check_av_opt_set<int>(codec_ctx->priv_data, "la_depth", 0);
1981 check_av_opt_set<int>(codec_ctx->priv_data, "pred_struct", 0);
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) {
1985 check_av_opt_set<int>(codec_ctx->priv_data, "tile_row_cnt", tile_row_cnt);
1986 check_av_opt_set<int>(codec_ctx->priv_data, "tile_col_cnt", tile_col_cnt);
1987 check_av_opt_set<int>(codec_ctx->priv_data, "tile_slice_mode", 1);
1988 check_av_opt_set<int>(codec_ctx->priv_data, "umv", 0);
1989 }
1990 if (param->desc.width * param->desc.height * param->desc.fps > FLW_UHD_60) {
1991 check_av_opt_set<const char *>(codec_ctx->priv_data,
1992 "preset", "11");
1993 }
1994 }
1995}
1996
1997static void
1998configure_svt_av1(AVCodecContext *codec_ctx, struct setparam_param *param) {
1999 const char *preset =
2000 param->desc.width * param->desc.height * param->desc.fps <=
2001 FLW_THRESH
2002 ? "9"
2003 : "11";
2004 check_av_opt_set<const char *>(codec_ctx->priv_data, "preset", preset);
2005#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(59, 21, 100)
2006 // pred-struct=1 is low-latency mode
2007 char params[STR_LEN] = "pred-struct=1:";
2008 if (param->requested_bitrate > 0) {
2009 if (param->requested_crf == -1 && param->requested_cqp == -1) {
2010 params[0] = '\0'; // do not set pred-struct for VBR
2011 MSG(WARNING,
2012 "Bitrate setting without crf/cqp for SVT "
2013 "AV1 is not recommended since it increases "
2014 "latency, prefer CRF or CQP mode if "
2015 "possible.\n");
2016 MSG(WARNING, "However, you can specify _both_ crf/cqp "
2017 "and bitrate options to set bitrate "
2018 "limit.\n");
2019 } else {
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);
2024 }
2025 }
2026 snprintf(params + strlen(params), sizeof params - strlen(params), "%s",
2027 "fast-decode=1:tile-columns=2:tile-rows=2");
2028 check_av_opt_set(codec_ctx->priv_data, "svtav1-params", params);
2029#else
2030 // tile_columns and tile_rows are log2 values
2031 for (auto const &val : { "tile_columns", "tile_rows" }) {
2032 check_av_opt_set<int>(codec_ctx->priv_data, val, 2,
2033 "tile dimensions for SVT AV1");
2034 }
2035#endif
2036}
2037
2038void
2039configure_libopenh264(AVCodecContext *codec_ctx,
2040 struct setparam_param *param)
2041{
2042 if (param->requested_bitrate != 0 || param->requested_bpp != 0) {
2043 check_av_opt_set(codec_ctx->priv_data, "rc_mode", "bitrate");
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");
2047 check_av_opt_set(codec_ctx->priv_data, "rc_mode", "quality");
2048 } else { // FFmpeg sets quality by default
2049 check_av_opt_set(codec_ctx->priv_data, "rc_mode", "off");
2050 return;
2051 }
2052 MSG(WARNING, "Setting frame skipping for OpenH264 when bitrate/quality "
2053 "is set. Do not set if not desired.\n");
2054 check_av_opt_set(codec_ctx->priv_data, "allow_skip_frames", 1);
2055 // slices - must be either >1 to enable multithreading (32 default now)
2056}
2057
2058static void setparam_h264_h265_av1(AVCodecContext *codec_ctx, struct setparam_param *param)
2059{
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 || // libx264 and libx264rgb
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; // (untested)
2076 }
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);
2090 } else {
2091 log_msg(LOG_LEVEL_WARNING, "[lavc] Warning: Unknown encoder %s. Using default configuration values.\n", codec_ctx->codec->name);
2092 }
2093}
2094
2095string
2096get_opt_default_value(const AVOption *opt)
2097{
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
2109 ? ""
2110 : string("\"") + opt->default_val.str + "\"";
2111 default:
2112 return "";
2113 }
2114}
2115
2117static bool
2118show_coder_help(string const &name, bool encoder)
2119{
2120 bool dec_found = true;
2121 if (encoder) {
2122 dec_found = show_coder_help(name, false);
2123 }
2124 const auto *codec = encoder
2125 ? avcodec_find_encoder_by_name(name.c_str())
2126 : avcodec_find_decoder_by_name(name.c_str());
2127 if (codec == nullptr) {
2128 if (!dec_found) {
2129 MSG(ERROR,
2130 "Unable to find neither encoder nor decoder %s!\n",
2131 name.c_str());
2132 }
2133 return false;
2134 }
2135 col() << "Options for " << SBOLD(name) << " "
2136 << (encoder ? "encoder" : "decoder") << ":\n";
2137 const auto *opt = codec->priv_class->option;
2138 if (opt == nullptr) {
2139 return true;
2140 }
2141 while (opt->name != nullptr) {
2142 string default_val;
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;
2148 }
2149 indent = "\t- ";
2150 }
2151 string help_str;
2152 if (opt->help != nullptr && strlen(opt->help) > 0) {
2153 help_str = opt->help;
2154 }
2155 if (!default_val.empty()) {
2156 if (help_str.find("default") == 0) {
2157 default_val = "";
2158 } else if (!help_str.empty()) {
2159 help_str += ", ";
2160 }
2161 }
2162 if (!help_str.empty() || !default_val.empty()) {
2163 help_str = " - "s + help_str;
2164 }
2165 col() << indent << SBOLD(opt->name) << help_str << default_val << "\n";
2166 opt++;
2167 }
2168 print_codec_aux_usage(name);
2169 color_printf("\n");
2170 return true;
2171}
2172
2174static void
2175print_codec_aux_usage(string const &name)
2176{
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";
2179 }
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";
2182 }
2183 if (name == "libsvtav1") {
2184 color_printf("\nIf using " TBOLD("svtav1-params") ", the option "
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");
2188 color_printf("\nExamples:\n");
2189 color_printf(TBOLD("\tuv -c lavc:enc=libsvtav1")
2190 "\n\t - use SVT AV1 with default RC CRF 35\n");
2191 color_printf(TBOLD("\tuv -c lavc:enc=libsvtav1:crf=30")
2192 "\n\t - use SVT AV1 with CRF=30\n");
2193 color_printf(TBOLD("\tuv -c lavc:enc=libsvtav1:cqp=30")
2194 "\n\t - use SVT AV1 with QP=30\n");
2195 color_printf(TBOLD("\tuv -c lavc:enc=libsvtav1:crf=35:bitr=3M")
2196 "\n\t - use SVT AV1 with QP=35 and Maximum Bitrate 3 Mbps\n");
2197 color_printf(TBOLD("\tuv -c lavc:enc=libsvtav1:bitr=3M")
2198 "\n\t - use SVT AV1 in VBR mode with 3 Mbps (not "
2199 "recommended at the moment, increases latency)\n");
2200 }
2201}
2202
2203static void setparam_vp8_vp9(AVCodecContext *codec_ctx, struct setparam_param *param)
2204{
2205 codec_ctx->rc_buffer_size = codec_ctx->bit_rate / param->desc.fps;
2206 //codec_ctx->rc_buffer_aggressivity = 0.5;
2207 check_av_opt_set<const char *>(codec_ctx->priv_data, "deadline", "realtime");
2208 check_av_opt_set<int>(codec_ctx->priv_data, "cpu-used", 8, "quality/speed ration modifier");
2209 check_av_opt_set<int>(codec_ctx->priv_data, "rc_lookahead", 0);
2210}
2211
2212static void libavcodec_check_messages(struct state_video_compress_libav *s)
2213{
2214 struct message *msg;
2215 while ((msg = check_message(&s->module_data))) {
2216 struct msg_change_compress_data *data =
2217 (struct msg_change_compress_data *) msg;
2218 struct response *r;
2219 if (parse_fmt(s, data->config_string) == 0) {
2220 log_msg(LOG_LEVEL_NOTICE, "[Libavcodec] Compression successfully changed.\n");
2221 r = new_response(RESPONSE_OK, NULL);
2222 } else {
2223 log_msg(LOG_LEVEL_ERROR, "[Libavcodec] Unable to change compression!\n");
2225 }
2226 memset(&s->saved_desc, 0, sizeof(s->saved_desc));
2227 free_message(msg, r);
2228 }
2229
2230}
2231
2232const struct video_compress_info libavcodec_info = {
2233 "libavcodec",
2234 libavcodec_compress_init,
2235 NULL,
2236 libavcodec_compress_tile,
2237 NULL,
2238 NULL,
2239 NULL,
2240 NULL,
2241 get_libavcodec_module_info,
2242};
2243
2244const struct video_compress_info lavc_info = {
2245 "lavc",
2246 libavcodec_compress_init,
2247 nullptr,
2248 libavcodec_compress_tile,
2249 nullptr,
2250 nullptr,
2251 nullptr,
2252 nullptr,
2253 nullptr,
2254};
2255
2259
2260} // end of anonymous namespace
2261
2262
2263/* vim: set expandtab sw=8 tw=120: */
#define UNUSED(x)
int void * val
struct video_desc desc
struct video_frame * frame
const char * fmt
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])
Definition portaudio.c:126
static void show_help()
Definition wasapi.cpp:193
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define SRED(x)
Definition color_out.h:85
#define TERM_RESET
Definition color_out.h:47
#define SBOLD(x)
Definition color_out.h:80
#define TBOLD(x)
Definition color_out.h:70
static __device__ vec2 clamp(const vec2 &v, float min_val, float max_val)
Definition cuda_dxt.cu:110
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
void log_msg_once(int level, uint32_t id, const char *msg,...)
Definition debug.cpp:137
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_DEBUG2
Definition debug.h:67
#define debug_file_dump(key, serialize, data)
Definition debug.h:86
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG(level)
Definition debug.h:313
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
steady_clock::duration duration
Definition echo.cpp:67
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
void module_done(struct module *module_data)
Definition module.c:93
@ MODULE_CLASS_DATA
Definition module.h:86
#define VIDEO_COMPRESS_ABI_VERSION
void exit_uv(int status)
Definition host.cpp:625
const char * get_commandline_param(const char *key)
Definition host.cpp:894
unsigned int cuda_devices[MAX_CUDA_DEVICES]
Definition host.cpp:167
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
#define INIT_NOERR
Definition host.h:73
This file contains functions related to hw acceleration.
int vaapi_init(struct AVCodecContext *s, struct hw_accel_state *state, codec_t out_codec)
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
volatile int log_level
Definition debug.cpp:65
codec_t get_av_to_ug_codec(enum AVCodecID av_codec)
Definition lavc_common.c:79
const char * lavc_thread_type_to_str(int thread_type)
enum AVCodecID get_ug_to_av_codec(codec_t ug_codec)
Definition lavc_common.c:89
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
Definition lavc_common.h:95
void serialize_video_avframe(const void *f, FILE *out)
Definition lavc_video.c:103
void usage()
Definition main.cpp:28
@ LIBRARY_CLASS_VIDEO_COMPRESS
Definition lib_common.h:82
#define REGISTER_HIDDEN_MODULE(name, info, lclass, abi)
Definition lib_common.h:156
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define DEFAULT_NVENC_RC_BUF_SIZE_FACTOR
#define MOD_NAME
#define DEFAULT_X26X_RC_BUF_SIZE_FACTOR
#define snprintf_ch(str,...)
shortcut for snprintf(var, sizeof var...), var must be a char array
Definition macros.h:101
#define TOSTRING(A)
Definition macros.h:49
#define IF_NOT_UNDEF_ELSE(val, default_val)
Definition macros.h:53
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
#define to_fourcc(a, b, c, d)
Creates FourCC word.
Definition macros.h:114
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
#define DEBUG
Definition main.c:27
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_OK
Definition messaging.h:57
#define RESPONSE_INT_SERV_ERR
Definition messaging.h:63
double unit_evaluate_dbl(const char *str, bool case_sensitive, const char **endptr)
Definition misc.cpp:102
bool is_arm_mac()
Definition misc.cpp:315
long long unit_evaluate(const char *str, const char **endptr)
Definition misc.cpp:81
const char * format_in_si_units(unsigned long long int val)
Definition misc.cpp:154
#define min(a, b)
Definition rtp.c:99
struct msghdr msg
@ NAL_HEVC_SPS
Definition rtpdec_h264.h:67
@ NAL_HEVC_PPS
Definition rtpdec_h264.h:68
@ NAL_H264_PPS
Definition rtpdec_h264.h:63
@ NAL_H264_SPS
Definition rtpdec_h264.h:62
@ NAL_HEVC_VPS
Definition rtpdec_h264.h:66
#define NALU_HDR_GET_TYPE(nal, is_hevc)
Definition rtpdec_h264.h:88
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
Definition rtpenc_h264.h:52
#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...
Definition rtpenc_h264.h:55
#define START_CODE_3B
Definition rtpenc_h264.h:50
#define START_CODE_4B
Definition rtpenc_h264.h:51
#define HEVC_NAL_SEI_PREFIX
Definition rtpenc_h264.h:53
codec_t first
Definition sdl2.c:423
static void cleanup()
Definition sdp.c:195
const char * parent
Definition settings.cpp:198
const char * param
Definition settings.cpp:195
const char * name
Definition settings.cpp:193
#define DEFAULT_CODEC
Definition spout.cpp:59
void replace_all(char *in, const char *from, const char *to)
Replaces all occurencies of 'from' to 'to' in string 'in'.
Definition string.c:71
#define DELDEL
Definition string.h:50
#define ESCAPED_COLON
Definition string.h:51
const char * name
displayed name
std::string name
std::vector< codec > codecs
std::vector< module_option > opts
Definition hd-rum.c:27
void * priv_data
Definition module.h:126
bool rgb
Definition types.h:142
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
codec_t color_spec
Definition types.h:182
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
codec_t color_spec
Definition types.h:306
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
long long time_ns_t
Definition tv.h:81
#define NS_IN_SEC
Definition tv.h:92
#define NS_IN_SEC_DBL
Definition tv.h:93
static time_ns_t get_time_in_ns()
Definition tv.h:101
#define NS_TO_MS(val_ns)
Definition tv.h:98
depth
Definition types.h:125
@ SUBS_420
Definition types.h:133
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
codec_t
Definition types.h:65
@ VP8
VP8 frame.
Definition types.h:86
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ PRORES
abstract Apple ProRes, must not be used in transmit
Definition types.h:100
@ AV1
AOMedia Video 1.
Definition types.h:96
@ J2K
JPEG 2000.
Definition types.h:89
@ HFYU
HuffYUV.
Definition types.h:92
@ MJPG
JPEG image, without restart intervals.
Definition types.h:85
@ FFV1
FFV1.
Definition types.h:93
@ H264
H.264 frame.
Definition types.h:83
@ VP9
VP9 frame.
Definition types.h:87
@ H265
H.264 frame.
Definition types.h:84
T get_map_val_or_default(std::map< key, T > const &map, key const &k, T const &def)
Definition misc.h:85
char * wrap_paragraph(char *text)
Definition text.c:204
codec_t ug_codec
Definition v4l2_common.h:68
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)
static bool configure_with(struct state_video_compress_cineform *s, struct video_desc desc)
Definition cineform.cpp:243
const char * key
Definition cineform.cpp:125
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
Definition libavcodec.c:898
static int check_av_opt_set(void *state, const char *key, const char *val)
Definition libavcodec.c:134
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)
#define PARAM_TILE_COUNT
Definition video_frame.h:68