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