Coverage Report

Created: 2025-09-27 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opus/src/opus_projection_decoder.c
Line
Count
Source
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
9.72k
{
57
9.72k
  float *float_dst;
58
9.72k
  const MappingMatrix *matrix;
59
9.72k
  float_dst = (float *)dst;
60
9.72k
  matrix = (const MappingMatrix *)user_data;
61
62
9.72k
  if (dst_channel == 0)
63
8.90k
    OPUS_CLEAR(float_dst, frame_size * dst_stride);
64
65
9.72k
  if (src != NULL)
66
9.72k
    mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel,
67
9.72k
      src_stride, float_dst, dst_stride, frame_size);
68
9.72k
}
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
18.1k
{
80
18.1k
  opus_int16 *short_dst;
81
18.1k
  const MappingMatrix *matrix;
82
18.1k
  short_dst = (opus_int16 *)dst;
83
18.1k
  matrix = (const MappingMatrix *)user_data;
84
18.1k
  if (dst_channel == 0)
85
16.2k
    OPUS_CLEAR(short_dst, frame_size * dst_stride);
86
87
18.1k
  if (src != NULL)
88
18.1k
    mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel,
89
18.1k
      src_stride, short_dst, dst_stride, frame_size);
90
18.1k
}
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
0
{
101
0
  opus_int32 *short_dst;
102
0
  const MappingMatrix *matrix;
103
0
  short_dst = (opus_int32 *)dst;
104
0
  matrix = (const MappingMatrix *)user_data;
105
0
  if (dst_channel == 0)
106
0
    OPUS_CLEAR(short_dst, frame_size * dst_stride);
107
108
0
  if (src != NULL)
109
0
    mapping_matrix_multiply_channel_out_int24(matrix, src, dst_channel,
110
0
      src_stride, short_dst, dst_stride, frame_size);
111
0
}
112
113
static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st)
114
52.5k
{
115
  /* void* cast avoids clang -Wcast-align warning */
116
52.5k
  return (MappingMatrix*)(void*)((char*)st +
117
52.5k
    align(sizeof(OpusProjectionDecoder)));
118
52.5k
}
119
120
static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st)
121
52.5k
{
122
  /* void* cast avoids clang -Wcast-align warning */
123
52.5k
  return (OpusMSDecoder*)(void*)((char*)st +
124
52.5k
    align(sizeof(OpusProjectionDecoder) +
125
52.5k
    st->demixing_matrix_size_in_bytes));
126
52.5k
}
127
128
opus_int32 opus_projection_decoder_get_size(int channels, int streams,
129
                                            int coupled_streams)
130
26.7k
{
131
26.7k
  opus_int32 matrix_size;
132
26.7k
  opus_int32 decoder_size;
133
134
26.7k
  matrix_size =
135
26.7k
    mapping_matrix_get_size(streams + coupled_streams, channels);
136
26.7k
  if (!matrix_size)
137
32
    return 0;
138
139
26.7k
  decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams);
140
26.7k
  if (!decoder_size)
141
190
    return 0;
142
143
26.5k
  return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size;
144
26.7k
}
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
26.5k
{
150
26.5k
  int nb_input_streams;
151
26.5k
  opus_int32 expected_matrix_size;
152
26.5k
  int i, ret;
153
26.5k
  unsigned char mapping[255];
154
26.5k
  VARDECL(opus_int16, buf);
155
26.5k
  ALLOC_STACK;
156
157
  /* Verify supplied matrix size. */
158
26.5k
  nb_input_streams = streams + coupled_streams;
159
26.5k
  expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16);
160
26.5k
  if (expected_matrix_size != demixing_matrix_size)
161
229
  {
162
229
    RESTORE_STACK;
163
229
    return OPUS_BAD_ARG;
164
229
  }
165
166
  /* Convert demixing matrix input into internal format. */
167
26.2k
  ALLOC(buf, nb_input_streams * channels, opus_int16);
168
330k
  for (i = 0; i < nb_input_streams * channels; i++)
169
304k
  {
170
304k
    int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i];
171
304k
    s = ((s & 0xFFFF) ^ 0x8000) - 0x8000;
172
304k
    buf[i] = (opus_int16)s;
173
304k
  }
174
175
  /* Assign demixing matrix. */
176
26.2k
  st->demixing_matrix_size_in_bytes =
177
26.2k
    mapping_matrix_get_size(channels, nb_input_streams);
178
26.2k
  if (!st->demixing_matrix_size_in_bytes)
179
0
  {
180
0
    RESTORE_STACK;
181
0
    return OPUS_BAD_ARG;
182
0
  }
183
184
26.2k
  mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0,
185
26.2k
    buf, demixing_matrix_size);
186
187
  /* Set trivial mapping so each input channel pairs with a matrix column. */
188
59.9k
  for (i = 0; i < channels; i++)
189
33.6k
    mapping[i] = i;
190
191
26.2k
  ret = opus_multistream_decoder_init(
192
26.2k
    get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping);
193
26.2k
  RESTORE_STACK;
194
26.2k
  return ret;
195
26.2k
}
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
26.7k
{
201
26.7k
  int size;
202
26.7k
  int ret;
203
26.7k
  OpusProjectionDecoder *st;
204
205
  /* Allocate space for the projection decoder. */
206
26.7k
  size = opus_projection_decoder_get_size(channels, streams, coupled_streams);
207
26.7k
  if (!size) {
208
222
    if (error)
209
222
      *error = OPUS_ALLOC_FAIL;
210
222
    return NULL;
211
222
  }
212
26.5k
  st = (OpusProjectionDecoder *)opus_alloc(size);
213
26.5k
  if (!st)
214
0
  {
215
0
    if (error)
216
0
      *error = OPUS_ALLOC_FAIL;
217
0
    return NULL;
218
0
  }
219
220
  /* Initialize projection decoder with provided settings. */
221
26.5k
  ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams,
222
26.5k
                                     demixing_matrix, demixing_matrix_size);
223
26.5k
  if (ret != OPUS_OK)
224
276
  {
225
276
    opus_free(st);
226
276
    st = NULL;
227
276
  }
228
26.5k
  if (error)
229
26.5k
    *error = ret;
230
26.5k
  return st;
231
26.5k
}
232
233
#ifdef FIXED_POINT
234
16.9k
#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
16.9k
{
243
16.9k
  return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
244
16.9k
    pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, OPTIONAL_CLIP,
245
16.9k
    get_dec_demixing_matrix(st));
246
16.9k
}
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
0
{
252
0
  return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
253
0
    pcm, opus_projection_copy_channel_out_int24, frame_size, decode_fec, 0,
254
0
    get_dec_demixing_matrix(st));
255
0
}
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
9.30k
{
261
9.30k
  return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
262
9.30k
    pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0,
263
9.30k
    get_dec_demixing_matrix(st));
264
9.30k
}
265
#endif
266
267
int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...)
268
0
{
269
0
  va_list ap;
270
0
  int ret = OPUS_OK;
271
272
0
  va_start(ap, request);
273
0
  ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st),
274
0
    request, ap);
275
0
  va_end(ap);
276
0
  return ret;
277
0
}
278
279
void opus_projection_decoder_destroy(OpusProjectionDecoder *st)
280
26.2k
{
281
26.2k
  opus_free(st);
282
26.2k
}