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 : #ifdef HAVE_CONFIG_H
20 : #include "config.h"
21 : #endif
22 : #include "logger.h"
23 : #include "system_codec_container.h"
24 : #include "media_encoder.h"
25 :
26 : #include <sstream>
27 :
28 : #ifdef APPLE
29 : #include <TargetConditionals.h>
30 : #endif
31 :
32 : namespace jami {
33 :
34 36 : SystemCodecContainer::SystemCodecContainer() {}
35 :
36 36 : SystemCodecContainer::~SystemCodecContainer() {}
37 :
38 : void
39 36 : SystemCodecContainer::initCodecConfig()
40 : {
41 : #ifdef ENABLE_VIDEO
42 36 : auto minH264 = SystemCodecInfo::DEFAULT_H264_MIN_QUALITY;
43 36 : auto maxH264 = SystemCodecInfo::DEFAULT_H264_MAX_QUALITY;
44 36 : auto minH265 = SystemCodecInfo::DEFAULT_H264_MIN_QUALITY;
45 36 : auto maxH265 = SystemCodecInfo::DEFAULT_H264_MAX_QUALITY;
46 36 : auto minVP8 = SystemCodecInfo::DEFAULT_VP8_MIN_QUALITY;
47 36 : auto maxVP8 = SystemCodecInfo::DEFAULT_VP8_MAX_QUALITY;
48 36 : auto defaultBitrate = SystemCodecInfo::DEFAULT_VIDEO_BITRATE;
49 : #endif
50 504 : availableCodecList_ = {
51 : #ifdef ENABLE_VIDEO
52 : /* Define supported video codec*/
53 0 : std::make_shared<SystemVideoCodecInfo>(AV_CODEC_ID_HEVC,
54 0 : AV_CODEC_ID_HEVC,
55 : "H.265/HEVC",
56 : "H265",
57 : "",
58 0 : CODEC_ENCODER_DECODER,
59 : defaultBitrate,
60 : minH265,
61 : maxH265),
62 :
63 0 : std::make_shared<SystemVideoCodecInfo>(AV_CODEC_ID_H264,
64 0 : AV_CODEC_ID_H264,
65 : "H.264/AVC",
66 : "H264",
67 : "libx264",
68 36 : CODEC_ENCODER_DECODER,
69 : defaultBitrate,
70 : minH264,
71 : maxH264),
72 :
73 0 : std::make_shared<SystemVideoCodecInfo>(AV_CODEC_ID_VP8,
74 0 : AV_CODEC_ID_VP8,
75 : "VP8",
76 : "VP8",
77 : "libvpx",
78 36 : CODEC_ENCODER_DECODER,
79 : defaultBitrate,
80 : minVP8,
81 : maxVP8),
82 : #if !(defined(TARGET_OS_IOS) && TARGET_OS_IOS)
83 0 : std::make_shared<SystemVideoCodecInfo>(
84 36 : AV_CODEC_ID_MPEG4, AV_CODEC_ID_MPEG4, "MP4V-ES", "MP4V-ES", "mpeg4", CODEC_ENCODER_DECODER, defaultBitrate),
85 :
86 0 : std::make_shared<SystemVideoCodecInfo>(
87 36 : AV_CODEC_ID_H263, AV_CODEC_ID_H263, "H.263", "H263-1998", "h263", CODEC_ENCODER_DECODER, defaultBitrate),
88 : #endif
89 :
90 : #endif
91 : /* Define supported audio codec*/
92 :
93 0 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_OPUS,
94 0 : AV_CODEC_ID_OPUS,
95 : "Opus",
96 : "opus",
97 : "libopus",
98 0 : CODEC_ENCODER_DECODER,
99 0 : 0,
100 0 : 48000,
101 0 : 2,
102 0 : 104,
103 36 : AV_SAMPLE_FMT_FLT),
104 :
105 0 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_ADPCM_G722,
106 0 : AV_CODEC_ID_ADPCM_G722,
107 : "G.722",
108 : "G722",
109 : "g722",
110 0 : CODEC_ENCODER_DECODER,
111 0 : 0,
112 0 : 16000,
113 0 : 1,
114 36 : 9),
115 :
116 0 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_ADPCM_G726,
117 0 : AV_CODEC_ID_ADPCM_G726,
118 : "G.726",
119 : "G726-32",
120 : "g726",
121 0 : CODEC_ENCODER_DECODER,
122 0 : 0,
123 0 : 8000,
124 0 : 1,
125 36 : 2),
126 :
127 0 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_SPEEX | 0x20000000,
128 0 : AV_CODEC_ID_SPEEX,
129 : "Speex",
130 : "speex",
131 : "libspeex",
132 0 : CODEC_ENCODER_DECODER,
133 0 : 0,
134 0 : 32000,
135 0 : 1,
136 36 : 112),
137 :
138 0 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_SPEEX | 0x10000000,
139 0 : AV_CODEC_ID_SPEEX,
140 : "Speex",
141 : "speex",
142 : "libspeex",
143 0 : CODEC_ENCODER_DECODER,
144 0 : 0,
145 0 : 16000,
146 0 : 1,
147 36 : 111),
148 :
149 0 : std::make_shared<SystemAudioCodecInfo>(
150 36 : AV_CODEC_ID_SPEEX, AV_CODEC_ID_SPEEX, "Speex", "speex", "libspeex", CODEC_ENCODER_DECODER, 0, 8000, 1, 110),
151 :
152 0 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_PCM_ALAW,
153 0 : AV_CODEC_ID_PCM_ALAW,
154 : "G.711a",
155 : "PCMA",
156 : "pcm_alaw",
157 0 : CODEC_ENCODER_DECODER,
158 0 : 64,
159 0 : 8000,
160 0 : 1,
161 36 : 8),
162 :
163 36 : std::make_shared<SystemAudioCodecInfo>(AV_CODEC_ID_PCM_MULAW,
164 0 : AV_CODEC_ID_PCM_MULAW,
165 : "G.711u",
166 : "PCMU",
167 : "pcm_mulaw",
168 0 : CODEC_ENCODER_DECODER,
169 0 : 64,
170 0 : 8000,
171 0 : 1,
172 36 : 0),
173 504 : };
174 72 : }
175 :
176 : void
177 36 : SystemCodecContainer::init(bool enableAcceleration)
178 : {
179 36 : initCodecConfig();
180 36 : setActiveH265(enableAcceleration);
181 36 : checkInstalledCodecs();
182 36 : }
183 :
184 : bool
185 36 : SystemCodecContainer::setActiveH265(bool enableAcceleration)
186 : {
187 : #if (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
188 : removeCodecByName("H265");
189 : return false;
190 : #endif
191 :
192 : #if defined(ENABLE_VIDEO) && defined(ENABLE_HWACCEL)
193 36 : if (not enableAcceleration) {
194 36 : removeCodecByName("H265");
195 36 : return false;
196 : }
197 :
198 0 : auto apiName = MediaEncoder::testH265Accel();
199 0 : if (apiName != "") {
200 0 : JAMI_WARNING("Found a usable accelerated H265/HEVC codec: {}, enabling.", apiName);
201 0 : return true;
202 : } else {
203 0 : JAMI_WARNING("Unable to find a usable accelerated H265/HEVC codec, disabling.");
204 0 : removeCodecByName("H265");
205 : }
206 : #else
207 : removeCodecByName("H265");
208 : #endif
209 0 : return false;
210 0 : }
211 :
212 : void
213 36 : SystemCodecContainer::checkInstalledCodecs()
214 : {
215 36 : std::ostringstream enc_ss;
216 36 : std::ostringstream dec_ss;
217 :
218 468 : for (const auto& codecIt : availableCodecList_) {
219 432 : AVCodecID codecId = (AVCodecID) codecIt->avcodecId;
220 432 : CodecType codecType = codecIt->codecType;
221 :
222 432 : if (codecType & CODEC_ENCODER) {
223 432 : if (avcodec_find_encoder(codecId) != nullptr)
224 432 : enc_ss << codecIt->name << ' ';
225 : else
226 0 : codecIt->codecType = (CodecType) ((unsigned) codecType & ~CODEC_ENCODER);
227 : }
228 :
229 432 : if (codecType & CODEC_DECODER) {
230 432 : if (avcodec_find_decoder(codecId) != nullptr)
231 432 : dec_ss << codecIt->name << ' ';
232 : else
233 0 : codecIt->codecType = (CodecType) ((unsigned) codecType & ~CODEC_DECODER);
234 : }
235 : }
236 144 : JAMI_LOG("Encoders found: {}", enc_ss.str());
237 144 : JAMI_LOG("Decoders found: {}", dec_ss.str());
238 36 : }
239 :
240 : std::vector<std::shared_ptr<SystemCodecInfo>>
241 802 : SystemCodecContainer::getSystemCodecInfoList(MediaType mediaType)
242 : {
243 802 : if (mediaType & MEDIA_ALL)
244 802 : return availableCodecList_;
245 :
246 : // otherwise we have to instantiate a new list containing filtered objects
247 : // must be destroyed by the caller…
248 0 : std::vector<std::shared_ptr<SystemCodecInfo>> systemCodecList;
249 0 : for (const auto& codecIt : availableCodecList_) {
250 0 : if (codecIt->mediaType & mediaType)
251 0 : systemCodecList.push_back(codecIt);
252 : }
253 0 : return systemCodecList;
254 0 : }
255 :
256 : std::vector<unsigned>
257 0 : SystemCodecContainer::getSystemCodecInfoIdList(MediaType mediaType)
258 : {
259 0 : std::vector<unsigned> idList;
260 0 : for (const auto& codecIt : availableCodecList_) {
261 0 : if (codecIt->mediaType & mediaType)
262 0 : idList.push_back(codecIt->id);
263 : }
264 0 : return idList;
265 0 : }
266 :
267 : std::shared_ptr<SystemCodecInfo>
268 0 : SystemCodecContainer::searchCodecById(unsigned codecId, MediaType mediaType)
269 : {
270 0 : for (const auto& codecIt : availableCodecList_) {
271 0 : if ((codecIt->id == codecId) && (codecIt->mediaType & mediaType))
272 0 : return codecIt;
273 : }
274 0 : return {};
275 : }
276 : std::shared_ptr<SystemCodecInfo>
277 6 : SystemCodecContainer::searchCodecByName(const std::string& name, MediaType mediaType)
278 : {
279 21 : for (const auto& codecIt : availableCodecList_) {
280 21 : if (codecIt->name == name && (codecIt->mediaType & mediaType))
281 6 : return codecIt;
282 : }
283 0 : return {};
284 : }
285 : std::shared_ptr<SystemCodecInfo>
286 0 : SystemCodecContainer::searchCodecByPayload(unsigned payload, MediaType mediaType)
287 : {
288 0 : for (const auto& codecIt : availableCodecList_) {
289 0 : if ((codecIt->payloadType == payload) && (codecIt->mediaType & mediaType))
290 0 : return codecIt;
291 : }
292 0 : return {};
293 : }
294 : void
295 36 : SystemCodecContainer::removeCodecByName(const std::string& name, MediaType mediaType)
296 : {
297 36 : for (auto codecIt = availableCodecList_.begin(); codecIt != availableCodecList_.end(); ++codecIt) {
298 36 : if ((*codecIt)->mediaType & mediaType and (*codecIt)->name == name) {
299 36 : availableCodecList_.erase(codecIt);
300 36 : break;
301 : }
302 : }
303 36 : }
304 :
305 : } // namespace jami
|