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