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
--
⑨