UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
codec.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include "config_unix.h"
39#include "config_win32.h"
40
41#include <algorithm>
42#include <cassert>
43#include <climits>
44#include <string>
45#include <unordered_map>
46
47#include "audio/codec.h"
48#include "audio/utils.h"
49#include "compat/strings.h" // strdup, strcasecmp
50#include "debug.h"
51#include "lib_common.h"
52#include "utils/macros.h"
53#include "utils/misc.h"
54
55#define MOD_NAME "[acodec] "
56
57using std::get;
58using std::hash;
59using std::max;
60using std::stoi;
61using std::string;
62using std::tuple;
63using std::unordered_map;
64using std::vector;
65
66static const unordered_map<audio_codec_t, audio_codec_info_t, hash<int>>
68 {AC_NONE, { "(none)", 0 } },
69 { AC_PCM, { "PCM", 0x0001 } },
70 { AC_ALAW, { "A-law", 0x0006 } },
71 { AC_MULAW, { "u-law", 0x0007 } },
72 { AC_SPEEX, { "speex", 0xA109 } },
73 { AC_OPUS, // fcc is "Opus", the TwoCC isn't defined
74 { "Opus", 0x7375704F }},
75 { AC_G722, { "G.722", 0x028F } },
76 { AC_MP3, { "MP3", 0x0055 } },
77 { AC_AAC, { "AAC", 0x00FF } },
78 { AC_FLAC, { "FLAC", 0xF1AC } },
79};
80
81static struct audio_codec_state *audio_codec_init_real(const char *audio_codec_cfg,
82 audio_codec_direction_t direction, bool try_init);
83
92
93static string
95{
96 if (st->funcs->get_codec_info == nullptr) {
97 return {};
98 }
99 char buf[STR_LEN];
100 const char *ret =
101 st->funcs->get_codec_info(st->state[0], sizeof buf, buf);
102 if (ret == nullptr) {
103 return {};
104 }
105 return ret;
106}
107
108vector<tuple<audio_codec_info_t, bool, string>>
110{
111 vector<tuple<audio_codec_info_t, bool, string>> ret;
112
113 for (auto const &it : audio_codec_info) {
114 if(it.first != AC_NONE) {
115 struct audio_codec_state *st = (struct audio_codec_state *)
117 AUDIO_CODER, true);
118 bool available = false;
119 string desc;
120 if(st){
121 available = true;
122 desc = get_codec_desc(st);
124 }
125 ret.emplace_back(it.second, available, desc);
126 }
127 }
128
129 return ret;
130}
131
133 printf("Syntax:\n");
134 col() << SBOLD(
135 SRED("\t-A <codec_name>")
136 << "[:sample_rate=<sampling_rate>][:bitrate=<bitrate>]\n");
137 col() << "\nwhere\n";
138 col() << "\t" << SBOLD("codec_name ") << " - one of the list below\n";
139 col() << "\t" << SBOLD("sample_rate")
140 << " - sample rate that will the codec used (may differ from\n"
141 << "\t\t captured)\n";
142 col() << "\t" << SBOLD("bitrate ") << " - codec bitrate "
143 << SBOLD("per channel") << " (with optional k/M suffix)\n";
144 col() << "\n";
145 printf("Supported audio codecs:\n");
146 for (auto const &it : get_audio_codec_list()) {
147 string notes;
148 if (!get<1>(it)) {
149 notes += " " TRED("unavailable");
150 } else {
151 notes = get<2>(it);
152 }
153 col() << SBOLD("\t" << get<0>(it).name)
154 << (notes.empty() ? "" : " - ") << notes << "\n";
155 }
156 col() << "\nCodecs marked as \"deprecated\" may be removed in future.\n"
157 "Codec coder marked with '*' is default.\n";
158}
159
164
165struct audio_codec_state *audio_codec_init_cfg(const char *audio_codec_cfg,
167 return audio_codec_init_real(audio_codec_cfg, direction, false);
168}
169
170
171static struct audio_codec_state *audio_codec_init_real(const char *audio_codec_cfg,
172 audio_codec_direction_t direction, bool silent) {
173 const struct audio_codec_params params =
174 parse_audio_codec_params(audio_codec_cfg);
175 if (params.codec == AC_NONE) {
176 return nullptr;
177 }
178 void *state = NULL;
179 const struct audio_compress_info *aci = nullptr;
180
182
183 for (auto const &it : audio_compressions) {
184 aci = static_cast<const struct audio_compress_info *>(it.second);
185 for (unsigned int j = 0; aci->supported_codecs[j] != AC_NONE; ++j) {
186 if (aci->supported_codecs[j] == params.codec) {
187 state = aci->init(params.codec, direction,
188 silent, params.bitrate);
189 if (state) {
190 break;
191 }
192 if (!silent) {
194 "Error: initialization of "
195 "audio codec failed!\n");
196 }
197 }
198 }
199 if(state)
200 break;
201 }
202
203 if(!state) {
204 if (!silent) {
206 "Unable to find encoder for audio codec '%s'\n",
208 }
209 return NULL;
210 }
211
212 struct audio_codec_state *s = (struct audio_codec_state *) calloc(1, sizeof(struct audio_codec_state));
213
214 s->state = (void **) calloc(1, sizeof(void*));
215 s->state[0] = state;
216 s->state_count = 1;
217 s->funcs = aci;
218 s->desc.codec = params.codec;
219 s->direction = direction;
220 s->bitrate = params.bitrate;
221
222 return s;
223}
224
227{
228 if (old != nullptr && old->desc.codec == audio_codec) {
229 return old;
230 }
231 audio_codec_done(old);
232 return audio_codec_init(audio_codec, direction);
233}
234
246{
247 audio_frame2 res;
248
249 if (frame != nullptr) {
250 if (s->state_count < frame->get_channel_count()) {
251 s->state = (void **) realloc(s->state, sizeof(void *) * frame->get_channel_count());
252 for (int i = s->state_count; i < frame->get_channel_count(); ++i) {
253 s->state[i] = s->funcs->init(s->desc.codec, s->direction, false, s->bitrate);
254 if (s->state[i] == nullptr) {
255 LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Error: initialization of audio codec failed!\n";
256 return {};
257 }
258 }
259 s->state_count = frame->get_channel_count();
260 }
261
262 s->desc.ch_count = frame->get_channel_count();
263 s->desc.bps = frame->get_bps();
264 s->desc.sample_rate = frame->get_sample_rate();
265 res.set_timestamp(frame->get_timestamp());
266 }
267
268 audio_channel channel;
269 channel.timestamp = frame == nullptr ? -1 : frame->get_timestamp();
270 int nonzero_channels = 0;
271 for (int i = 0; i < s->desc.ch_count; ++i) {
272 audio_channel *encode_channel = NULL;
273 if(frame) {
274 audio_channel_demux(frame, i, &channel);
275 encode_channel = &channel;
276 }
277 audio_channel *out = s->funcs->compress(s->state[i], encode_channel);
278 if (out == nullptr) {
279 continue;
280 }
281 if (!res) {
282 res.init(s->desc.ch_count, out->codec, out->bps, out->sample_rate);
283 res.set_duration(out->duration);
284 } else {
285 assert(out->bps == res.get_bps()
286 && out->sample_rate == res.get_sample_rate());
287 }
288 res.append(i, out->data, out->data_len);
289 res.set_timestamp(out->timestamp);
290 nonzero_channels += 1;
291 }
292
293 if (nonzero_channels == 0) {
294 return {};
295 }
296 return res;
297}
298
300{
301 if (s->state_count < frame->get_channel_count()) {
302 s->state = (void **) realloc(s->state, sizeof(void *) * frame->get_channel_count());
303 for(int i = s->state_count; i < frame->get_channel_count(); ++i) {
304 s->state[i] = s->funcs->init(s->desc.codec, s->direction, false, 0);
305 if(s->state[i] == NULL) {
307 "Error: initialization of audio codec "
308 "failed!\n");
309 return {};
310 }
311 }
312 s->state_count = frame->get_channel_count();
313 }
314
315#if 0
316 if (s->out->ch_count != frame->ch_count) {
317 s->out->ch_count = frame->ch_count;
318 }
319#endif
320
321 audio_frame2 ret;
322 audio_channel channel;
323 int nonzero_channels = 0;
324 bool out_frame_initialized = false;
325 for (int i = 0; i < frame->get_channel_count(); ++i) {
326 audio_channel_demux(frame, i, &channel);
327 if (channel.data_len == 0) {
328 continue;
329 }
330 audio_channel *out = s->funcs->decompress(s->state[i], &channel);
331 if (out) {
332 if (!out_frame_initialized) {
333 ret.init(frame->get_channel_count(), AC_PCM, out->bps, out->sample_rate);
334 ret.set_timestamp(frame->get_timestamp());
335 out_frame_initialized = true;
336 } else {
337 assert(out->bps == ret.get_bps()
338 && out->sample_rate == ret.get_sample_rate());
339 }
340 ret.append(i, out->data, out->data_len);
341 nonzero_channels += 1;
342 }
343 }
344
345 if (nonzero_channels != frame->get_channel_count()) {
347 "[Audio decompress] %d empty channel(s) returned!\n",
348 frame->get_channel_count() - nonzero_channels);
349 return {};
350 }
351 int max_len = 0;
352 for(int i = 0; i < frame->get_channel_count(); ++i) {
353 max_len = max<int>(max_len, ret.get_data_len(i));
354 }
355 for(int i = 0; i < frame->get_channel_count(); ++i) {
356 int len = ret.get_data_len(i);
357 if (len != max_len) {
358 LOG(LOG_LEVEL_WARNING) << "[Audio decompress] Inequal channel length detected (" << ret.get_data_len(i) << " vs " << max_len << ")!\n",
359 ret.resize(i, max_len);
360 memset(ret.get_data(i) + len, 0, max_len - len);
361 }
362 }
363
364 return ret;
365}
366
368{
369 return s->funcs->get_samplerates(s->state[0]);
370}
371
373{
374 if(!s)
375 return;
376 for(int i = 0; i < s->state_count; ++i) {
377 s->funcs->done(s->state[i]);
378 }
379 free(s->state);
380
381 free(s);
382}
383
384static audio_codec_t
386{
387 for (auto const &it : audio_codec_info) {
388 if (strcasecmp(it.second.name, codec) == 0) {
389 return it.first;
390 }
391 }
392 if (strcasecmp(codec, "PCMA") == 0) {
393 return AC_ALAW;
394 }
395 if (strcasecmp(codec, "PCMU") == 0) {
396 return AC_MULAW;
397 }
398 return AC_NONE;
399}
400
403{
404 char *cfg = strdupa(ccfg);
405 char *save_ptr = nullptr;
406 char *tmp = cfg;
407 char *item = nullptr;
408
410 };
411 while ((item = strtok_r(tmp, ":", &save_ptr)) != nullptr) {
412 tmp = nullptr;
413 if (params.codec == AC_NONE) {
414 params.codec = get_audio_codec(item);
415 if (params.codec == AC_NONE) {
416 MSG(ERROR,
417 "Unknown audio codec \"%s\" given!\n",
418 item);
419 return {};
420 }
421 continue;
422 }
423 if (IS_KEY_PREFIX(item, "sample_rate")) {
424 params.sample_rate = stoi(strchr(item, '=') + 1);
425 if (params.sample_rate < 0) {
426 MSG(ERROR,
427 "Sample rate cannot be negative! given "
428 "%d\n",
429 params.sample_rate);
430 return {};
431 }
432 } else if (IS_KEY_PREFIX(item, "bitrate")) {
433 const char *val = strchr(item, '=') + 1;
434 const char *endptr = nullptr;
435 long long rate = unit_evaluate(val, &endptr);
436 if (rate <= 0 || rate > INT_MAX || endptr[0] != '\0') {
438 << "Wrong bitrate: " << val << "\n";
439 return {};
440 }
441 params.bitrate = (int) rate;
442 } else {
443 MSG(ERROR, "Unknown audio option: %s\n", item);
444 return {};
445 }
446 }
447 return params;
448}
449
451{
452 return audio_codec_info.at(codec).name;
453}
454
456{
457 return audio_codec_info.at(codec).tag;
458}
459
461{
462 for (auto const &it : audio_codec_info) {
463 if(it.second.tag == tag) {
464 return it.first;
465 }
466 }
467 return AC_NONE;
468}
void ** state
int void * val
struct video_desc desc
struct video_frame * frame
int void size_t * len
audio_codec_t
Definition types.h:51
@ AC_G722
Definition types.h:58
@ AC_AAC
Definition types.h:60
@ AC_OPUS
Definition types.h:57
@ AC_FLAC
Definition types.h:61
@ AC_MULAW
Definition types.h:55
@ AC_SPEEX
Definition types.h:56
@ AC_MP3
Definition types.h:59
@ AC_PCM
Definition types.h:53
@ AC_ALAW
Definition types.h:54
@ AC_NONE
Definition types.h:52
void resize(int channel, size_t len)
Definition types.cpp:183
char * get_data(int channel)
Definition types.cpp:218
void init(int nr_channels, audio_codec_t codec, int bps, int sample_rate)
Initializes audio_frame2 for use. If already initialized, data are dropped.
Definition types.cpp:115
void set_duration(double duration)
Definition types.cpp:288
void set_timestamp(int64_t ts)
Definition types.cpp:335
size_t get_data_len(int channel) const
Definition types.cpp:228
int get_sample_rate() const
Definition types.cpp:275
int get_bps() const
Definition types.cpp:200
void append(audio_frame2 const &frame)
Definition types.cpp:125
static const unordered_map< audio_codec_t, audio_codec_info_t, hash< int > > audio_codec_info
Definition codec.cpp:67
struct audio_codec_state * audio_codec_init_cfg(const char *audio_codec_cfg, audio_codec_direction_t direction)
Definition codec.cpp:165
static string get_codec_desc(struct audio_codec_state *st)
Definition codec.cpp:94
audio_codec_t get_audio_codec_to_tag(uint32_t tag)
Definition codec.cpp:460
struct audio_codec_params parse_audio_codec_params(const char *ccfg)
Definition codec.cpp:402
struct audio_codec_state * audio_codec_init(audio_codec_t audio_codec, audio_codec_direction_t direction)
Definition codec.cpp:160
vector< tuple< audio_codec_info_t, bool, string > > get_audio_codec_list()
Definition codec.cpp:109
audio_frame2 audio_codec_decompress(struct audio_codec_state *s, audio_frame2 *frame)
Definition codec.cpp:299
const char * get_name_to_audio_codec(audio_codec_t codec)
Definition codec.cpp:450
static struct audio_codec_state * audio_codec_init_real(const char *audio_codec_cfg, audio_codec_direction_t direction, bool try_init)
Definition codec.cpp:171
audio_frame2 audio_codec_compress(struct audio_codec_state *s, const audio_frame2 *frame)
Definition codec.cpp:245
static audio_codec_t get_audio_codec(const char *codec)
Definition codec.cpp:385
#define MOD_NAME
Definition codec.cpp:55
struct audio_codec_state * audio_codec_reconfigure(struct audio_codec_state *old, audio_codec_t audio_codec, audio_codec_direction_t direction)
Definition codec.cpp:225
const int * audio_codec_get_supported_samplerates(struct audio_codec_state *s)
Definition codec.cpp:367
uint32_t get_audio_tag(audio_codec_t codec)
Definition codec.cpp:455
void list_audio_codecs(void)
Definition codec.cpp:132
void audio_codec_done(struct audio_codec_state *s)
Definition codec.cpp:372
audio_codec_direction_t
Definition codec.h:45
@ AUDIO_CODER
Definition codec.h:46
#define AUDIO_COMPRESS_ABI_VERSION
Definition codec.h:43
#define SRED(x)
Definition color_out.h:85
#define SBOLD(x)
Definition color_out.h:80
#define TRED(x)
Definition color_out.h:75
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG(level)
Definition debug.h:313
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
static struct @19 params[100]
map< string, const void * > get_libraries_for_class(enum library_class cls, int abi_version, bool include_hidden)
@ LIBRARY_CLASS_AUDIO_COMPRESS
Definition lib_common.h:80
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134
long long unit_evaluate(const char *str, const char **endptr)
Definition misc.cpp:81
#define max(a, b)
Definition rtp.c:98
const char * name
Definition settings.cpp:193
#define strdupa(s)
Definition strings.h:77
Audio channel is a non-owning view on audio_frame2 isolating one channel.
Definition types.h:122
audio_codec_t codec
Definition types.h:127
int64_t timestamp
Definition types.h:128
const char * data
Definition types.h:125
int sample_rate
Definition types.h:124
double duration
Definition types.h:129
int data_len
Definition types.h:126
audio_desc desc
Definition codec.cpp:88
const struct audio_compress_info * funcs
Definition codec.cpp:87
void ** state
Definition codec.cpp:85
audio_codec_direction_t direction
Definition codec.cpp:89
audio_channel *(* compress)(void *, audio_channel *)
Definition codec.h:53
const char *(* get_codec_info)(void *, size_t buflen, char *buffer)
returns additional text data to be printed in help
Definition codec.h:57
void(* done)(void *)
Definition codec.h:58
audio_channel *(* decompress)(void *, audio_channel *)
Definition codec.h:54
const int *(* get_samplerates)(void *)
Definition codec.h:55
void *(* init)(audio_codec_t, audio_codec_direction_t, bool, int bitrate)
Definition codec.h:52
const audio_codec_t * supported_codecs
Definition codec.h:51
int sample_rate
Definition types.h:78
int ch_count
Definition types.h:79
int bps
Definition types.h:77
audio_codec_t codec
Definition types.h:80
Definition hd-rum.c:27
void audio_channel_demux(const audio_frame2 *frame, int index, audio_channel *channel)
Definition utils.cpp:528