Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "libav_deps.h" // MUST BE INCLUDED FIRST
19 : #include "string_utils.h"
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 : #include "logger.h"
25 :
26 : #include <algorithm>
27 : #include <string>
28 : #include <mutex>
29 :
30 : extern "C" {
31 : #if LIBAVUTIL_VERSION_MAJOR < 56
32 : AVFrameSideData*
33 : av_frame_new_side_data_from_buf(AVFrame* frame, enum AVFrameSideDataType type, AVBufferRef* buf)
34 : {
35 : auto side_data = av_frame_new_side_data(frame, type, 0);
36 : av_buffer_unref(&side_data->buf);
37 : side_data->buf = buf;
38 : side_data->data = side_data->buf->data;
39 : side_data->size = side_data->buf->size;
40 : return side_data;
41 : }
42 : #endif
43 : }
44 :
45 : namespace jami {
46 : namespace libav_utils {
47 :
48 : AVSampleFormat
49 232 : choose_sample_fmt(const AVCodec* codec, const AVSampleFormat* preferred_formats, int preferred_formats_count)
50 : {
51 : #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
52 232 : const void* supportedConfig = nullptr;
53 232 : if (avcodec_get_supported_config(nullptr, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, &supportedConfig, nullptr) < 0)
54 0 : return AV_SAMPLE_FMT_NONE;
55 232 : const auto* supportedFormats = static_cast<const AVSampleFormat*>(supportedConfig);
56 : #else
57 : const auto* supportedFormats = codec->sample_fmts;
58 : #endif
59 232 : if (!supportedFormats)
60 1 : return preferred_formats_count > 0 ? preferred_formats[0] : AV_SAMPLE_FMT_NONE;
61 :
62 231 : for (int i = 0; i < preferred_formats_count; ++i) {
63 462 : for (const auto* it = supportedFormats; *it != AV_SAMPLE_FMT_NONE; ++it) {
64 462 : if (*it == preferred_formats[i])
65 231 : return preferred_formats[i];
66 : }
67 : }
68 0 : return AV_SAMPLE_FMT_NONE;
69 : }
70 :
71 : AVSampleFormat
72 232 : choose_sample_fmt_default(const AVCodec* codec, AVSampleFormat defaultFormat)
73 : {
74 : // List of supported formats, current default first
75 232 : const AVSampleFormat preferred_formats[] = {defaultFormat,
76 : AV_SAMPLE_FMT_FLTP,
77 : AV_SAMPLE_FMT_FLT,
78 : AV_SAMPLE_FMT_S16P,
79 : AV_SAMPLE_FMT_S16,
80 : AV_SAMPLE_FMT_DBLP,
81 : AV_SAMPLE_FMT_DBL,
82 : AV_SAMPLE_FMT_S32P,
83 232 : AV_SAMPLE_FMT_S32};
84 464 : return choose_sample_fmt(codec, preferred_formats, sizeof(preferred_formats) / sizeof(preferred_formats[0]));
85 : }
86 :
87 : #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
88 : // protect libav/ffmpeg access
89 : static int
90 : avcodecManageMutex(void** data, enum AVLockOp op)
91 : {
92 : auto mutex = reinterpret_cast<std::mutex**>(data);
93 : int ret = 0;
94 : switch (op) {
95 : case AV_LOCK_CREATE:
96 : try {
97 : *mutex = new std::mutex;
98 : } catch (const std::bad_alloc& e) {
99 : return AVERROR(ENOMEM);
100 : }
101 : break;
102 : case AV_LOCK_OBTAIN:
103 : (*mutex)->lock();
104 : break;
105 : case AV_LOCK_RELEASE:
106 : (*mutex)->unlock();
107 : break;
108 : case AV_LOCK_DESTROY:
109 : delete *mutex;
110 : *mutex = nullptr;
111 : break;
112 : default:
113 : #ifdef AVERROR_BUG
114 : return AVERROR_BUG;
115 : #else
116 : break;
117 : #endif
118 : }
119 : return AVERROR(ret);
120 : }
121 : #endif
122 :
123 : static constexpr const char* AVLOGLEVEL = "AVLOGLEVEL";
124 :
125 : static void
126 45 : setAvLogLevel()
127 : {
128 45 : char* envvar = getenv(AVLOGLEVEL);
129 45 : signed level = AV_LOG_WARNING;
130 :
131 45 : if (envvar != nullptr) {
132 0 : level = to_int<int>(envvar, AV_LOG_ERROR);
133 0 : level = std::max(AV_LOG_QUIET, std::min(level, AV_LOG_DEBUG));
134 : }
135 45 : av_log_set_level(level);
136 45 : }
137 :
138 : #ifdef __ANDROID__
139 : static void
140 : androidAvLogCb(void* ptr, int level, const char* fmt, va_list vl)
141 : {
142 : if (level > av_log_get_level())
143 : return;
144 :
145 : char line[1024];
146 : int print_prefix = 1;
147 : int android_level;
148 : va_list vl2;
149 : va_copy(vl2, vl);
150 : av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
151 : va_end(vl2);
152 :
153 : // replace unprintable characters with '?'
154 : int idx = 0;
155 : while (line[idx]) {
156 : if (line[idx] < 0x08 || (line[idx] > 0x0D && line[idx] < 0x20))
157 : line[idx] = '?';
158 : ++idx;
159 : }
160 :
161 : switch (level) {
162 : case AV_LOG_QUIET:
163 : android_level = ANDROID_LOG_SILENT;
164 : break;
165 : case AV_LOG_PANIC:
166 : android_level = ANDROID_LOG_FATAL;
167 : break;
168 : case AV_LOG_FATAL:
169 : android_level = ANDROID_LOG_FATAL;
170 : break;
171 : case AV_LOG_ERROR:
172 : android_level = ANDROID_LOG_ERROR;
173 : break;
174 : case AV_LOG_WARNING:
175 : android_level = ANDROID_LOG_WARN;
176 : break;
177 : case AV_LOG_INFO:
178 : android_level = ANDROID_LOG_INFO;
179 : break;
180 : case AV_LOG_VERBOSE:
181 : android_level = ANDROID_LOG_INFO;
182 : break;
183 : case AV_LOG_DEBUG:
184 : android_level = ANDROID_LOG_DEBUG;
185 : break;
186 : case AV_LOG_TRACE:
187 : android_level = ANDROID_LOG_VERBOSE;
188 : break;
189 : default:
190 : android_level = ANDROID_LOG_DEFAULT;
191 : break;
192 : }
193 : __android_log_print(android_level, "FFmpeg", "%s", line);
194 : }
195 : #endif
196 :
197 : static void
198 45 : init_once()
199 : {
200 : #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
201 : av_register_all();
202 : #endif
203 45 : avdevice_register_all();
204 45 : avformat_network_init();
205 : #if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(7, 13, 100)
206 : avfilter_register_all();
207 : #endif
208 :
209 : #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
210 : av_lockmgr_register(avcodecManageMutex);
211 : #endif
212 :
213 45 : setAvLogLevel();
214 :
215 : #ifdef __ANDROID__
216 : // android doesn't like stdout and stderr :(
217 : av_log_set_callback(androidAvLogCb);
218 : #endif
219 45 : }
220 :
221 : static std::once_flag already_called;
222 :
223 : void
224 67 : av_init()
225 : {
226 67 : std::call_once(already_called, init_once);
227 67 : }
228 :
229 : bool
230 0 : is_yuv_planar(const AVPixFmtDescriptor& desc)
231 : {
232 0 : if (not(desc.flags & AV_PIX_FMT_FLAG_PLANAR) or desc.flags & AV_PIX_FMT_FLAG_RGB)
233 0 : return false;
234 :
235 : /* handle formats that do not use all planes */
236 0 : unsigned used_bit_mask = (1u << desc.nb_components) - 1;
237 0 : for (unsigned i = 0; i < desc.nb_components; ++i)
238 0 : used_bit_mask &= ~(1u << desc.comp[i].plane);
239 :
240 0 : return not used_bit_mask;
241 : }
242 :
243 : std::string
244 86 : getError(int err)
245 : {
246 86 : std::string ret(AV_ERROR_MAX_STRING_SIZE, '\0');
247 86 : av_strerror(err, (char*) ret.data(), ret.size());
248 86 : return ret;
249 0 : }
250 :
251 : const char*
252 59 : getDictValue(const AVDictionary* d, const std::string& key, int flags)
253 : {
254 59 : auto* kv = av_dict_get(d, key.c_str(), nullptr, flags);
255 59 : if (kv)
256 59 : return kv->value;
257 : else
258 0 : return "";
259 : }
260 :
261 : void
262 198 : setDictValue(AVDictionary** d, const std::string& key, const std::string& value, int flags)
263 : {
264 198 : av_dict_set(d, key.c_str(), value.c_str(), flags);
265 198 : }
266 :
267 : void
268 15769 : fillWithBlack(AVFrame* frame)
269 : {
270 15769 : const AVPixelFormat format = static_cast<AVPixelFormat>(frame->format);
271 15769 : const int planes = av_pix_fmt_count_planes(format);
272 : // workaround for casting pointers to different sizes
273 : // on 64 bit machines: sizeof(ptrdiff_t) != sizeof(int)
274 : ptrdiff_t linesizes[4];
275 63076 : for (int i = 0; i < planes; ++i)
276 47307 : linesizes[i] = frame->linesize[i];
277 15769 : int ret = av_image_fill_black(frame->data, linesizes, format, frame->color_range, frame->width, frame->height);
278 15769 : if (ret < 0) {
279 0 : JAMI_ERROR("Failed to blacken frame");
280 : }
281 15769 : }
282 :
283 : void
284 0 : fillWithSilence(AVFrame* frame)
285 : {
286 0 : int ret = av_samples_set_silence(frame->extended_data,
287 : 0,
288 : frame->nb_samples,
289 : frame->ch_layout.nb_channels,
290 0 : (AVSampleFormat) frame->format);
291 0 : if (ret < 0)
292 0 : JAMI_ERROR("Failed to fill frame with silence");
293 0 : }
294 :
295 : AudioFormat
296 6 : getFormat(const AVFrame* frame)
297 : {
298 12 : return AudioFormat {static_cast<unsigned>(frame->sample_rate),
299 6 : static_cast<unsigned>(frame->ch_layout.nb_channels),
300 6 : static_cast<AVSampleFormat>(frame->format)};
301 : }
302 :
303 : } // namespace libav_utils
304 : } // namespace jami
|