1use crate::externs::{free, malloc};
2use crate::src::opus_encoder::{downmix_float, downmix_int};
3use crate::src::opus_multistream_encoder::{
4 opus_multistream_encode_native, opus_multistream_encoder_ctl_va_list,
5};
6use crate::src::opus_private::align;
7use crate::{opus_multistream_encoder_get_size, opus_multistream_encoder_init, OpusMSEncoder};
8
9pub mod arch_h {
10 pub type opus_val16 = f32;
11 pub type opus_val32 = f32;
12}
13pub mod stddef_h {
14 pub type size_t = u64;
15 pub const NULL: i32 = 0;
16}
17pub mod opus_projection_h {
18 pub const OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: i32 = 6001;
19 pub const OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: i32 = 6003;
20 pub const OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: i32 = 6005;
21}
22pub use self::arch_h::{opus_val16, opus_val32};
23pub use self::opus_projection_h::{
24 OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST,
25 OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST,
26};
27pub use self::stddef_h::{size_t, NULL};
28use crate::celt::mathops::isqrt32;
29use crate::src::mapping_matrix::{
30 mapping_matrix_foa_demixing, mapping_matrix_foa_demixing_data, mapping_matrix_foa_mixing,
31 mapping_matrix_foa_mixing_data, mapping_matrix_get_data, mapping_matrix_get_size,
32 mapping_matrix_init, mapping_matrix_multiply_channel_in_float,
33 mapping_matrix_multiply_channel_in_short, mapping_matrix_soa_demixing,
34 mapping_matrix_soa_demixing_data, mapping_matrix_soa_mixing, mapping_matrix_soa_mixing_data,
35 mapping_matrix_toa_demixing, mapping_matrix_toa_demixing_data, mapping_matrix_toa_mixing,
36 mapping_matrix_toa_mixing_data, MappingMatrix,
37};
38use crate::src::opus_defines::{OPUS_ALLOC_FAIL, OPUS_BAD_ARG, OPUS_OK, OPUS_UNIMPLEMENTED};
39use crate::varargs::VarArgs;
40
41#[derive(Copy, Clone)]
42#[repr(C)]
43pub struct OpusProjectionEncoder {
44 pub mixing_matrix_size_in_bytes: i32,
45 pub demixing_matrix_size_in_bytes: i32,
46}
47unsafe fn opus_projection_copy_channel_in_float(
48 dst: *mut opus_val16,
49 dst_stride: i32,
50 src: *const core::ffi::c_void,
51 src_stride: i32,
52 src_channel: i32,
53 frame_size: i32,
54 user_data: *mut core::ffi::c_void,
55) {
56 mapping_matrix_multiply_channel_in_float(
57 user_data as *const MappingMatrix,
58 src as *const f32,
59 src_stride,
60 dst,
61 src_channel,
62 dst_stride,
63 frame_size,
64 );
65}
66unsafe fn opus_projection_copy_channel_in_short(
67 dst: *mut opus_val16,
68 dst_stride: i32,
69 src: *const core::ffi::c_void,
70 src_stride: i32,
71 src_channel: i32,
72 frame_size: i32,
73 user_data: *mut core::ffi::c_void,
74) {
75 mapping_matrix_multiply_channel_in_short(
76 user_data as *const MappingMatrix,
77 src as *const i16,
78 src_stride,
79 dst,
80 src_channel,
81 dst_stride,
82 frame_size,
83 );
84}
85unsafe fn get_order_plus_one_from_channels(channels: i32, order_plus_one: *mut i32) -> i32 {
86 let mut order_plus_one_: i32 = 0;
87 let mut acn_channels: i32 = 0;
88 let mut nondiegetic_channels: i32 = 0;
89 if channels < 1 || channels > 227 {
90 return OPUS_BAD_ARG;
91 }
92 order_plus_one_ = isqrt32(channels as u32) as i32;
93 acn_channels = order_plus_one_ * order_plus_one_;
94 nondiegetic_channels = channels - acn_channels;
95 if nondiegetic_channels != 0 && nondiegetic_channels != 2 {
96 return OPUS_BAD_ARG;
97 }
98 if !order_plus_one.is_null() {
99 *order_plus_one = order_plus_one_;
100 }
101 return OPUS_OK;
102}
103unsafe fn get_streams_from_channels(
104 channels: i32,
105 mapping_family: i32,
106 streams: *mut i32,
107 coupled_streams: *mut i32,
108 order_plus_one: *mut i32,
109) -> i32 {
110 if mapping_family == 3 {
111 if get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK {
112 return OPUS_BAD_ARG;
113 }
114 if !streams.is_null() {
115 *streams = (channels + 1) / 2;
116 }
117 if !coupled_streams.is_null() {
118 *coupled_streams = channels / 2;
119 }
120 return OPUS_OK;
121 }
122 return OPUS_BAD_ARG;
123}
124unsafe fn get_mixing_matrix(st: *mut OpusProjectionEncoder) -> *mut MappingMatrix {
125 return (st as *mut i8)
126 .offset(align(::core::mem::size_of::<OpusProjectionEncoder>() as u64 as i32) as isize)
127 as *mut core::ffi::c_void as *mut MappingMatrix;
128}
129unsafe fn get_enc_demixing_matrix(st: *mut OpusProjectionEncoder) -> *mut MappingMatrix {
130 return (st as *mut i8).offset(align(
131 (::core::mem::size_of::<OpusProjectionEncoder>() as u64)
132 .wrapping_add((*st).mixing_matrix_size_in_bytes as u64) as i32,
133 ) as isize) as *mut core::ffi::c_void as *mut MappingMatrix;
134}
135unsafe fn get_multistream_encoder(st: *mut OpusProjectionEncoder) -> *mut OpusMSEncoder {
136 return (st as *mut i8).offset(align(
137 (::core::mem::size_of::<OpusProjectionEncoder>() as u64)
138 .wrapping_add((*st).mixing_matrix_size_in_bytes as u64)
139 .wrapping_add((*st).demixing_matrix_size_in_bytes as u64) as i32,
140 ) as isize) as *mut core::ffi::c_void as *mut OpusMSEncoder;
141}
142pub unsafe fn opus_projection_ambisonics_encoder_get_size(
143 channels: i32,
144 mapping_family: i32,
145) -> i32 {
146 let mut nb_streams: i32 = 0;
147 let mut nb_coupled_streams: i32 = 0;
148 let mut order_plus_one: i32 = 0;
149 let mut mixing_matrix_rows: i32 = 0;
150 let mut mixing_matrix_cols: i32 = 0;
151 let mut demixing_matrix_rows: i32 = 0;
152 let mut demixing_matrix_cols: i32 = 0;
153 let mut mixing_matrix_size: i32 = 0;
154 let mut demixing_matrix_size: i32 = 0;
155 let mut encoder_size: i32 = 0;
156 let mut ret: i32 = 0;
157 ret = get_streams_from_channels(
158 channels,
159 mapping_family,
160 &mut nb_streams,
161 &mut nb_coupled_streams,
162 &mut order_plus_one,
163 );
164 if ret != OPUS_OK {
165 return 0;
166 }
167 if order_plus_one == 2 {
168 mixing_matrix_rows = mapping_matrix_foa_mixing.rows;
169 mixing_matrix_cols = mapping_matrix_foa_mixing.cols;
170 demixing_matrix_rows = mapping_matrix_foa_demixing.rows;
171 demixing_matrix_cols = mapping_matrix_foa_demixing.cols;
172 } else if order_plus_one == 3 {
173 mixing_matrix_rows = mapping_matrix_soa_mixing.rows;
174 mixing_matrix_cols = mapping_matrix_soa_mixing.cols;
175 demixing_matrix_rows = mapping_matrix_soa_demixing.rows;
176 demixing_matrix_cols = mapping_matrix_soa_demixing.cols;
177 } else if order_plus_one == 4 {
178 mixing_matrix_rows = mapping_matrix_toa_mixing.rows;
179 mixing_matrix_cols = mapping_matrix_toa_mixing.cols;
180 demixing_matrix_rows = mapping_matrix_toa_demixing.rows;
181 demixing_matrix_cols = mapping_matrix_toa_demixing.cols;
182 } else {
183 return 0;
184 }
185 mixing_matrix_size = mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols);
186 if mixing_matrix_size == 0 {
187 return 0;
188 }
189 demixing_matrix_size = mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols);
190 if demixing_matrix_size == 0 {
191 return 0;
192 }
193 encoder_size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
194 if encoder_size == 0 {
195 return 0;
196 }
197 return align(::core::mem::size_of::<OpusProjectionEncoder>() as u64 as i32)
198 + mixing_matrix_size
199 + demixing_matrix_size
200 + encoder_size;
201}
202pub unsafe fn opus_projection_ambisonics_encoder_init(
203 st: *mut OpusProjectionEncoder,
204 Fs: i32,
205 channels: i32,
206 mapping_family: i32,
207 streams: *mut i32,
208 coupled_streams: *mut i32,
209 application: i32,
210) -> i32 {
211 let mut mixing_matrix: *mut MappingMatrix = 0 as *mut MappingMatrix;
212 let mut demixing_matrix: *mut MappingMatrix = 0 as *mut MappingMatrix;
213 let mut ms_encoder: *mut OpusMSEncoder = 0 as *mut OpusMSEncoder;
214 let mut i: i32 = 0;
215 let mut ret: i32 = 0;
216 let mut order_plus_one: i32 = 0;
217 let mut mapping: [u8; 255] = [0; 255];
218 if streams.is_null() || coupled_streams.is_null() {
219 return OPUS_BAD_ARG;
220 }
221 if get_streams_from_channels(
222 channels,
223 mapping_family,
224 streams,
225 coupled_streams,
226 &mut order_plus_one,
227 ) != OPUS_OK
228 {
229 return OPUS_BAD_ARG;
230 }
231 if mapping_family == 3 {
232 mixing_matrix = get_mixing_matrix(st);
233 if order_plus_one == 2 {
234 mapping_matrix_init(
235 mixing_matrix,
236 mapping_matrix_foa_mixing.rows,
237 mapping_matrix_foa_mixing.cols,
238 mapping_matrix_foa_mixing.gain,
239 mapping_matrix_foa_mixing_data.as_ptr(),
240 ::core::mem::size_of::<[i16; 36]>() as u64 as i32,
241 );
242 } else if order_plus_one == 3 {
243 mapping_matrix_init(
244 mixing_matrix,
245 mapping_matrix_soa_mixing.rows,
246 mapping_matrix_soa_mixing.cols,
247 mapping_matrix_soa_mixing.gain,
248 mapping_matrix_soa_mixing_data.as_ptr(),
249 ::core::mem::size_of::<[i16; 121]>() as u64 as i32,
250 );
251 } else if order_plus_one == 4 {
252 mapping_matrix_init(
253 mixing_matrix,
254 mapping_matrix_toa_mixing.rows,
255 mapping_matrix_toa_mixing.cols,
256 mapping_matrix_toa_mixing.gain,
257 mapping_matrix_toa_mixing_data.as_ptr(),
258 ::core::mem::size_of::<[i16; 324]>() as u64 as i32,
259 );
260 } else {
261 return OPUS_BAD_ARG;
262 }
263 (*st).mixing_matrix_size_in_bytes =
264 mapping_matrix_get_size((*mixing_matrix).rows, (*mixing_matrix).cols);
265 if (*st).mixing_matrix_size_in_bytes == 0 {
266 return OPUS_BAD_ARG;
267 }
268 demixing_matrix = get_enc_demixing_matrix(st);
269 if order_plus_one == 2 {
270 mapping_matrix_init(
271 demixing_matrix,
272 mapping_matrix_foa_demixing.rows,
273 mapping_matrix_foa_demixing.cols,
274 mapping_matrix_foa_demixing.gain,
275 mapping_matrix_foa_demixing_data.as_ptr(),
276 ::core::mem::size_of::<[i16; 36]>() as u64 as i32,
277 );
278 } else if order_plus_one == 3 {
279 mapping_matrix_init(
280 demixing_matrix,
281 mapping_matrix_soa_demixing.rows,
282 mapping_matrix_soa_demixing.cols,
283 mapping_matrix_soa_demixing.gain,
284 mapping_matrix_soa_demixing_data.as_ptr(),
285 ::core::mem::size_of::<[i16; 121]>() as u64 as i32,
286 );
287 } else if order_plus_one == 4 {
288 mapping_matrix_init(
289 demixing_matrix,
290 mapping_matrix_toa_demixing.rows,
291 mapping_matrix_toa_demixing.cols,
292 mapping_matrix_toa_demixing.gain,
293 mapping_matrix_toa_demixing_data.as_ptr(),
294 ::core::mem::size_of::<[i16; 324]>() as u64 as i32,
295 );
296 } else {
297 return OPUS_BAD_ARG;
298 }
299 (*st).demixing_matrix_size_in_bytes =
300 mapping_matrix_get_size((*demixing_matrix).rows, (*demixing_matrix).cols);
301 if (*st).demixing_matrix_size_in_bytes == 0 {
302 return OPUS_BAD_ARG;
303 }
304 } else {
305 return OPUS_UNIMPLEMENTED;
306 }
307 if *streams + *coupled_streams > (*mixing_matrix).rows
308 || channels > (*mixing_matrix).cols
309 || channels > (*demixing_matrix).rows
310 || *streams + *coupled_streams > (*demixing_matrix).cols
311 {
312 return OPUS_BAD_ARG;
313 }
314 i = 0;
315 while i < channels {
316 mapping[i as usize] = i as u8;
317 i += 1;
318 }
319 ms_encoder = get_multistream_encoder(st);
320 ret = opus_multistream_encoder_init(
321 ms_encoder,
322 Fs,
323 channels,
324 *streams,
325 *coupled_streams,
326 mapping.as_mut_ptr(),
327 application,
328 );
329 return ret;
330}
331pub unsafe fn opus_projection_ambisonics_encoder_create(
332 Fs: i32,
333 channels: i32,
334 mapping_family: i32,
335 streams: *mut i32,
336 coupled_streams: *mut i32,
337 application: i32,
338 error: *mut i32,
339) -> *mut OpusProjectionEncoder {
340 let mut size: i32 = 0;
341 let mut ret: i32 = 0;
342 let mut st: *mut OpusProjectionEncoder = 0 as *mut OpusProjectionEncoder;
343 size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family);
344 if size == 0 {
345 if !error.is_null() {
346 *error = OPUS_ALLOC_FAIL;
347 }
348 return NULL as *mut OpusProjectionEncoder;
349 }
350 st = malloc(size as size_t) as *mut OpusProjectionEncoder;
351 if st.is_null() {
352 if !error.is_null() {
353 *error = OPUS_ALLOC_FAIL;
354 }
355 return NULL as *mut OpusProjectionEncoder;
356 }
357 ret = opus_projection_ambisonics_encoder_init(
358 st,
359 Fs,
360 channels,
361 mapping_family,
362 streams,
363 coupled_streams,
364 application,
365 );
366 if ret != OPUS_OK {
367 free(st as *mut core::ffi::c_void);
368 st = NULL as *mut OpusProjectionEncoder;
369 }
370 if !error.is_null() {
371 *error = ret;
372 }
373 return st;
374}
375pub unsafe fn opus_projection_encode(
376 st: *mut OpusProjectionEncoder,
377 pcm: *const i16,
378 frame_size: i32,
379 data: *mut u8,
380 max_data_bytes: i32,
381) -> i32 {
382 return opus_multistream_encode_native(
383 get_multistream_encoder(st),
384 Some(
385 opus_projection_copy_channel_in_short
386 as unsafe fn(
387 *mut opus_val16,
388 i32,
389 *const core::ffi::c_void,
390 i32,
391 i32,
392 i32,
393 *mut core::ffi::c_void,
394 ) -> (),
395 ),
396 pcm as *const core::ffi::c_void,
397 frame_size,
398 data,
399 max_data_bytes,
400 16,
401 Some(
402 downmix_int
403 as unsafe fn(
404 *const core::ffi::c_void,
405 *mut opus_val32,
406 i32,
407 i32,
408 i32,
409 i32,
410 i32,
411 ) -> (),
412 ),
413 0,
414 get_mixing_matrix(st) as *mut core::ffi::c_void,
415 );
416}
417pub unsafe fn opus_projection_encode_float(
418 st: *mut OpusProjectionEncoder,
419 pcm: *const f32,
420 frame_size: i32,
421 data: *mut u8,
422 max_data_bytes: i32,
423) -> i32 {
424 return opus_multistream_encode_native(
425 get_multistream_encoder(st),
426 Some(
427 opus_projection_copy_channel_in_float
428 as unsafe fn(
429 *mut opus_val16,
430 i32,
431 *const core::ffi::c_void,
432 i32,
433 i32,
434 i32,
435 *mut core::ffi::c_void,
436 ) -> (),
437 ),
438 pcm as *const core::ffi::c_void,
439 frame_size,
440 data,
441 max_data_bytes,
442 24,
443 Some(
444 downmix_float
445 as unsafe fn(
446 *const core::ffi::c_void,
447 *mut opus_val32,
448 i32,
449 i32,
450 i32,
451 i32,
452 i32,
453 ) -> (),
454 ),
455 1,
456 get_mixing_matrix(st) as *mut core::ffi::c_void,
457 );
458}
459pub unsafe fn opus_projection_encoder_destroy(st: *mut OpusProjectionEncoder) {
460 free(st as *mut core::ffi::c_void);
461}
462pub unsafe fn opus_projection_encoder_ctl_impl(
463 st: *mut OpusProjectionEncoder,
464 request: i32,
465 args: VarArgs,
466) -> i32 {
467 let current_block: u64;
468 let mut demixing_matrix: *mut MappingMatrix = 0 as *mut MappingMatrix;
469 let mut ms_encoder: *mut OpusMSEncoder = 0 as *mut OpusMSEncoder;
470 let mut ret: i32 = OPUS_OK;
471 ms_encoder = get_multistream_encoder(st);
472 demixing_matrix = get_enc_demixing_matrix(st);
473 let mut ap = args;
474 match request {
475 OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST => {
476 let value = ap.arg::<&mut i32>();
477 *value = (((*ms_encoder).layout.nb_channels
478 * ((*ms_encoder).layout.nb_streams + (*ms_encoder).layout.nb_coupled_streams))
479 as u64)
480 .wrapping_mul(::core::mem::size_of::<i16>() as u64) as i32;
481 current_block = 18153031941552419006;
482 }
483 OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST => {
484 let value_0 = ap.arg::<&mut i32>();
485 *value_0 = (*demixing_matrix).gain;
486 current_block = 18153031941552419006;
487 }
488 OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST => {
489 let mut i: i32 = 0;
490 let mut j: i32 = 0;
491 let mut k: i32 = 0;
492 let mut l: i32 = 0;
493 let mut nb_input_streams: i32 = 0;
494 let mut nb_output_streams: i32 = 0;
495 let mut external_char: *mut u8 = 0 as *mut u8;
496 let mut internal_short: *mut i16 = 0 as *mut i16;
497 let mut external_size: i32 = 0;
498 let mut internal_size: i32 = 0;
499 nb_input_streams =
500 (*ms_encoder).layout.nb_streams + (*ms_encoder).layout.nb_coupled_streams;
501 nb_output_streams = (*ms_encoder).layout.nb_channels;
502 external_char = ap.arg::<*mut u8>();
503 external_size = ap.arg::<i32>();
504 if external_char.is_null() {
505 current_block = 17184638872671510253;
506 } else {
507 internal_short = mapping_matrix_get_data(demixing_matrix);
508 internal_size = ((nb_input_streams * nb_output_streams) as u64)
509 .wrapping_mul(::core::mem::size_of::<i16>() as u64)
510 as i32;
511 if external_size != internal_size {
512 current_block = 17184638872671510253;
513 } else {
514 l = 0;
515 i = 0;
516 while i < nb_input_streams {
517 j = 0;
518 while j < nb_output_streams {
519 k = (*demixing_matrix).rows * i + j;
520 *external_char.offset((2 * l) as isize) =
521 *internal_short.offset(k as isize) as u8;
522 *external_char.offset((2 * l + 1) as isize) =
523 (*internal_short.offset(k as isize) as i32 >> 8) as u8;
524 l += 1;
525 j += 1;
526 }
527 i += 1;
528 }
529 current_block = 18153031941552419006;
530 }
531 }
532 }
533 _ => {
534 ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap);
535 current_block = 18153031941552419006;
536 }
537 }
538 match current_block {
539 17184638872671510253 => return OPUS_BAD_ARG,
540 _ => return ret,
541 };
542}
543#[macro_export]
544macro_rules! opus_projection_encoder_ctl {
545 ($st:expr, $request:expr, $($arg:expr),*) => {
546 $crate::opus_projection_encoder_ctl_impl($st, $request, $crate::varargs!($($arg),*))
547 };
548 ($st:expr, $request:expr) => {
549 opus_projection_encoder_ctl!($st, $request,)
550 };
551 ($st:expr, $request:expr, $($arg:expr),*,) => {
552 opus_projection_encoder_ctl!($st, $request, $($arg),*)
553 };
554}