opus_projection_encoder.c (16886B)
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 { 59 mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, 60 (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); 61 } 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 { 74 mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, 75 (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); 76 } 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 { 88 mapping_matrix_multiply_channel_in_int24((const MappingMatrix*)user_data, 89 (const opus_int32*)src, src_stride, dst, src_channel, dst_stride, frame_size); 90 } 91 92 static int get_order_plus_one_from_channels(int channels, int *order_plus_one) 93 { 94 int order_plus_one_; 95 int acn_channels; 96 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 if (channels < 1 || channels > 227) 102 return OPUS_BAD_ARG; 103 104 order_plus_one_ = isqrt32(channels); 105 acn_channels = order_plus_one_ * order_plus_one_; 106 nondiegetic_channels = channels - acn_channels; 107 if (nondiegetic_channels != 0 && nondiegetic_channels != 2) 108 return OPUS_BAD_ARG; 109 110 if (order_plus_one) 111 *order_plus_one = order_plus_one_; 112 return OPUS_OK; 113 } 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 { 119 if (mapping_family == 3) 120 { 121 if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) 122 return OPUS_BAD_ARG; 123 if (streams) 124 *streams = (channels + 1) / 2; 125 if (coupled_streams) 126 *coupled_streams = channels / 2; 127 return OPUS_OK; 128 } 129 return OPUS_BAD_ARG; 130 } 131 132 static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) 133 { 134 /* void* cast avoids clang -Wcast-align warning */ 135 return (MappingMatrix *)(void*)((char*)st + 136 align(sizeof(OpusProjectionEncoder))); 137 } 138 139 static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st) 140 { 141 /* void* cast avoids clang -Wcast-align warning */ 142 return (MappingMatrix *)(void*)((char*)st + 143 align(sizeof(OpusProjectionEncoder) + 144 st->mixing_matrix_size_in_bytes)); 145 } 146 147 static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) 148 { 149 /* void* cast avoids clang -Wcast-align warning */ 150 return (OpusMSEncoder *)(void*)((char*)st + 151 align(sizeof(OpusProjectionEncoder) + 152 st->mixing_matrix_size_in_bytes + 153 st->demixing_matrix_size_in_bytes)); 154 } 155 156 opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, 157 int mapping_family) 158 { 159 int nb_streams; 160 int nb_coupled_streams; 161 int order_plus_one; 162 int mixing_matrix_rows, mixing_matrix_cols; 163 int demixing_matrix_rows, demixing_matrix_cols; 164 opus_int32 mixing_matrix_size, demixing_matrix_size; 165 opus_int32 encoder_size; 166 int ret; 167 168 ret = get_streams_from_channels(channels, mapping_family, &nb_streams, 169 &nb_coupled_streams, &order_plus_one); 170 if (ret != OPUS_OK) 171 return 0; 172 173 if (order_plus_one == 2) 174 { 175 mixing_matrix_rows = mapping_matrix_foa_mixing.rows; 176 mixing_matrix_cols = mapping_matrix_foa_mixing.cols; 177 demixing_matrix_rows = mapping_matrix_foa_demixing.rows; 178 demixing_matrix_cols = mapping_matrix_foa_demixing.cols; 179 } 180 else if (order_plus_one == 3) 181 { 182 mixing_matrix_rows = mapping_matrix_soa_mixing.rows; 183 mixing_matrix_cols = mapping_matrix_soa_mixing.cols; 184 demixing_matrix_rows = mapping_matrix_soa_demixing.rows; 185 demixing_matrix_cols = mapping_matrix_soa_demixing.cols; 186 } 187 else if (order_plus_one == 4) 188 { 189 mixing_matrix_rows = mapping_matrix_toa_mixing.rows; 190 mixing_matrix_cols = mapping_matrix_toa_mixing.cols; 191 demixing_matrix_rows = mapping_matrix_toa_demixing.rows; 192 demixing_matrix_cols = mapping_matrix_toa_demixing.cols; 193 } 194 else if (order_plus_one == 5) 195 { 196 mixing_matrix_rows = mapping_matrix_fourthoa_mixing.rows; 197 mixing_matrix_cols = mapping_matrix_fourthoa_mixing.cols; 198 demixing_matrix_rows = mapping_matrix_fourthoa_demixing.rows; 199 demixing_matrix_cols = mapping_matrix_fourthoa_demixing.cols; 200 } 201 else if (order_plus_one == 6) 202 { 203 mixing_matrix_rows = mapping_matrix_fifthoa_mixing.rows; 204 mixing_matrix_cols = mapping_matrix_fifthoa_mixing.cols; 205 demixing_matrix_rows = mapping_matrix_fifthoa_demixing.rows; 206 demixing_matrix_cols = mapping_matrix_fifthoa_demixing.cols; 207 } 208 else 209 return 0; 210 211 mixing_matrix_size = 212 mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); 213 if (!mixing_matrix_size) 214 return 0; 215 216 demixing_matrix_size = 217 mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); 218 if (!demixing_matrix_size) 219 return 0; 220 221 encoder_size = 222 opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); 223 if (!encoder_size) 224 return 0; 225 226 return align(sizeof(OpusProjectionEncoder)) + 227 mixing_matrix_size + demixing_matrix_size + encoder_size; 228 } 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 { 235 MappingMatrix *mixing_matrix; 236 MappingMatrix *demixing_matrix; 237 OpusMSEncoder *ms_encoder; 238 int i; 239 int ret; 240 int order_plus_one; 241 unsigned char mapping[255]; 242 243 if (streams == NULL || coupled_streams == NULL) { 244 return OPUS_BAD_ARG; 245 } 246 247 if (get_streams_from_channels(channels, mapping_family, streams, 248 coupled_streams, &order_plus_one) != OPUS_OK) 249 return OPUS_BAD_ARG; 250 251 if (mapping_family == 3) 252 { 253 /* Assign mixing matrix based on available pre-computed matrices. */ 254 mixing_matrix = get_mixing_matrix(st); 255 if (order_plus_one == 2) 256 { 257 mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, 258 mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, 259 mapping_matrix_foa_mixing_data, 260 sizeof(mapping_matrix_foa_mixing_data)); 261 } 262 else if (order_plus_one == 3) 263 { 264 mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, 265 mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, 266 mapping_matrix_soa_mixing_data, 267 sizeof(mapping_matrix_soa_mixing_data)); 268 } 269 else if (order_plus_one == 4) 270 { 271 mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, 272 mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, 273 mapping_matrix_toa_mixing_data, 274 sizeof(mapping_matrix_toa_mixing_data)); 275 } 276 else if (order_plus_one == 5) 277 { 278 mapping_matrix_init(mixing_matrix, mapping_matrix_fourthoa_mixing.rows, 279 mapping_matrix_fourthoa_mixing.cols, mapping_matrix_fourthoa_mixing.gain, 280 mapping_matrix_fourthoa_mixing_data, 281 sizeof(mapping_matrix_fourthoa_mixing_data)); 282 } 283 else if (order_plus_one == 6) 284 { 285 mapping_matrix_init(mixing_matrix, mapping_matrix_fifthoa_mixing.rows, 286 mapping_matrix_fifthoa_mixing.cols, mapping_matrix_fifthoa_mixing.gain, 287 mapping_matrix_fifthoa_mixing_data, 288 sizeof(mapping_matrix_fifthoa_mixing_data)); 289 } 290 else 291 return OPUS_BAD_ARG; 292 293 st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( 294 mixing_matrix->rows, mixing_matrix->cols); 295 if (!st->mixing_matrix_size_in_bytes) 296 return OPUS_BAD_ARG; 297 298 /* Assign demixing matrix based on available pre-computed matrices. */ 299 demixing_matrix = get_enc_demixing_matrix(st); 300 if (order_plus_one == 2) 301 { 302 mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, 303 mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, 304 mapping_matrix_foa_demixing_data, 305 sizeof(mapping_matrix_foa_demixing_data)); 306 } 307 else if (order_plus_one == 3) 308 { 309 mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, 310 mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, 311 mapping_matrix_soa_demixing_data, 312 sizeof(mapping_matrix_soa_demixing_data)); 313 } 314 else if (order_plus_one == 4) 315 { 316 mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, 317 mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, 318 mapping_matrix_toa_demixing_data, 319 sizeof(mapping_matrix_toa_demixing_data)); 320 } 321 else if (order_plus_one == 5) 322 { 323 mapping_matrix_init(demixing_matrix, mapping_matrix_fourthoa_demixing.rows, 324 mapping_matrix_fourthoa_demixing.cols, mapping_matrix_fourthoa_demixing.gain, 325 mapping_matrix_fourthoa_demixing_data, 326 sizeof(mapping_matrix_fourthoa_demixing_data)); 327 } 328 else if (order_plus_one == 6) 329 { 330 mapping_matrix_init(demixing_matrix, mapping_matrix_fifthoa_demixing.rows, 331 mapping_matrix_fifthoa_demixing.cols, mapping_matrix_fifthoa_demixing.gain, 332 mapping_matrix_fifthoa_demixing_data, 333 sizeof(mapping_matrix_fifthoa_demixing_data)); 334 } 335 else 336 return OPUS_BAD_ARG; 337 338 st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( 339 demixing_matrix->rows, demixing_matrix->cols); 340 if (!st->demixing_matrix_size_in_bytes) 341 return OPUS_BAD_ARG; 342 } 343 else 344 return OPUS_UNIMPLEMENTED; 345 346 /* Ensure matrices are large enough for desired coding scheme. */ 347 if (*streams + *coupled_streams > mixing_matrix->rows || 348 channels > mixing_matrix->cols || 349 channels > demixing_matrix->rows || 350 *streams + *coupled_streams > demixing_matrix->cols) 351 return OPUS_BAD_ARG; 352 353 /* Set trivial mapping so each input channel pairs with a matrix column. */ 354 for (i = 0; i < channels; i++) 355 mapping[i] = i; 356 357 /* Initialize multistream encoder with provided settings. */ 358 ms_encoder = get_multistream_encoder(st); 359 ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, 360 *coupled_streams, mapping, application); 361 return ret; 362 } 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 { 368 int size; 369 int ret; 370 OpusProjectionEncoder *st; 371 372 /* Allocate space for the projection encoder. */ 373 size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); 374 if (!size) { 375 if (error) 376 *error = OPUS_ALLOC_FAIL; 377 return NULL; 378 } 379 st = (OpusProjectionEncoder *)opus_alloc(size); 380 if (!st) 381 { 382 if (error) 383 *error = OPUS_ALLOC_FAIL; 384 return NULL; 385 } 386 387 /* Initialize projection encoder with provided settings. */ 388 ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, 389 mapping_family, streams, coupled_streams, application); 390 if (ret != OPUS_OK) 391 { 392 opus_free(st); 393 st = NULL; 394 } 395 if (error) 396 *error = ret; 397 return st; 398 } 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 { 404 return opus_multistream_encode_native(get_multistream_encoder(st), 405 opus_projection_copy_channel_in_short, pcm, frame_size, data, 406 max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); 407 } 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 { 413 return opus_multistream_encode_native(get_multistream_encoder(st), 414 opus_projection_copy_channel_in_int24, pcm, frame_size, data, 415 max_data_bytes, MAX_ENCODING_DEPTH, downmix_int, 0, get_mixing_matrix(st)); 416 } 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 { 423 return opus_multistream_encode_native(get_multistream_encoder(st), 424 opus_projection_copy_channel_in_float, pcm, frame_size, data, 425 max_data_bytes, MAX_ENCODING_DEPTH, downmix_float, 1, get_mixing_matrix(st)); 426 } 427 #endif 428 429 void opus_projection_encoder_destroy(OpusProjectionEncoder *st) 430 { 431 opus_free(st); 432 } 433 434 int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) 435 { 436 va_list ap; 437 MappingMatrix *demixing_matrix; 438 OpusMSEncoder *ms_encoder; 439 int ret = OPUS_OK; 440 441 ms_encoder = get_multistream_encoder(st); 442 demixing_matrix = get_enc_demixing_matrix(st); 443 444 va_start(ap, request); 445 switch(request) 446 { 447 case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: 448 { 449 opus_int32 *value = va_arg(ap, opus_int32*); 450 if (!value) 451 { 452 goto bad_arg; 453 } 454 *value = 455 ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams 456 + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); 457 } 458 break; 459 case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: 460 { 461 opus_int32 *value = va_arg(ap, opus_int32*); 462 if (!value) 463 { 464 goto bad_arg; 465 } 466 *value = demixing_matrix->gain; 467 } 468 break; 469 case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: 470 { 471 int i, j, k, l; 472 int nb_input_streams; 473 int nb_output_streams; 474 unsigned char *external_char; 475 opus_int16 *internal_short; 476 opus_int32 external_size; 477 opus_int32 internal_size; 478 479 /* (I/O is in relation to the decoder's perspective). */ 480 nb_input_streams = ms_encoder->layout.nb_streams + 481 ms_encoder->layout.nb_coupled_streams; 482 nb_output_streams = ms_encoder->layout.nb_channels; 483 484 external_char = va_arg(ap, unsigned char *); 485 external_size = va_arg(ap, opus_int32); 486 if (!external_char) 487 { 488 goto bad_arg; 489 } 490 internal_short = mapping_matrix_get_data(demixing_matrix); 491 internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); 492 if (external_size != internal_size) 493 { 494 goto bad_arg; 495 } 496 497 /* Copy demixing matrix subset to output destination. */ 498 l = 0; 499 for (i = 0; i < nb_input_streams; i++) { 500 for (j = 0; j < nb_output_streams; j++) { 501 k = demixing_matrix->rows * i + j; 502 external_char[2*l] = (unsigned char)internal_short[k]; 503 external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); 504 l++; 505 } 506 } 507 } 508 break; 509 default: 510 { 511 ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); 512 } 513 break; 514 } 515 va_end(ap); 516 return ret; 517 518 bad_arg: 519 va_end(ap); 520 return OPUS_BAD_ARG; 521 }