OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2011 Xiph.Org Foundation |
| 2 Written by Jean-Marc Valin */ |
| 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 "opus_multistream.h" |
| 33 #include "opus.h" |
| 34 #include "opus_private.h" |
| 35 #include "stack_alloc.h" |
| 36 #include <stdarg.h> |
| 37 #include "float_cast.h" |
| 38 #include "os_support.h" |
| 39 |
| 40 struct OpusMSDecoder { |
| 41 ChannelLayout layout; |
| 42 /* Decoder states go here */ |
| 43 }; |
| 44 |
| 45 |
| 46 |
| 47 |
| 48 /* DECODER */ |
| 49 |
| 50 opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_stre
ams) |
| 51 { |
| 52 int coupled_size; |
| 53 int mono_size; |
| 54 |
| 55 if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0
; |
| 56 coupled_size = opus_decoder_get_size(2); |
| 57 mono_size = opus_decoder_get_size(1); |
| 58 return align(sizeof(OpusMSDecoder)) |
| 59 + nb_coupled_streams * align(coupled_size) |
| 60 + (nb_streams-nb_coupled_streams) * align(mono_size); |
| 61 } |
| 62 |
| 63 int opus_multistream_decoder_init( |
| 64 OpusMSDecoder *st, |
| 65 opus_int32 Fs, |
| 66 int channels, |
| 67 int streams, |
| 68 int coupled_streams, |
| 69 const unsigned char *mapping |
| 70 ) |
| 71 { |
| 72 int coupled_size; |
| 73 int mono_size; |
| 74 int i, ret; |
| 75 char *ptr; |
| 76 |
| 77 if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
| 78 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) |
| 79 return OPUS_BAD_ARG; |
| 80 |
| 81 st->layout.nb_channels = channels; |
| 82 st->layout.nb_streams = streams; |
| 83 st->layout.nb_coupled_streams = coupled_streams; |
| 84 |
| 85 for (i=0;i<st->layout.nb_channels;i++) |
| 86 st->layout.mapping[i] = mapping[i]; |
| 87 if (!validate_layout(&st->layout)) |
| 88 return OPUS_BAD_ARG; |
| 89 |
| 90 ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
| 91 coupled_size = opus_decoder_get_size(2); |
| 92 mono_size = opus_decoder_get_size(1); |
| 93 |
| 94 for (i=0;i<st->layout.nb_coupled_streams;i++) |
| 95 { |
| 96 ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); |
| 97 if(ret!=OPUS_OK)return ret; |
| 98 ptr += align(coupled_size); |
| 99 } |
| 100 for (;i<st->layout.nb_streams;i++) |
| 101 { |
| 102 ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); |
| 103 if(ret!=OPUS_OK)return ret; |
| 104 ptr += align(mono_size); |
| 105 } |
| 106 return OPUS_OK; |
| 107 } |
| 108 |
| 109 |
| 110 OpusMSDecoder *opus_multistream_decoder_create( |
| 111 opus_int32 Fs, |
| 112 int channels, |
| 113 int streams, |
| 114 int coupled_streams, |
| 115 const unsigned char *mapping, |
| 116 int *error |
| 117 ) |
| 118 { |
| 119 int ret; |
| 120 OpusMSDecoder *st; |
| 121 if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
| 122 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) |
| 123 { |
| 124 if (error) |
| 125 *error = OPUS_BAD_ARG; |
| 126 return NULL; |
| 127 } |
| 128 st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, c
oupled_streams)); |
| 129 if (st==NULL) |
| 130 { |
| 131 if (error) |
| 132 *error = OPUS_ALLOC_FAIL; |
| 133 return NULL; |
| 134 } |
| 135 ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_stream
s, mapping); |
| 136 if (error) |
| 137 *error = ret; |
| 138 if (ret != OPUS_OK) |
| 139 { |
| 140 opus_free(st); |
| 141 st = NULL; |
| 142 } |
| 143 return st; |
| 144 } |
| 145 |
| 146 typedef void (*opus_copy_channel_out_func)( |
| 147 void *dst, |
| 148 int dst_stride, |
| 149 int dst_channel, |
| 150 const opus_val16 *src, |
| 151 int src_stride, |
| 152 int frame_size |
| 153 ); |
| 154 |
| 155 static int opus_multistream_decode_native( |
| 156 OpusMSDecoder *st, |
| 157 const unsigned char *data, |
| 158 opus_int32 len, |
| 159 void *pcm, |
| 160 opus_copy_channel_out_func copy_channel_out, |
| 161 int frame_size, |
| 162 int decode_fec, |
| 163 int soft_clip |
| 164 ) |
| 165 { |
| 166 opus_int32 Fs; |
| 167 int coupled_size; |
| 168 int mono_size; |
| 169 int s, c; |
| 170 char *ptr; |
| 171 int do_plc=0; |
| 172 VARDECL(opus_val16, buf); |
| 173 ALLOC_STACK; |
| 174 |
| 175 /* Limit frame_size to avoid excessive stack allocations. */ |
| 176 opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs)); |
| 177 frame_size = IMIN(frame_size, Fs/25*3); |
| 178 ALLOC(buf, 2*frame_size, opus_val16); |
| 179 ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
| 180 coupled_size = opus_decoder_get_size(2); |
| 181 mono_size = opus_decoder_get_size(1); |
| 182 |
| 183 if (len==0) |
| 184 do_plc = 1; |
| 185 if (len < 0) |
| 186 return OPUS_BAD_ARG; |
| 187 if (!do_plc && len < 2*st->layout.nb_streams-1) |
| 188 return OPUS_INVALID_PACKET; |
| 189 for (s=0;s<st->layout.nb_streams;s++) |
| 190 { |
| 191 OpusDecoder *dec; |
| 192 int packet_offset, ret; |
| 193 |
| 194 dec = (OpusDecoder*)ptr; |
| 195 ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(m
ono_size); |
| 196 |
| 197 if (!do_plc && len<=0) |
| 198 { |
| 199 RESTORE_STACK; |
| 200 return OPUS_INVALID_PACKET; |
| 201 } |
| 202 packet_offset = 0; |
| 203 ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=s
t->layout.nb_streams-1, &packet_offset, soft_clip); |
| 204 data += packet_offset; |
| 205 len -= packet_offset; |
| 206 if (ret > frame_size) |
| 207 { |
| 208 RESTORE_STACK; |
| 209 return OPUS_BUFFER_TOO_SMALL; |
| 210 } |
| 211 if (s>0 && ret != frame_size) |
| 212 { |
| 213 RESTORE_STACK; |
| 214 return OPUS_INVALID_PACKET; |
| 215 } |
| 216 if (ret <= 0) |
| 217 { |
| 218 RESTORE_STACK; |
| 219 return ret; |
| 220 } |
| 221 frame_size = ret; |
| 222 if (s < st->layout.nb_coupled_streams) |
| 223 { |
| 224 int chan, prev; |
| 225 prev = -1; |
| 226 /* Copy "left" audio to the channel(s) where it belongs */ |
| 227 while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) |
| 228 { |
| 229 (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
| 230 buf, 2, frame_size); |
| 231 prev = chan; |
| 232 } |
| 233 prev = -1; |
| 234 /* Copy "right" audio to the channel(s) where it belongs */ |
| 235 while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) |
| 236 { |
| 237 (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
| 238 buf+1, 2, frame_size); |
| 239 prev = chan; |
| 240 } |
| 241 } else { |
| 242 int chan, prev; |
| 243 prev = -1; |
| 244 /* Copy audio to the channel(s) where it belongs */ |
| 245 while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) |
| 246 { |
| 247 (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
| 248 buf, 1, frame_size); |
| 249 prev = chan; |
| 250 } |
| 251 } |
| 252 } |
| 253 /* Handle muted channels */ |
| 254 for (c=0;c<st->layout.nb_channels;c++) |
| 255 { |
| 256 if (st->layout.mapping[c] == 255) |
| 257 { |
| 258 (*copy_channel_out)(pcm, st->layout.nb_channels, c, |
| 259 NULL, 0, frame_size); |
| 260 } |
| 261 } |
| 262 RESTORE_STACK; |
| 263 return frame_size; |
| 264 } |
| 265 |
| 266 #if !defined(DISABLE_FLOAT_API) |
| 267 static void opus_copy_channel_out_float( |
| 268 void *dst, |
| 269 int dst_stride, |
| 270 int dst_channel, |
| 271 const opus_val16 *src, |
| 272 int src_stride, |
| 273 int frame_size |
| 274 ) |
| 275 { |
| 276 float *float_dst; |
| 277 opus_int32 i; |
| 278 float_dst = (float*)dst; |
| 279 if (src != NULL) |
| 280 { |
| 281 for (i=0;i<frame_size;i++) |
| 282 #if defined(FIXED_POINT) |
| 283 float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride]; |
| 284 #else |
| 285 float_dst[i*dst_stride+dst_channel] = src[i*src_stride]; |
| 286 #endif |
| 287 } |
| 288 else |
| 289 { |
| 290 for (i=0;i<frame_size;i++) |
| 291 float_dst[i*dst_stride+dst_channel] = 0; |
| 292 } |
| 293 } |
| 294 #endif |
| 295 |
| 296 static void opus_copy_channel_out_short( |
| 297 void *dst, |
| 298 int dst_stride, |
| 299 int dst_channel, |
| 300 const opus_val16 *src, |
| 301 int src_stride, |
| 302 int frame_size |
| 303 ) |
| 304 { |
| 305 opus_int16 *short_dst; |
| 306 opus_int32 i; |
| 307 short_dst = (opus_int16*)dst; |
| 308 if (src != NULL) |
| 309 { |
| 310 for (i=0;i<frame_size;i++) |
| 311 #if defined(FIXED_POINT) |
| 312 short_dst[i*dst_stride+dst_channel] = src[i*src_stride]; |
| 313 #else |
| 314 short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]); |
| 315 #endif |
| 316 } |
| 317 else |
| 318 { |
| 319 for (i=0;i<frame_size;i++) |
| 320 short_dst[i*dst_stride+dst_channel] = 0; |
| 321 } |
| 322 } |
| 323 |
| 324 |
| 325 |
| 326 #ifdef FIXED_POINT |
| 327 int opus_multistream_decode( |
| 328 OpusMSDecoder *st, |
| 329 const unsigned char *data, |
| 330 opus_int32 len, |
| 331 opus_int16 *pcm, |
| 332 int frame_size, |
| 333 int decode_fec |
| 334 ) |
| 335 { |
| 336 return opus_multistream_decode_native(st, data, len, |
| 337 pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0); |
| 338 } |
| 339 |
| 340 #ifndef DISABLE_FLOAT_API |
| 341 int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, |
| 342 opus_int32 len, float *pcm, int frame_size, int decode_fec) |
| 343 { |
| 344 return opus_multistream_decode_native(st, data, len, |
| 345 pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); |
| 346 } |
| 347 #endif |
| 348 |
| 349 #else |
| 350 |
| 351 int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data, |
| 352 opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) |
| 353 { |
| 354 return opus_multistream_decode_native(st, data, len, |
| 355 pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1); |
| 356 } |
| 357 |
| 358 int opus_multistream_decode_float( |
| 359 OpusMSDecoder *st, |
| 360 const unsigned char *data, |
| 361 opus_int32 len, |
| 362 float *pcm, |
| 363 int frame_size, |
| 364 int decode_fec |
| 365 ) |
| 366 { |
| 367 return opus_multistream_decode_native(st, data, len, |
| 368 pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); |
| 369 } |
| 370 #endif |
| 371 |
| 372 int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) |
| 373 { |
| 374 va_list ap; |
| 375 int coupled_size, mono_size; |
| 376 char *ptr; |
| 377 int ret = OPUS_OK; |
| 378 |
| 379 va_start(ap, request); |
| 380 |
| 381 coupled_size = opus_decoder_get_size(2); |
| 382 mono_size = opus_decoder_get_size(1); |
| 383 ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
| 384 switch (request) |
| 385 { |
| 386 case OPUS_GET_BANDWIDTH_REQUEST: |
| 387 case OPUS_GET_SAMPLE_RATE_REQUEST: |
| 388 case OPUS_GET_GAIN_REQUEST: |
| 389 case OPUS_GET_LAST_PACKET_DURATION_REQUEST: |
| 390 { |
| 391 OpusDecoder *dec; |
| 392 /* For int32* GET params, just query the first stream */ |
| 393 opus_int32 *value = va_arg(ap, opus_int32*); |
| 394 dec = (OpusDecoder*)ptr; |
| 395 ret = opus_decoder_ctl(dec, request, value); |
| 396 } |
| 397 break; |
| 398 case OPUS_GET_FINAL_RANGE_REQUEST: |
| 399 { |
| 400 int s; |
| 401 opus_uint32 *value = va_arg(ap, opus_uint32*); |
| 402 opus_uint32 tmp; |
| 403 if (!value) |
| 404 { |
| 405 goto bad_arg; |
| 406 } |
| 407 *value = 0; |
| 408 for (s=0;s<st->layout.nb_streams;s++) |
| 409 { |
| 410 OpusDecoder *dec; |
| 411 dec = (OpusDecoder*)ptr; |
| 412 if (s < st->layout.nb_coupled_streams) |
| 413 ptr += align(coupled_size); |
| 414 else |
| 415 ptr += align(mono_size); |
| 416 ret = opus_decoder_ctl(dec, request, &tmp); |
| 417 if (ret != OPUS_OK) break; |
| 418 *value ^= tmp; |
| 419 } |
| 420 } |
| 421 break; |
| 422 case OPUS_RESET_STATE: |
| 423 { |
| 424 int s; |
| 425 for (s=0;s<st->layout.nb_streams;s++) |
| 426 { |
| 427 OpusDecoder *dec; |
| 428 |
| 429 dec = (OpusDecoder*)ptr; |
| 430 if (s < st->layout.nb_coupled_streams) |
| 431 ptr += align(coupled_size); |
| 432 else |
| 433 ptr += align(mono_size); |
| 434 ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); |
| 435 if (ret != OPUS_OK) |
| 436 break; |
| 437 } |
| 438 } |
| 439 break; |
| 440 case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: |
| 441 { |
| 442 int s; |
| 443 opus_int32 stream_id; |
| 444 OpusDecoder **value; |
| 445 stream_id = va_arg(ap, opus_int32); |
| 446 if (stream_id<0 || stream_id >= st->layout.nb_streams) |
| 447 ret = OPUS_BAD_ARG; |
| 448 value = va_arg(ap, OpusDecoder**); |
| 449 if (!value) |
| 450 { |
| 451 goto bad_arg; |
| 452 } |
| 453 for (s=0;s<stream_id;s++) |
| 454 { |
| 455 if (s < st->layout.nb_coupled_streams) |
| 456 ptr += align(coupled_size); |
| 457 else |
| 458 ptr += align(mono_size); |
| 459 } |
| 460 *value = (OpusDecoder*)ptr; |
| 461 } |
| 462 break; |
| 463 case OPUS_SET_GAIN_REQUEST: |
| 464 { |
| 465 int s; |
| 466 /* This works for int32 params */ |
| 467 opus_int32 value = va_arg(ap, opus_int32); |
| 468 for (s=0;s<st->layout.nb_streams;s++) |
| 469 { |
| 470 OpusDecoder *dec; |
| 471 |
| 472 dec = (OpusDecoder*)ptr; |
| 473 if (s < st->layout.nb_coupled_streams) |
| 474 ptr += align(coupled_size); |
| 475 else |
| 476 ptr += align(mono_size); |
| 477 ret = opus_decoder_ctl(dec, request, value); |
| 478 if (ret != OPUS_OK) |
| 479 break; |
| 480 } |
| 481 } |
| 482 break; |
| 483 default: |
| 484 ret = OPUS_UNIMPLEMENTED; |
| 485 break; |
| 486 } |
| 487 |
| 488 va_end(ap); |
| 489 return ret; |
| 490 bad_arg: |
| 491 va_end(ap); |
| 492 return OPUS_BAD_ARG; |
| 493 } |
| 494 |
| 495 |
| 496 void opus_multistream_decoder_destroy(OpusMSDecoder *st) |
| 497 { |
| 498 opus_free(st); |
| 499 } |
OLD | NEW |