123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /* Copyright (c) 2017 Google Inc.
- Written by Andrew Allen */
- /*
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "mathops.h"
- #include "os_support.h"
- #include "opus_private.h"
- #include "opus_defines.h"
- #include "opus_projection.h"
- #include "opus_multistream.h"
- #include "mapping_matrix.h"
- #include "stack_alloc.h"
- struct OpusProjectionDecoder
- {
- opus_int32 demixing_matrix_size_in_bytes;
- /* Encoder states go here */
- };
- #if !defined(DISABLE_FLOAT_API)
- static void opus_projection_copy_channel_out_float(
- void *dst,
- int dst_stride,
- int dst_channel,
- const opus_val16 *src,
- int src_stride,
- int frame_size,
- void *user_data)
- {
- float *float_dst;
- const MappingMatrix *matrix;
- float_dst = (float *)dst;
- matrix = (const MappingMatrix *)user_data;
- if (dst_channel == 0)
- OPUS_CLEAR(float_dst, frame_size * dst_stride);
- if (src != NULL)
- mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel,
- src_stride, float_dst, dst_stride, frame_size);
- }
- #endif
- static void opus_projection_copy_channel_out_short(
- void *dst,
- int dst_stride,
- int dst_channel,
- const opus_val16 *src,
- int src_stride,
- int frame_size,
- void *user_data)
- {
- opus_int16 *short_dst;
- const MappingMatrix *matrix;
- short_dst = (opus_int16 *)dst;
- matrix = (const MappingMatrix *)user_data;
- if (dst_channel == 0)
- OPUS_CLEAR(short_dst, frame_size * dst_stride);
- if (src != NULL)
- mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel,
- src_stride, short_dst, dst_stride, frame_size);
- }
- static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st)
- {
- /* void* cast avoids clang -Wcast-align warning */
- return (MappingMatrix*)(void*)((char*)st +
- align(sizeof(OpusProjectionDecoder)));
- }
- static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st)
- {
- /* void* cast avoids clang -Wcast-align warning */
- return (OpusMSDecoder*)(void*)((char*)st +
- align(sizeof(OpusProjectionDecoder) +
- st->demixing_matrix_size_in_bytes));
- }
- opus_int32 opus_projection_decoder_get_size(int channels, int streams,
- int coupled_streams)
- {
- opus_int32 matrix_size;
- opus_int32 decoder_size;
- matrix_size =
- mapping_matrix_get_size(streams + coupled_streams, channels);
- if (!matrix_size)
- return 0;
- decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams);
- if (!decoder_size)
- return 0;
- return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size;
- }
- int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs,
- int channels, int streams, int coupled_streams,
- unsigned char *demixing_matrix, opus_int32 demixing_matrix_size)
- {
- int nb_input_streams;
- opus_int32 expected_matrix_size;
- int i, ret;
- unsigned char mapping[255];
- VARDECL(opus_int16, buf);
- ALLOC_STACK;
- /* Verify supplied matrix size. */
- nb_input_streams = streams + coupled_streams;
- expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16);
- if (expected_matrix_size != demixing_matrix_size)
- {
- RESTORE_STACK;
- return OPUS_BAD_ARG;
- }
- /* Convert demixing matrix input into internal format. */
- ALLOC(buf, nb_input_streams * channels, opus_int16);
- for (i = 0; i < nb_input_streams * channels; i++)
- {
- int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i];
- s = ((s & 0xFFFF) ^ 0x8000) - 0x8000;
- buf[i] = (opus_int16)s;
- }
- /* Assign demixing matrix. */
- st->demixing_matrix_size_in_bytes =
- mapping_matrix_get_size(channels, nb_input_streams);
- if (!st->demixing_matrix_size_in_bytes)
- {
- RESTORE_STACK;
- return OPUS_BAD_ARG;
- }
- mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0,
- buf, demixing_matrix_size);
- /* Set trivial mapping so each input channel pairs with a matrix column. */
- for (i = 0; i < channels; i++)
- mapping[i] = i;
- ret = opus_multistream_decoder_init(
- get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping);
- RESTORE_STACK;
- return ret;
- }
- OpusProjectionDecoder *opus_projection_decoder_create(
- opus_int32 Fs, int channels, int streams, int coupled_streams,
- unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error)
- {
- int size;
- int ret;
- OpusProjectionDecoder *st;
- /* Allocate space for the projection decoder. */
- size = opus_projection_decoder_get_size(channels, streams, coupled_streams);
- if (!size) {
- if (error)
- *error = OPUS_ALLOC_FAIL;
- return NULL;
- }
- st = (OpusProjectionDecoder *)opus_alloc(size);
- if (!st)
- {
- if (error)
- *error = OPUS_ALLOC_FAIL;
- return NULL;
- }
- /* Initialize projection decoder with provided settings. */
- ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams,
- demixing_matrix, demixing_matrix_size);
- if (ret != OPUS_OK)
- {
- opus_free(st);
- st = NULL;
- }
- if (error)
- *error = ret;
- return st;
- }
- #ifdef FIXED_POINT
- int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
- opus_int32 len, opus_int16 *pcm, int frame_size,
- int decode_fec)
- {
- return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
- pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0,
- get_dec_demixing_matrix(st));
- }
- #else
- int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
- opus_int32 len, opus_int16 *pcm, int frame_size,
- int decode_fec)
- {
- return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
- pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1,
- get_dec_demixing_matrix(st));
- }
- #endif
- #ifndef DISABLE_FLOAT_API
- int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data,
- opus_int32 len, float *pcm, int frame_size, int decode_fec)
- {
- return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
- pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0,
- get_dec_demixing_matrix(st));
- }
- #endif
- int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...)
- {
- va_list ap;
- int ret = OPUS_OK;
- va_start(ap, request);
- ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st),
- request, ap);
- va_end(ap);
- return ret;
- }
- void opus_projection_decoder_destroy(OpusProjectionDecoder *st)
- {
- opus_free(st);
- }
|