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