tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }