opus_projection_decoder.c (8481B)
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 "mapping_matrix.h" 39 #include "stack_alloc.h" 40 41 struct OpusProjectionDecoder 42 { 43 opus_int32 demixing_matrix_size_in_bytes; 44 /* Encoder states go here */ 45 }; 46 47 #if !defined(DISABLE_FLOAT_API) 48 static void opus_projection_copy_channel_out_float( 49 void *dst, 50 int dst_stride, 51 int dst_channel, 52 const opus_res *src, 53 int src_stride, 54 int frame_size, 55 void *user_data) 56 { 57 float *float_dst; 58 const MappingMatrix *matrix; 59 float_dst = (float *)dst; 60 matrix = (const MappingMatrix *)user_data; 61 62 if (dst_channel == 0) 63 OPUS_CLEAR(float_dst, frame_size * dst_stride); 64 65 if (src != NULL) 66 mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel, 67 src_stride, float_dst, dst_stride, frame_size); 68 } 69 #endif 70 71 static void opus_projection_copy_channel_out_short( 72 void *dst, 73 int dst_stride, 74 int dst_channel, 75 const opus_res *src, 76 int src_stride, 77 int frame_size, 78 void *user_data) 79 { 80 opus_int16 *short_dst; 81 const MappingMatrix *matrix; 82 short_dst = (opus_int16 *)dst; 83 matrix = (const MappingMatrix *)user_data; 84 if (dst_channel == 0) 85 OPUS_CLEAR(short_dst, frame_size * dst_stride); 86 87 if (src != NULL) 88 mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel, 89 src_stride, short_dst, dst_stride, frame_size); 90 } 91 92 static void opus_projection_copy_channel_out_int24( 93 void *dst, 94 int dst_stride, 95 int dst_channel, 96 const opus_res *src, 97 int src_stride, 98 int frame_size, 99 void *user_data) 100 { 101 opus_int32 *short_dst; 102 const MappingMatrix *matrix; 103 short_dst = (opus_int32 *)dst; 104 matrix = (const MappingMatrix *)user_data; 105 if (dst_channel == 0) 106 OPUS_CLEAR(short_dst, frame_size * dst_stride); 107 108 if (src != NULL) 109 mapping_matrix_multiply_channel_out_int24(matrix, src, dst_channel, 110 src_stride, short_dst, dst_stride, frame_size); 111 } 112 113 static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st) 114 { 115 /* void* cast avoids clang -Wcast-align warning */ 116 return (MappingMatrix*)(void*)((char*)st + 117 align(sizeof(OpusProjectionDecoder))); 118 } 119 120 static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st) 121 { 122 /* void* cast avoids clang -Wcast-align warning */ 123 return (OpusMSDecoder*)(void*)((char*)st + 124 align(sizeof(OpusProjectionDecoder) + 125 st->demixing_matrix_size_in_bytes)); 126 } 127 128 opus_int32 opus_projection_decoder_get_size(int channels, int streams, 129 int coupled_streams) 130 { 131 opus_int32 matrix_size; 132 opus_int32 decoder_size; 133 134 matrix_size = 135 mapping_matrix_get_size(streams + coupled_streams, channels); 136 if (!matrix_size) 137 return 0; 138 139 decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams); 140 if (!decoder_size) 141 return 0; 142 143 return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size; 144 } 145 146 int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, 147 int channels, int streams, int coupled_streams, 148 unsigned char *demixing_matrix, opus_int32 demixing_matrix_size) 149 { 150 int nb_input_streams; 151 opus_int32 expected_matrix_size; 152 int i, ret; 153 unsigned char mapping[255]; 154 VARDECL(opus_int16, buf); 155 ALLOC_STACK; 156 157 /* Verify supplied matrix size. */ 158 nb_input_streams = streams + coupled_streams; 159 expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16); 160 if (expected_matrix_size != demixing_matrix_size) 161 { 162 RESTORE_STACK; 163 return OPUS_BAD_ARG; 164 } 165 166 /* Convert demixing matrix input into internal format. */ 167 ALLOC(buf, nb_input_streams * channels, opus_int16); 168 for (i = 0; i < nb_input_streams * channels; i++) 169 { 170 int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i]; 171 s = ((s & 0xFFFF) ^ 0x8000) - 0x8000; 172 buf[i] = (opus_int16)s; 173 } 174 175 /* Assign demixing matrix. */ 176 st->demixing_matrix_size_in_bytes = 177 mapping_matrix_get_size(channels, nb_input_streams); 178 if (!st->demixing_matrix_size_in_bytes) 179 { 180 RESTORE_STACK; 181 return OPUS_BAD_ARG; 182 } 183 184 mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0, 185 buf, demixing_matrix_size); 186 187 /* Set trivial mapping so each input channel pairs with a matrix column. */ 188 for (i = 0; i < channels; i++) 189 mapping[i] = i; 190 191 ret = opus_multistream_decoder_init( 192 get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping); 193 RESTORE_STACK; 194 return ret; 195 } 196 197 OpusProjectionDecoder *opus_projection_decoder_create( 198 opus_int32 Fs, int channels, int streams, int coupled_streams, 199 unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error) 200 { 201 int size; 202 int ret; 203 OpusProjectionDecoder *st; 204 205 /* Allocate space for the projection decoder. */ 206 size = opus_projection_decoder_get_size(channels, streams, coupled_streams); 207 if (!size) { 208 if (error) 209 *error = OPUS_ALLOC_FAIL; 210 return NULL; 211 } 212 st = (OpusProjectionDecoder *)opus_alloc(size); 213 if (!st) 214 { 215 if (error) 216 *error = OPUS_ALLOC_FAIL; 217 return NULL; 218 } 219 220 /* Initialize projection decoder with provided settings. */ 221 ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams, 222 demixing_matrix, demixing_matrix_size); 223 if (ret != OPUS_OK) 224 { 225 opus_free(st); 226 st = NULL; 227 } 228 if (error) 229 *error = ret; 230 return st; 231 } 232 233 #ifdef FIXED_POINT 234 #define OPTIONAL_CLIP 0 235 #else 236 #define OPTIONAL_CLIP 1 237 #endif 238 239 int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, 240 opus_int32 len, opus_int16 *pcm, int frame_size, 241 int decode_fec) 242 { 243 return opus_multistream_decode_native(get_multistream_decoder(st), data, len, 244 pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, OPTIONAL_CLIP, 245 get_dec_demixing_matrix(st)); 246 } 247 248 int opus_projection_decode24(OpusProjectionDecoder *st, const unsigned char *data, 249 opus_int32 len, opus_int32 *pcm, int frame_size, 250 int decode_fec) 251 { 252 return opus_multistream_decode_native(get_multistream_decoder(st), data, len, 253 pcm, opus_projection_copy_channel_out_int24, frame_size, decode_fec, 0, 254 get_dec_demixing_matrix(st)); 255 } 256 257 #ifndef DISABLE_FLOAT_API 258 int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data, 259 opus_int32 len, float *pcm, int frame_size, int decode_fec) 260 { 261 return opus_multistream_decode_native(get_multistream_decoder(st), data, len, 262 pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0, 263 get_dec_demixing_matrix(st)); 264 } 265 #endif 266 267 int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) 268 { 269 va_list ap; 270 int ret = OPUS_OK; 271 272 va_start(ap, request); 273 ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st), 274 request, ap); 275 va_end(ap); 276 return ret; 277 } 278 279 void opus_projection_decoder_destroy(OpusProjectionDecoder *st) 280 { 281 opus_free(st); 282 }