UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
lavc_common.c
Go to the documentation of this file.
1
6/*
7 * Copyright (c) 2013-2023 CESNET, z. s. p. o.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, is permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of CESNET nor the names of its contributors may be
22 * used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
27 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
29 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
47#include <assert.h>
48#include <stdbool.h>
49#include <stdint.h>
50
51#include "debug.h"
52#include "host.h"
54#include <libavutil/channel_layout.h>
55#include "utils/macros.h"
56#include "video.h"
57
58#define MOD_NAME "[lavc_common] "
59
60//
61// UG <-> FFMPEG format translations
62//
63static const struct {
64 enum AVCodecID av;
66} av_to_uv_map[] = {
67 { AV_CODEC_ID_H264, H264 },
68 { AV_CODEC_ID_HEVC, H265 },
69 { AV_CODEC_ID_MJPEG, MJPG },
70 { AV_CODEC_ID_JPEG2000, J2K },
71 { AV_CODEC_ID_VP8, VP8 },
72 { AV_CODEC_ID_VP9, VP9 },
73 { AV_CODEC_ID_HUFFYUV, HFYU },
74 { AV_CODEC_ID_FFV1, FFV1 },
75 { AV_CODEC_ID_AV1, AV1 },
76 { AV_CODEC_ID_PRORES, PRORES },
77};
78
79codec_t get_av_to_ug_codec(enum AVCodecID av_codec)
80{
81 for (unsigned int i = 0; i < sizeof av_to_uv_map / sizeof av_to_uv_map[0]; ++i) {
82 if (av_to_uv_map[i].av == av_codec) {
83 return av_to_uv_map[i].uv;
84 }
85 }
86 return VIDEO_CODEC_NONE;
87}
88
90{
91 for (unsigned int i = 0; i < sizeof av_to_uv_map / sizeof av_to_uv_map[0]; ++i) {
92 if (av_to_uv_map[i].uv == ug_codec) {
93 return av_to_uv_map[i].av;
94 }
95 }
96 return AV_CODEC_ID_NONE;
97}
98
99//
100// utility functions
101//
102void print_libav_error(int verbosity, const char *msg, int rc) {
103 char errbuf[1024];
104 av_strerror(rc, errbuf, sizeof(errbuf));
105
106 log_msg(verbosity, "%s: %s\n", msg, errbuf);
107}
108
109void printf_libav_error(int verbosity, int rc, const char *msg, ...) {
110 char message[1024];
111
112 va_list ap;
113 va_start(ap, msg);
114 vsnprintf(message, sizeof message, msg, ap);
115 va_end(ap);
116
117 print_libav_error(verbosity, message, rc);
118}
119
121 return codec == HFYU || codec == FFV1;
122}
123
124static inline int av_to_uv_log(int level) {
125 enum {
126 AV_TO_UV_MULT = 8, // FF uses multiples of 8
127 };
128 if (level <= AV_LOG_PANIC) { // AV_LOG_QUIET(-8) -> LOG_LEVEL_QUIET(0)
129 level += AV_TO_UV_MULT;// AV_LOG_PANIC(0) -> LOG_LEVEL_FATAL(1)
130 }
131 // AV_LOG_FATAL(8), ERROR and WARNING map directly to UG counterparts /8
132 if (level >= AV_LOG_INFO) { // AV_LOG_INFO(32) -> LOG_LEVEL_INFO(5)
133 level += AV_TO_UV_MULT; // and so on for the rest
134 }
135 return level / AV_TO_UV_MULT;
136}
137
143static _Bool av_log_filter(const char *ff_module_name, const char *fmt) {
144 if (ff_module_name && strcmp(ff_module_name, "mjpeg") == 0 && strstr(fmt, "APP") != NULL) {
145 return 1;
146 }
147 return 0;
148}
149
150static void av_log_ug_callback(void *avcl, int av_level, const char *fmt, va_list vl) {
151 int level = av_to_uv_log(av_level);
152 if (level > log_level) {
153 return;
154 }
155 // avcl handling is taken from av_log_default_callback
156 AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
157 const char *ff_module_name = avc ? avc->item_name(avcl) : NULL;
158 if (av_log_filter(ff_module_name, fmt)) {
159 return;
160 }
161 static _Thread_local char buf[STR_LEN];
162 if (strlen(buf) == 0) {
163 snprintf(buf + strlen(buf), sizeof buf - strlen(buf), "[lavc");
164 if (ff_module_name) {
165 snprintf(buf + strlen(buf), sizeof buf - strlen(buf),
166 " %s @ %p", ff_module_name, avcl);
167 }
168 snprintf(buf + strlen(buf), sizeof buf - strlen(buf), "] ");
169 }
170 vsnprintf(buf + strlen(buf), sizeof buf - strlen(buf), fmt, vl);
171 if (buf[strlen(buf) - 1] != '\n' && strlen(buf) < sizeof buf - 1) {
172 return;
173 }
174 if (strlen(buf) == sizeof buf - 1 && buf[strlen(buf) - 1] != '\n') {
175 MSG(WARNING, "logger buffer full! flushing output:\n");
176 }
177 log_msg(level, "%s", buf);
178 buf[0] = '\0';
179}
180
181#ifdef HAVE_CONFIG_H // built inside UG
182ADD_TO_PARAM("lavc-log-level",
183 "* lavc-log-level=<num>\n"
184 " Set libavcodec log level (FFmpeg range semantics, bypasses UG logger)\n"
185 " - 'D' - use FFmpeg default log handler\n");
186#endif
189 const char *param = NULL;
190#ifdef HAVE_CONFIG_H // built inside UG
191 param = get_commandline_param("lavc-log-level");
192#endif
193 if (param == NULL) {
194 av_log_set_callback(av_log_ug_callback);
195 return;
196 }
197 char *endptr = NULL;
198 const long av_log_level = strtol(param, &endptr, 10);
199 if (av_log_level < AV_LOG_QUIET || av_log_level > AV_LOG_TRACE ||
200 endptr == param) {
201 MSG(ERROR, "Wrong log level for FFmpeg '%s'\n", param);
202 }
203 av_log_set_level((int) av_log_level);
204}
205
207int av_pixfmt_get_subsampling(enum AVPixelFormat fmt) {
208 const struct AVPixFmtDescriptor *pd = av_pix_fmt_desc_get(fmt);
209 if (pd->log2_chroma_w == 0 && pd->log2_chroma_h == 0) {
210 return 4440;
211 }
212 if (pd->log2_chroma_w == 1 && pd->log2_chroma_h == 0) {
213 return 4220;
214 }
215 if (pd->log2_chroma_w == 1 && pd->log2_chroma_h == 1) {
216 return 4200;
217 }
218 return 0; // other (todo)
219}
220
221struct pixfmt_desc av_pixfmt_get_desc(enum AVPixelFormat pixfmt) {
222 struct pixfmt_desc ret = { 0 };
223 const struct AVPixFmtDescriptor *avd = av_pix_fmt_desc_get(pixfmt);
224 ret.depth = avd->comp[0].depth;
225 ret.rgb = avd->flags & AV_PIX_FMT_FLAG_RGB;
227 return ret;
228}
229
230
231void lavd_flush(AVCodecContext *codec_ctx) {
232#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100)
233 int ret = 0;
234 char errbuf[AV_ERROR_MAX_STRING_SIZE];
235 ret = avcodec_send_packet(codec_ctx, NULL);
236 if (ret != 0) {
237 av_strerror(ret, errbuf, sizeof errbuf);
240 "lavd_flush send - unexpected return value: %s (%d)\n",
241 errbuf, ret);
242 }
243 AVFrame *frame = av_frame_alloc();
244 do {
245 ret = avcodec_receive_frame(codec_ctx, frame);
246 } while (ret >= 0 && ret != AVERROR_EOF && ret != AVERROR(EAGAIN));
247 if (ret < 0 && ret != AVERROR_EOF && ret != AVERROR(EAGAIN)) {
248 av_strerror(ret, errbuf, sizeof errbuf);
251 "lavd_flush recv - unexpected return value: %s (%d)\n",
252 errbuf, ret);
253 }
254 av_frame_free(&frame);
255#else
256 UNUSED(codec_ctx);
257#endif
258}
259void print_decoder_error(const char *mod_name, int rc) {
260 char buf[1024];
261 switch (rc) {
262 case 0:
263 break;
264 case EAGAIN:
266 "%sNo frame returned - needs more input data.\n",
267 mod_name);
268 break;
269 case EINVAL:
270 log_msg(LOG_LEVEL_ERROR, "%sDecoder in invalid state!\n",
271 mod_name);
272 break;
273 default:
274 av_strerror(rc, buf, sizeof buf);
276 "%sError while decoding frame (rc == %d): %s.\n",
277 mod_name, rc, buf);
278 break;
279 }
280}
281
282const char *lavc_thread_type_to_str(int thread_type) {
283 static _Thread_local char buf[128];
284 memset(buf, 0, sizeof buf);
285 if ((thread_type & FF_THREAD_FRAME) != 0) {
286 strncpy(buf, "thread", sizeof buf - 1);
287 }
288 if ((thread_type & FF_THREAD_SLICE) != 0) {
289 if (strlen(buf) > 0) {
290 strncpy(buf, ", ", sizeof buf - 1);
291 }
292 strncpy(buf, "slice", sizeof buf - 1);
293 }
294 if (strlen(buf) == 0) {
295 return "(other)";
296 }
297 return buf;
298}
299
300struct audio_desc
301audio_desc_from_av_frame(const AVFrame *frm)
302{
303 struct audio_desc desc = { 0 };
304 desc.bps = av_get_bytes_per_sample(frm->format);
305 #if FF_API_NEW_CHANNEL_LAYOUT
306 desc.ch_count = frm->ch_layout.nb_channels;
307#else
308 desc.ch_count = av_get_channel_layout_nb_channels(frm->channel_layout);
309#endif
310 desc.codec = AC_PCM;
311 desc.sample_rate = frm->sample_rate;
312
313 return desc;
314}
315
316enum AVSampleFormat
318{
319 switch (bps) {
320 case 1:
321 return planar ? AV_SAMPLE_FMT_U8P : AV_SAMPLE_FMT_U8;
322 case 2:
323 return planar ? AV_SAMPLE_FMT_S16P : AV_SAMPLE_FMT_S16;
324 break;
325 case 3:
326 case 4:
327 return planar ? AV_SAMPLE_FMT_S32P : AV_SAMPLE_FMT_S32;
328 break;
329 default:
330 abort();
331 }
332}
333
338const char *
339get_avpixfmts_names(const enum AVPixelFormat *pixfmts)
340{
341 _Thread_local static char buf[STR_LEN];
342 if (pixfmts == NULL || *pixfmts == AV_PIX_FMT_NONE) {
343 snprintf(buf, sizeof buf, "(none)");
344 return buf;
345 }
346 buf[0] = '\0';
347 const enum AVPixelFormat *it = pixfmts;
348 while (*it != AV_PIX_FMT_NONE) {
349 snprintf(buf + strlen(buf), sizeof buf - strlen(buf), "%s%s",
350 it != pixfmts ? " " : "", av_get_pix_fmt_name(*it));
351 it++;
352 }
353 return buf;
354}
355/* vi: set expandtab sw=8: */
#define UNUSED(x)
struct video_desc desc
struct video_frame * frame
const char * fmt
@ AC_PCM
Definition types.h:53
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#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_WARNING
less severe errors
Definition debug.h:60
const char * get_commandline_param(const char *key)
Definition host.cpp:894
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
volatile int log_level
Definition debug.cpp:65
codec_t get_av_to_ug_codec(enum AVCodecID av_codec)
Definition lavc_common.c:79
enum AVSampleFormat audio_bps_to_av_sample_fmt(int bps, bool planar)
const char * lavc_thread_type_to_str(int thread_type)
codec_t uv
Definition lavc_common.c:65
struct audio_desc audio_desc_from_av_frame(const AVFrame *frm)
static _Bool av_log_filter(const char *ff_module_name, const char *fmt)
void print_decoder_error(const char *mod_name, int rc)
struct pixfmt_desc av_pixfmt_get_desc(enum AVPixelFormat pixfmt)
enum AVCodecID get_ug_to_av_codec(codec_t ug_codec)
Definition lavc_common.c:89
void lavd_flush(AVCodecContext *codec_ctx)
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.
enum AVCodecID av
Definition lavc_common.c:64
int av_pixfmt_get_subsampling(enum AVPixelFormat fmt)
void printf_libav_error(int verbosity, int rc, const char *msg,...)
#define MOD_NAME
Definition lavc_common.c:58
bool libav_codec_has_extradata(codec_t codec)
static int av_to_uv_log(int level)
static const struct @21 av_to_uv_map[]
void print_libav_error(int verbosity, const char *msg, int rc)
static void av_log_ug_callback(void *avcl, int av_level, const char *fmt, va_list vl)
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
const char * param
Definition settings.cpp:195
int bps
Definition types.h:77
int depth
bit depth; 0 means that whole struct is undefined
Definition types.h:140
bool rgb
Definition types.h:142
int subsampling
in 'JabA' format, eg. '4444'
Definition types.h:141
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
codec_t ug_codec
Definition v4l2_common.h:68
This is an umbrella header for video functions.
int vsnprintf(char *s, size_t buf_size, const char *format, va_list ap)
Definition vsnprintf.c:46