/src/opus/src/opus_projection_encoder.c
Line | Count | Source |
1 | | /* Copyright (c) 2017 Google Inc. |
2 | | Written by Andrew Allen */ |
3 | | /* |
4 | | Redistribution and use in source and binary forms, with or without |
5 | | modification, are permitted provided that the following conditions |
6 | | are met: |
7 | | |
8 | | - Redistributions of source code must retain the above copyright |
9 | | notice, this list of conditions and the following disclaimer. |
10 | | |
11 | | - Redistributions in binary form must reproduce the above copyright |
12 | | notice, this list of conditions and the following disclaimer in the |
13 | | documentation and/or other materials provided with the distribution. |
14 | | |
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
16 | | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
17 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
18 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
19 | | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
20 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
21 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
22 | | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
23 | | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
24 | | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | | */ |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | #include "config.h" |
30 | | #endif |
31 | | |
32 | | #include "mathops.h" |
33 | | #include "os_support.h" |
34 | | #include "opus_private.h" |
35 | | #include "opus_defines.h" |
36 | | #include "opus_projection.h" |
37 | | #include "opus_multistream.h" |
38 | | #include "stack_alloc.h" |
39 | | #include "mapping_matrix.h" |
40 | | |
41 | | struct OpusProjectionEncoder |
42 | | { |
43 | | opus_int32 mixing_matrix_size_in_bytes; |
44 | | opus_int32 demixing_matrix_size_in_bytes; |
45 | | /* Encoder states go here */ |
46 | | }; |
47 | | |
48 | | #if !defined(DISABLE_FLOAT_API) |
49 | | static void opus_projection_copy_channel_in_float( |
50 | | opus_res *dst, |
51 | | int dst_stride, |
52 | | const void *src, |
53 | | int src_stride, |
54 | | int src_channel, |
55 | | int frame_size, |
56 | | void *user_data |
57 | | ) |
58 | 0 | { |
59 | 0 | mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, |
60 | 0 | (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); |
61 | 0 | } |
62 | | #endif |
63 | | |
64 | | static void opus_projection_copy_channel_in_short( |
65 | | opus_res *dst, |
66 | | int dst_stride, |
67 | | const void *src, |
68 | | int src_stride, |
69 | | int src_channel, |
70 | | int frame_size, |
71 | | void *user_data |
72 | | ) |
73 | 274k | { |
74 | 274k | mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, |
75 | 274k | (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); |
76 | 274k | } |
77 | | |
78 | | static void opus_projection_copy_channel_in_int24( |
79 | | opus_res *dst, |
80 | | int dst_stride, |
81 | | const void *src, |
82 | | int src_stride, |
83 | | int src_channel, |
84 | | int frame_size, |
85 | | void *user_data |
86 | | ) |
87 | 0 | { |
88 | 0 | mapping_matrix_multiply_channel_in_int24((const MappingMatrix*)user_data, |
89 | 0 | (const opus_int32*)src, src_stride, dst, src_channel, dst_stride, frame_size); |
90 | 0 | } |
91 | | |
92 | | static int get_order_plus_one_from_channels(int channels, int *order_plus_one) |
93 | 62.5k | { |
94 | 62.5k | int order_plus_one_; |
95 | 62.5k | int acn_channels; |
96 | 62.5k | int nondiegetic_channels; |
97 | | |
98 | | /* Allowed numbers of channels: |
99 | | * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1. |
100 | | */ |
101 | 62.5k | if (channels < 1 || channels > 227) |
102 | 15 | return OPUS_BAD_ARG; |
103 | | |
104 | 62.5k | order_plus_one_ = isqrt32(channels); |
105 | 62.5k | acn_channels = order_plus_one_ * order_plus_one_; |
106 | 62.5k | nondiegetic_channels = channels - acn_channels; |
107 | 62.5k | if (nondiegetic_channels != 0 && nondiegetic_channels != 2) |
108 | 53 | return OPUS_BAD_ARG; |
109 | | |
110 | 62.4k | if (order_plus_one) |
111 | 62.4k | *order_plus_one = order_plus_one_; |
112 | 62.4k | return OPUS_OK; |
113 | 62.5k | } |
114 | | |
115 | | static int get_streams_from_channels(int channels, int mapping_family, |
116 | | int *streams, int *coupled_streams, |
117 | | int *order_plus_one) |
118 | 62.6k | { |
119 | 62.6k | if (mapping_family == 3) |
120 | 62.5k | { |
121 | 62.5k | if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) |
122 | 68 | return OPUS_BAD_ARG; |
123 | 62.4k | if (streams) |
124 | 62.4k | *streams = (channels + 1) / 2; |
125 | 62.4k | if (coupled_streams) |
126 | 62.4k | *coupled_streams = channels / 2; |
127 | 62.4k | return OPUS_OK; |
128 | 62.5k | } |
129 | 77 | return OPUS_BAD_ARG; |
130 | 62.6k | } |
131 | | |
132 | | static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) |
133 | 61.7k | { |
134 | | /* void* cast avoids clang -Wcast-align warning */ |
135 | 61.7k | return (MappingMatrix *)(void*)((char*)st + |
136 | 61.7k | align(sizeof(OpusProjectionEncoder))); |
137 | 61.7k | } |
138 | | |
139 | | static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st) |
140 | 405k | { |
141 | | /* void* cast avoids clang -Wcast-align warning */ |
142 | 405k | return (MappingMatrix *)(void*)((char*)st + |
143 | 405k | align(sizeof(OpusProjectionEncoder) + |
144 | 405k | st->mixing_matrix_size_in_bytes)); |
145 | 405k | } |
146 | | |
147 | | static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) |
148 | 436k | { |
149 | | /* void* cast avoids clang -Wcast-align warning */ |
150 | 436k | return (OpusMSEncoder *)(void*)((char*)st + |
151 | 436k | align(sizeof(OpusProjectionEncoder) + |
152 | 436k | st->mixing_matrix_size_in_bytes + |
153 | 436k | st->demixing_matrix_size_in_bytes)); |
154 | 436k | } |
155 | | |
156 | | opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, |
157 | | int mapping_family) |
158 | 31.3k | { |
159 | 31.3k | int nb_streams; |
160 | 31.3k | int nb_coupled_streams; |
161 | 31.3k | int order_plus_one; |
162 | 31.3k | int mixing_matrix_rows, mixing_matrix_cols; |
163 | 31.3k | int demixing_matrix_rows, demixing_matrix_cols; |
164 | 31.3k | opus_int32 mixing_matrix_size, demixing_matrix_size; |
165 | 31.3k | opus_int32 encoder_size; |
166 | 31.3k | int ret; |
167 | | |
168 | 31.3k | ret = get_streams_from_channels(channels, mapping_family, &nb_streams, |
169 | 31.3k | &nb_coupled_streams, &order_plus_one); |
170 | 31.3k | if (ret != OPUS_OK) |
171 | 145 | return 0; |
172 | | |
173 | 31.2k | if (order_plus_one == 2) |
174 | 21.2k | { |
175 | 21.2k | mixing_matrix_rows = mapping_matrix_foa_mixing.rows; |
176 | 21.2k | mixing_matrix_cols = mapping_matrix_foa_mixing.cols; |
177 | 21.2k | demixing_matrix_rows = mapping_matrix_foa_demixing.rows; |
178 | 21.2k | demixing_matrix_cols = mapping_matrix_foa_demixing.cols; |
179 | 21.2k | } |
180 | 9.98k | else if (order_plus_one == 3) |
181 | 4.17k | { |
182 | 4.17k | mixing_matrix_rows = mapping_matrix_soa_mixing.rows; |
183 | 4.17k | mixing_matrix_cols = mapping_matrix_soa_mixing.cols; |
184 | 4.17k | demixing_matrix_rows = mapping_matrix_soa_demixing.rows; |
185 | 4.17k | demixing_matrix_cols = mapping_matrix_soa_demixing.cols; |
186 | 4.17k | } |
187 | 5.81k | else if (order_plus_one == 4) |
188 | 2.36k | { |
189 | 2.36k | mixing_matrix_rows = mapping_matrix_toa_mixing.rows; |
190 | 2.36k | mixing_matrix_cols = mapping_matrix_toa_mixing.cols; |
191 | 2.36k | demixing_matrix_rows = mapping_matrix_toa_demixing.rows; |
192 | 2.36k | demixing_matrix_cols = mapping_matrix_toa_demixing.cols; |
193 | 2.36k | } |
194 | 3.44k | else if (order_plus_one == 5) |
195 | 1.02k | { |
196 | 1.02k | mixing_matrix_rows = mapping_matrix_fourthoa_mixing.rows; |
197 | 1.02k | mixing_matrix_cols = mapping_matrix_fourthoa_mixing.cols; |
198 | 1.02k | demixing_matrix_rows = mapping_matrix_fourthoa_demixing.rows; |
199 | 1.02k | demixing_matrix_cols = mapping_matrix_fourthoa_demixing.cols; |
200 | 1.02k | } |
201 | 2.42k | else if (order_plus_one == 6) |
202 | 2.38k | { |
203 | 2.38k | mixing_matrix_rows = mapping_matrix_fifthoa_mixing.rows; |
204 | 2.38k | mixing_matrix_cols = mapping_matrix_fifthoa_mixing.cols; |
205 | 2.38k | demixing_matrix_rows = mapping_matrix_fifthoa_demixing.rows; |
206 | 2.38k | demixing_matrix_cols = mapping_matrix_fifthoa_demixing.cols; |
207 | 2.38k | } |
208 | 36 | else |
209 | 36 | return 0; |
210 | | |
211 | 31.2k | mixing_matrix_size = |
212 | 31.2k | mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); |
213 | 31.2k | if (!mixing_matrix_size) |
214 | 0 | return 0; |
215 | | |
216 | 31.2k | demixing_matrix_size = |
217 | 31.2k | mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); |
218 | 31.2k | if (!demixing_matrix_size) |
219 | 0 | return 0; |
220 | | |
221 | 31.2k | encoder_size = |
222 | 31.2k | opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); |
223 | 31.2k | if (!encoder_size) |
224 | 0 | return 0; |
225 | | |
226 | 31.2k | return align(sizeof(OpusProjectionEncoder)) + |
227 | 31.2k | mixing_matrix_size + demixing_matrix_size + encoder_size; |
228 | 31.2k | } |
229 | | |
230 | | int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, |
231 | | int channels, int mapping_family, |
232 | | int *streams, int *coupled_streams, |
233 | | int application) |
234 | 31.2k | { |
235 | 31.2k | MappingMatrix *mixing_matrix; |
236 | 31.2k | MappingMatrix *demixing_matrix; |
237 | 31.2k | OpusMSEncoder *ms_encoder; |
238 | 31.2k | int i; |
239 | 31.2k | int ret; |
240 | 31.2k | int order_plus_one; |
241 | 31.2k | unsigned char mapping[255]; |
242 | | |
243 | 31.2k | if (streams == NULL || coupled_streams == NULL) { |
244 | 0 | return OPUS_BAD_ARG; |
245 | 0 | } |
246 | | |
247 | 31.2k | if (get_streams_from_channels(channels, mapping_family, streams, |
248 | 31.2k | coupled_streams, &order_plus_one) != OPUS_OK) |
249 | 0 | return OPUS_BAD_ARG; |
250 | | |
251 | 31.2k | if (mapping_family == 3) |
252 | 31.2k | { |
253 | | /* Assign mixing matrix based on available pre-computed matrices. */ |
254 | 31.2k | mixing_matrix = get_mixing_matrix(st); |
255 | 31.2k | if (order_plus_one == 2) |
256 | 21.2k | { |
257 | 21.2k | mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, |
258 | 21.2k | mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, |
259 | 21.2k | mapping_matrix_foa_mixing_data, |
260 | 21.2k | sizeof(mapping_matrix_foa_mixing_data)); |
261 | 21.2k | } |
262 | 9.94k | else if (order_plus_one == 3) |
263 | 4.17k | { |
264 | 4.17k | mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, |
265 | 4.17k | mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, |
266 | 4.17k | mapping_matrix_soa_mixing_data, |
267 | 4.17k | sizeof(mapping_matrix_soa_mixing_data)); |
268 | 4.17k | } |
269 | 5.77k | else if (order_plus_one == 4) |
270 | 2.36k | { |
271 | 2.36k | mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, |
272 | 2.36k | mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, |
273 | 2.36k | mapping_matrix_toa_mixing_data, |
274 | 2.36k | sizeof(mapping_matrix_toa_mixing_data)); |
275 | 2.36k | } |
276 | 3.41k | else if (order_plus_one == 5) |
277 | 1.02k | { |
278 | 1.02k | mapping_matrix_init(mixing_matrix, mapping_matrix_fourthoa_mixing.rows, |
279 | 1.02k | mapping_matrix_fourthoa_mixing.cols, mapping_matrix_fourthoa_mixing.gain, |
280 | 1.02k | mapping_matrix_fourthoa_mixing_data, |
281 | 1.02k | sizeof(mapping_matrix_fourthoa_mixing_data)); |
282 | 1.02k | } |
283 | 2.38k | else if (order_plus_one == 6) |
284 | 2.38k | { |
285 | 2.38k | mapping_matrix_init(mixing_matrix, mapping_matrix_fifthoa_mixing.rows, |
286 | 2.38k | mapping_matrix_fifthoa_mixing.cols, mapping_matrix_fifthoa_mixing.gain, |
287 | 2.38k | mapping_matrix_fifthoa_mixing_data, |
288 | 2.38k | sizeof(mapping_matrix_fifthoa_mixing_data)); |
289 | 2.38k | } |
290 | 0 | else |
291 | 0 | return OPUS_BAD_ARG; |
292 | | |
293 | 31.2k | st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( |
294 | 31.2k | mixing_matrix->rows, mixing_matrix->cols); |
295 | 31.2k | if (!st->mixing_matrix_size_in_bytes) |
296 | 0 | return OPUS_BAD_ARG; |
297 | | |
298 | | /* Assign demixing matrix based on available pre-computed matrices. */ |
299 | 31.2k | demixing_matrix = get_enc_demixing_matrix(st); |
300 | 31.2k | if (order_plus_one == 2) |
301 | 21.2k | { |
302 | 21.2k | mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, |
303 | 21.2k | mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, |
304 | 21.2k | mapping_matrix_foa_demixing_data, |
305 | 21.2k | sizeof(mapping_matrix_foa_demixing_data)); |
306 | 21.2k | } |
307 | 9.94k | else if (order_plus_one == 3) |
308 | 4.17k | { |
309 | 4.17k | mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, |
310 | 4.17k | mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, |
311 | 4.17k | mapping_matrix_soa_demixing_data, |
312 | 4.17k | sizeof(mapping_matrix_soa_demixing_data)); |
313 | 4.17k | } |
314 | 5.77k | else if (order_plus_one == 4) |
315 | 2.36k | { |
316 | 2.36k | mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, |
317 | 2.36k | mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, |
318 | 2.36k | mapping_matrix_toa_demixing_data, |
319 | 2.36k | sizeof(mapping_matrix_toa_demixing_data)); |
320 | 2.36k | } |
321 | 3.41k | else if (order_plus_one == 5) |
322 | 1.02k | { |
323 | 1.02k | mapping_matrix_init(demixing_matrix, mapping_matrix_fourthoa_demixing.rows, |
324 | 1.02k | mapping_matrix_fourthoa_demixing.cols, mapping_matrix_fourthoa_demixing.gain, |
325 | 1.02k | mapping_matrix_fourthoa_demixing_data, |
326 | 1.02k | sizeof(mapping_matrix_fourthoa_demixing_data)); |
327 | 1.02k | } |
328 | 2.38k | else if (order_plus_one == 6) |
329 | 2.38k | { |
330 | 2.38k | mapping_matrix_init(demixing_matrix, mapping_matrix_fifthoa_demixing.rows, |
331 | 2.38k | mapping_matrix_fifthoa_demixing.cols, mapping_matrix_fifthoa_demixing.gain, |
332 | 2.38k | mapping_matrix_fifthoa_demixing_data, |
333 | 2.38k | sizeof(mapping_matrix_fifthoa_demixing_data)); |
334 | 2.38k | } |
335 | 0 | else |
336 | 0 | return OPUS_BAD_ARG; |
337 | | |
338 | 31.2k | st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( |
339 | 31.2k | demixing_matrix->rows, demixing_matrix->cols); |
340 | 31.2k | if (!st->demixing_matrix_size_in_bytes) |
341 | 0 | return OPUS_BAD_ARG; |
342 | 31.2k | } |
343 | 0 | else |
344 | 0 | return OPUS_UNIMPLEMENTED; |
345 | | |
346 | | /* Ensure matrices are large enough for desired coding scheme. */ |
347 | 31.2k | if (*streams + *coupled_streams > mixing_matrix->rows || |
348 | 31.2k | channels > mixing_matrix->cols || |
349 | 31.2k | channels > demixing_matrix->rows || |
350 | 31.2k | *streams + *coupled_streams > demixing_matrix->cols) |
351 | 0 | return OPUS_BAD_ARG; |
352 | | |
353 | | /* Set trivial mapping so each input channel pairs with a matrix column. */ |
354 | 314k | for (i = 0; i < channels; i++) |
355 | 283k | mapping[i] = i; |
356 | | |
357 | | /* Initialize multistream encoder with provided settings. */ |
358 | 31.2k | ms_encoder = get_multistream_encoder(st); |
359 | 31.2k | ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, |
360 | 31.2k | *coupled_streams, mapping, application); |
361 | 31.2k | return ret; |
362 | 31.2k | } |
363 | | |
364 | | OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( |
365 | | opus_int32 Fs, int channels, int mapping_family, int *streams, |
366 | | int *coupled_streams, int application, int *error) |
367 | 31.3k | { |
368 | 31.3k | int size; |
369 | 31.3k | int ret; |
370 | 31.3k | OpusProjectionEncoder *st; |
371 | | |
372 | | /* Allocate space for the projection encoder. */ |
373 | 31.3k | size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); |
374 | 31.3k | if (!size) { |
375 | 181 | if (error) |
376 | 181 | *error = OPUS_ALLOC_FAIL; |
377 | 181 | return NULL; |
378 | 181 | } |
379 | 31.2k | st = (OpusProjectionEncoder *)opus_alloc(size); |
380 | 31.2k | if (!st) |
381 | 0 | { |
382 | 0 | if (error) |
383 | 0 | *error = OPUS_ALLOC_FAIL; |
384 | 0 | return NULL; |
385 | 0 | } |
386 | | |
387 | | /* Initialize projection encoder with provided settings. */ |
388 | 31.2k | ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, |
389 | 31.2k | mapping_family, streams, coupled_streams, application); |
390 | 31.2k | if (ret != OPUS_OK) |
391 | 0 | { |
392 | 0 | opus_free(st); |
393 | 0 | st = NULL; |
394 | 0 | } |
395 | 31.2k | if (error) |
396 | 31.2k | *error = ret; |
397 | 31.2k | return st; |
398 | 31.2k | } |
399 | | |
400 | | int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, |
401 | | int frame_size, unsigned char *data, |
402 | | opus_int32 max_data_bytes) |
403 | 30.4k | { |
404 | 30.4k | return opus_multistream_encode_native(get_multistream_encoder(st), |
405 | 30.4k | opus_projection_copy_channel_in_short, pcm, frame_size, data, |
406 | 30.4k | max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); |
407 | 30.4k | } |
408 | | |
409 | | int opus_projection_encode24(OpusProjectionEncoder *st, const opus_int32 *pcm, |
410 | | int frame_size, unsigned char *data, |
411 | | opus_int32 max_data_bytes) |
412 | 0 | { |
413 | 0 | return opus_multistream_encode_native(get_multistream_encoder(st), |
414 | 0 | opus_projection_copy_channel_in_int24, pcm, frame_size, data, |
415 | 0 | max_data_bytes, MAX_ENCODING_DEPTH, downmix_int, 0, get_mixing_matrix(st)); |
416 | 0 | } |
417 | | |
418 | | #ifndef DISABLE_FLOAT_API |
419 | | int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, |
420 | | int frame_size, unsigned char *data, |
421 | | opus_int32 max_data_bytes) |
422 | 0 | { |
423 | 0 | return opus_multistream_encode_native(get_multistream_encoder(st), |
424 | 0 | opus_projection_copy_channel_in_float, pcm, frame_size, data, |
425 | 0 | max_data_bytes, MAX_ENCODING_DEPTH, downmix_float, 1, get_mixing_matrix(st)); |
426 | 0 | } |
427 | | #endif |
428 | | |
429 | | void opus_projection_encoder_destroy(OpusProjectionEncoder *st) |
430 | 31.3k | { |
431 | 31.3k | opus_free(st); |
432 | 31.3k | } |
433 | | |
434 | | int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) |
435 | 374k | { |
436 | 374k | va_list ap; |
437 | 374k | MappingMatrix *demixing_matrix; |
438 | 374k | OpusMSEncoder *ms_encoder; |
439 | 374k | int ret = OPUS_OK; |
440 | | |
441 | 374k | ms_encoder = get_multistream_encoder(st); |
442 | 374k | demixing_matrix = get_enc_demixing_matrix(st); |
443 | | |
444 | 374k | va_start(ap, request); |
445 | 374k | switch(request) |
446 | 374k | { |
447 | 0 | case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: |
448 | 0 | { |
449 | 0 | opus_int32 *value = va_arg(ap, opus_int32*); |
450 | 0 | if (!value) |
451 | 0 | { |
452 | 0 | goto bad_arg; |
453 | 0 | } |
454 | 0 | *value = |
455 | 0 | ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams |
456 | 0 | + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); |
457 | 0 | } |
458 | 0 | break; |
459 | 0 | case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: |
460 | 0 | { |
461 | 0 | opus_int32 *value = va_arg(ap, opus_int32*); |
462 | 0 | if (!value) |
463 | 0 | { |
464 | 0 | goto bad_arg; |
465 | 0 | } |
466 | 0 | *value = demixing_matrix->gain; |
467 | 0 | } |
468 | 0 | break; |
469 | 0 | case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: |
470 | 0 | { |
471 | 0 | int i, j, k, l; |
472 | 0 | int nb_input_streams; |
473 | 0 | int nb_output_streams; |
474 | 0 | unsigned char *external_char; |
475 | 0 | opus_int16 *internal_short; |
476 | 0 | opus_int32 external_size; |
477 | 0 | opus_int32 internal_size; |
478 | | |
479 | | /* (I/O is in relation to the decoder's perspective). */ |
480 | 0 | nb_input_streams = ms_encoder->layout.nb_streams + |
481 | 0 | ms_encoder->layout.nb_coupled_streams; |
482 | 0 | nb_output_streams = ms_encoder->layout.nb_channels; |
483 | |
|
484 | 0 | external_char = va_arg(ap, unsigned char *); |
485 | 0 | external_size = va_arg(ap, opus_int32); |
486 | 0 | if (!external_char) |
487 | 0 | { |
488 | 0 | goto bad_arg; |
489 | 0 | } |
490 | 0 | internal_short = mapping_matrix_get_data(demixing_matrix); |
491 | 0 | internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); |
492 | 0 | if (external_size != internal_size) |
493 | 0 | { |
494 | 0 | goto bad_arg; |
495 | 0 | } |
496 | | |
497 | | /* Copy demixing matrix subset to output destination. */ |
498 | 0 | l = 0; |
499 | 0 | for (i = 0; i < nb_input_streams; i++) { |
500 | 0 | for (j = 0; j < nb_output_streams; j++) { |
501 | 0 | k = demixing_matrix->rows * i + j; |
502 | 0 | external_char[2*l] = (unsigned char)internal_short[k]; |
503 | 0 | external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); |
504 | 0 | l++; |
505 | 0 | } |
506 | 0 | } |
507 | 0 | } |
508 | 0 | break; |
509 | 374k | default: |
510 | 374k | { |
511 | 374k | ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); |
512 | 374k | } |
513 | 374k | break; |
514 | 374k | } |
515 | 374k | va_end(ap); |
516 | 374k | return ret; |
517 | | |
518 | 0 | bad_arg: |
519 | 0 | va_end(ap); |
520 | 0 | return OPUS_BAD_ARG; |
521 | 374k | } |