UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
channel_remap.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2024 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#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif /* HAVE_CONFIG_H */
43
44#include <memory>
45#include <string_view>
46
47#include "debug.h"
48#include "module.h"
49#include "audio/audio_filter.h"
50#include "audio/types.h"
51#include "audio/utils.h"
52#include "lib_common.h"
53#include "utils/misc.h"
55
56#define MOD_NAME "[Remap filter] "
57
60
62
63 int bps = 0;
64 int ch_count = 0;
65 int sample_rate = 0;
66
68
69 std::vector<char> out_buffer;
71};
72
73static void usage(){
74 color_printf("Audio filter " TBOLD(
75 "channel_remap") " allows remapping audio channels.\n\n");
76 color_printf("Usage:\n");
77 color_printf("\t" TBOLD("--audio-filter channel_remap:[<src_ch>]:<dst_ch>[,[<src_ch>]:<dst_ch>]...\n\n"));
78 color_printf("(indexed from zero)\n");
79 color_printf("Maps source channels into destination channels.\n");
80 color_printf("If multiple source channels are mapped into the same destination channel, they are mixed together.\n");
81 color_printf("E.g. 0:0,1:0 means that the first and second channel are mixed to produce a single mono channel.\n");
82 color_printf("2:0,3:1 means that the third and fourth channel are mapped into first and second channel respectively.\n");
83}
84
85static af_result_code init(struct module *parent, const char *cfg, void **state){
86 auto s = std::make_unique<state_channel_remap>(parent);
87
88 if(strcmp(cfg, "help") == 0){
89 usage();
90 return AF_HELP_SHOWN;
91 }
92
93 if(!parse_channel_map_cfg(&s->channel_map, cfg)){
94 return AF_FAILURE;
95 }
96
97 assert(s->channel_map.size > 0);
98
99 *state = s.release();
100
101 return AF_OK;
102};
103
105 int in_bps, int in_ch_count, int in_sample_rate)
106{
107 auto s = static_cast<state_channel_remap *>(state);
108
109 s->bps = in_bps;
110 s->ch_count = in_ch_count;
111 s->sample_rate = in_sample_rate;
112
113 s->out_frame.bps = s->bps;
114 s->out_frame.sample_rate = s->sample_rate;
115
116 if(s->channel_map.size > in_ch_count){
117 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Audio channel map references channels with idx higher than ch. count!\n");
118 }
119
120 return AF_OK;
121}
122
123static void done(void *state){
124 auto s = static_cast<state_channel_remap *>(state);
125
126 delete s;
127}
128
129static void get_configured_in(void *state,
130 int *bps, int *ch_count, int *sample_rate)
131{
132 auto s = static_cast<state_channel_remap *>(state);
133
134 if(bps) *bps = s->bps;
135 if(ch_count) *ch_count = s->ch_count;
136 if(sample_rate) *sample_rate = s->sample_rate;
137}
138
139static void get_configured_out(void *state,
140 int *bps, int *ch_count, int *sample_rate)
141{
142 auto s = static_cast<state_channel_remap *>(state);
143
144 if(bps) *bps = s->bps;
145 if(ch_count) *ch_count = s->channel_map.max_output + 1;
146 if(sample_rate) *sample_rate = s->sample_rate;
147}
148
150 auto s = static_cast<state_channel_remap *>(state);
151 auto f = *frame;
152
153 if(f->bps != s->bps || f->ch_count != s->ch_count){
154 if(configure(state, f->bps, f->ch_count, f->sample_rate) != AF_OK){
155 return AF_MISCONFIGURED;
156 }
157 }
158
159 int frame_count = f->data_len / f->ch_count / f->bps;
160
161 s->out_frame.ch_count = s->channel_map.max_output + 1;
162 s->out_frame.data_len = frame_count * s->out_frame.bps * s->out_frame.ch_count;
163 if(s->out_frame.data_len > s->out_frame.max_size){
164 s->out_frame.max_size = s->out_frame.data_len;
165 s->out_buffer.resize(s->out_frame.max_size);
166 s->out_frame.data = s->out_buffer.data();
167 }
168
169 memset(s->out_frame.data, 0, s->out_frame.data_len);
170
171 int max_src_count = std::min(s->channel_map.size, f->ch_count);
172
173 for(int src_ch = 0; src_ch < max_src_count; src_ch++){
174 for(int dst_ch = 0; dst_ch < s->channel_map.sizes[src_ch]; dst_ch++){
175 remux_and_mix_channel(s->out_frame.data, f->data,
176 s->bps, frame_count,
177 f->ch_count, s->out_frame.ch_count,
178 src_ch, s->channel_map.map[src_ch][dst_ch], 1.0);
179 }
180 }
181
182 s->out_frame.timestamp = f->timestamp;
183
184 *frame = &s->out_frame;
185
186 return AF_OK;
187}
188
190 .name = "channel_remap",
191 .init = init,
192 .done = done,
193 .configure = configure,
194 .get_configured_in = get_configured_in,
195 .get_configured_out = get_configured_out,
196 .filter = filter,
197};
198
void ** state
int int int sample_rate
struct video_frame * frame
This file contains definition of some common audio types.
#define AUDIO_FILTER_ABI_VERSION
af_result_code
@ AF_FAILURE
@ AF_MISCONFIGURED
@ AF_HELP_SHOWN
@ AF_OK
static void get_configured_in(void *state, int *bps, int *ch_count, int *sample_rate)
static af_result_code filter(void *state, struct audio_frame **frame)
static void usage()
#define MOD_NAME
static af_result_code init(struct module *parent, const char *cfg, void **state)
static af_result_code configure(void *state, int in_bps, int in_ch_count, int in_sample_rate)
static void get_configured_out(void *state, int *bps, int *ch_count, int *sample_rate)
static const struct audio_filter_info audio_filter_channel_remap
static void done(void *state)
int color_printf(const char *format,...)
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
@ MODULE_CLASS_DATA
Definition module.h:86
@ LIBRARY_CLASS_AUDIO_FILTER
Definition lib_common.h:85
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
const char * parent
Definition settings.cpp:198
struct used to comunicate with audio capture/playback device
Definition types.h:99
int ch_count
Definition types.h:104
int bps
Definition types.h:100
state_channel_remap(struct module *mod)
struct audio_frame out_frame
std::vector< char > out_buffer
void remux_and_mix_channel(char *out, const char *in, int bps, int frames, int in_stream_channels, int out_stream_channels, int in_channel, int out_channel, double scale)
Definition utils.cpp:423
bool parse_channel_map_cfg(struct channel_map *channel_map, const char *cfg)
Definition utils.cpp:716