shithub: opus

Download patch

ref: 3399621b27c4a66b1c61dcb624ccb2b4d42e1d0d
parent: d04f59b4bfbb2ca105f0ee7109913ac0f0bca6b8
author: Jean-Marc Valin <jeanmarcv@google.com>
date: Thu Jun 13 06:55:12 EDT 2024

Adds 24-bit API for projection encoder/decoder

--- a/include/opus_projection.h
+++ b/include/opus_projection.h
@@ -260,7 +260,45 @@
     opus_int32 max_data_bytes
 ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
 
+/** Encodes a projection Opus frame.
+  * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
+  * @param[in] pcm <tt>const opus_int32*</tt>: The input signal as interleaved
+  *                                            samples representing (or slightly exceeding) 24-bit values.
+  *                                            This must contain
+  *                                            <code>frame_size*channels</code>
+  *                                            samples.
+  * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+  *                                 signal.
+  *                                 This must be an Opus frame size for the
+  *                                 encoder's sampling rate.
+  *                                 For example, at 48 kHz the permitted values
+  *                                 are 120, 240, 480, 960, 1920, and 2880.
+  *                                 Passing in a duration of less than 10 ms
+  *                                 (480 samples at 48 kHz) will prevent the
+  *                                 encoder from using the LPC or hybrid modes.
+  * @param[out] data <tt>unsigned char*</tt>: Output payload.
+  *                                           This must contain storage for at
+  *                                           least \a max_data_bytes.
+  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+  *                                                 memory for the output
+  *                                                 payload. This may be
+  *                                                 used to impose an upper limit on
+  *                                                 the instant bitrate, but should
+  *                                                 not be used as the only bitrate
+  *                                                 control. Use #OPUS_SET_BITRATE to
+  *                                                 control the bitrate.
+  * @returns The length of the encoded packet (in bytes) on success or a
+  *          negative error code (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode24(
+    OpusProjectionEncoder *st,
+    const opus_int32 *pcm,
+    int frame_size,
+    unsigned char *data,
+    opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
 
+
 /** Encodes a projection Opus frame from floating point input.
   * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
   * @param[in] pcm <tt>const float*</tt>: The input signal as interleaved
@@ -493,6 +531,43 @@
     int decode_fec
 ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
 
+/** Decode a projection Opus packet.
+  * @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
+  * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+  *                                                Use a <code>NULL</code>
+  *                                                pointer to indicate packet
+  *                                                loss.
+  * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+  * @param[out] pcm <tt>opus_int32*</tt>: Output signal, with interleaved
+  *                                       samples representing (or slightly exceeding) 24-bit values.
+  *                                       This must contain room for
+  *                                       <code>frame_size*channels</code>
+  *                                       samples.
+  * @param frame_size <tt>int</tt>: The number of samples per channel of
+  *                                 available space in \a pcm.
+  *                                 If this is less than the maximum packet duration
+  *                                 (120 ms; 5760 for 48kHz), this function will not be capable
+  *                                 of decoding some packets. In the case of PLC (data==NULL)
+  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly
+  *                                 the duration of audio that is missing, otherwise the
+  *                                 decoder will not be in the optimal state to decode the
+  *                                 next incoming packet. For the PLC and FEC cases, frame_size
+  *                                 <b>must</b> be a multiple of 2.5 ms.
+  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+  *                                 forward error correction data be decoded.
+  *                                 If no such data is available, the frame is
+  *                                 decoded as if it were lost.
+  * @returns Number of samples decoded on success or a negative error code
+  *          (see @ref opus_errorcodes) on failure.
+  */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode24(
+    OpusProjectionDecoder *st,
+    const unsigned char *data,
+    opus_int32 len,
+    opus_int32 *pcm,
+    int frame_size,
+    int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
 
 /** Decode a projection Opus packet with floating point output.
   * @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
--- a/src/mapping_matrix.c
+++ b/src/mapping_matrix.c
@@ -216,6 +216,72 @@
   }
 }
 
+void mapping_matrix_multiply_channel_in_int24(
+    const MappingMatrix *matrix,
+    const opus_int32 *input,
+    int input_rows,
+    opus_res *output,
+    int output_row,
+    int output_rows,
+    int frame_size)
+{
+  /* Matrix data is ordered col-wise. */
+  opus_int16* matrix_data;
+  int i, col;
+
+  celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);
+
+  matrix_data = mapping_matrix_get_data(matrix);
+
+  for (i = 0; i < frame_size; i++)
+  {
+    opus_val64 tmp = 0;
+    for (col = 0; col < input_rows; col++)
+    {
+      tmp +=
+        matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] *
+        (opus_val64)input[MATRIX_INDEX(input_rows, col, i)];
+    }
+#if defined(FIXED_POINT)
+    output[output_rows * i] = INT24TORES((tmp + 16384) >> 15);
+#else
+    output[output_rows * i] = INT24TORES((1/(32768.f))*tmp);
+#endif
+  }
+}
+
+void mapping_matrix_multiply_channel_out_int24(
+    const MappingMatrix *matrix,
+    const opus_res *input,
+    int input_row,
+    int input_rows,
+    opus_int32 *output,
+    int output_rows,
+    int frame_size)
+{
+  /* Matrix data is ordered col-wise. */
+  opus_int16* matrix_data;
+  int i, row;
+  opus_int32 input_sample;
+
+  celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);
+
+  matrix_data = mapping_matrix_get_data(matrix);
+
+  for (i = 0; i < frame_size; i++)
+  {
+    input_sample = RES2INT24(input[input_rows * i]);
+    for (row = 0; row < output_rows; row++)
+    {
+      opus_int64 tmp =
+        (opus_int64)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] *
+        input_sample;
+      output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15;
+    }
+  }
+}
+
+
 const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 };
 const opus_int16 mapping_matrix_foa_mixing_data[36] = {
      16384,      0, -16384,  23170,      0,      0,  16384,  23170,
--- a/src/mapping_matrix.h
+++ b/src/mapping_matrix.h
@@ -103,6 +103,26 @@
     int frame_size
 );
 
+
+void mapping_matrix_multiply_channel_in_int24(
+    const MappingMatrix *matrix,
+    const opus_int32 *input,
+    int input_rows,
+    opus_res *output,
+    int output_row,
+    int output_rows,
+    int frame_size
+);
+
+void mapping_matrix_multiply_channel_out_int24(
+    const MappingMatrix *matrix,
+    const opus_res *input,
+    int input_row,
+    int input_rows,
+    opus_int32 *output,
+    int output_rows,
+    int frame_size
+);
 /* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics.
  *   foa: first-order ambisonics
  *   soa: second-order ambisonics
--- a/src/opus_projection_decoder.c
+++ b/src/opus_projection_decoder.c
@@ -89,6 +89,27 @@
       src_stride, short_dst, dst_stride, frame_size);
 }
 
+static void opus_projection_copy_channel_out_int24(
+  void *dst,
+  int dst_stride,
+  int dst_channel,
+  const opus_res *src,
+  int src_stride,
+  int frame_size,
+  void *user_data)
+{
+  opus_int32 *short_dst;
+  const MappingMatrix *matrix;
+  short_dst = (opus_int32 *)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_int24(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 */
@@ -221,6 +242,15 @@
 {
   return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
     pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, OPTIONAL_CLIP,
+    get_dec_demixing_matrix(st));
+}
+
+int opus_projection_decode24(OpusProjectionDecoder *st, const unsigned char *data,
+                           opus_int32 len, opus_int32 *pcm, int frame_size,
+                           int decode_fec)
+{
+  return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
+    pcm, opus_projection_copy_channel_out_int24, frame_size, decode_fec, 0,
     get_dec_demixing_matrix(st));
 }
 
--- a/src/opus_projection_encoder.c
+++ b/src/opus_projection_encoder.c
@@ -75,6 +75,20 @@
     (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size);
 }
 
+static void opus_projection_copy_channel_in_int24(
+  opus_res *dst,
+  int dst_stride,
+  const void *src,
+  int src_stride,
+  int src_channel,
+  int frame_size,
+  void *user_data
+)
+{
+  mapping_matrix_multiply_channel_in_int24((const MappingMatrix*)user_data,
+    (const opus_int32*)src, src_stride, dst, src_channel, dst_stride, frame_size);
+}
+
 static int get_order_plus_one_from_channels(int channels, int *order_plus_one)
 {
   int order_plus_one_;
@@ -390,6 +404,15 @@
   return opus_multistream_encode_native(get_multistream_encoder(st),
     opus_projection_copy_channel_in_short, pcm, frame_size, data,
     max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st));
+}
+
+int opus_projection_encode24(OpusProjectionEncoder *st, const opus_int32 *pcm,
+                           int frame_size, unsigned char *data,
+                           opus_int32 max_data_bytes)
+{
+  return opus_multistream_encode_native(get_multistream_encoder(st),
+    opus_projection_copy_channel_in_int24, pcm, frame_size, data,
+    max_data_bytes, MAX_ENCODING_DEPTH, downmix_int, 0, get_mixing_matrix(st));
 }
 
 #ifndef DISABLE_FLOAT_API
--