unsafe_libopus/src/
opus_projection_encoder.rs

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}