diff options
author | Nils Wallménius <nils@rockbox.org> | 2014-01-19 16:31:59 +0100 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2014-07-13 11:12:40 +0200 |
commit | 9b7ec42403073ee887efc531c153e6b1b6c15bab (patch) | |
tree | 07e72fe9d817c65a6fede22955344a870842d5e6 /lib/rbcodec/codecs/libopus/opus_decoder.c | |
parent | e557951c94c1efa769900257e466900f0ffeb53b (diff) | |
download | rockbox-9b7ec42403073ee887efc531c153e6b1b6c15bab.tar.gz rockbox-9b7ec42403073ee887efc531c153e6b1b6c15bab.zip |
Sync to upstream libopus
Sync to commit bb4b6885a139644cf3ac14e7deda9f633ec2d93c
This brings in a bunch of optimizations to decode speed
and memory usage. Allocations are switched from using
the pseudostack to using the real stack. Enabled hacks
to reduce stack usage.
This should fix crashes on sansa clip, although some
files will not play due to failing allocations in the
codec buffer.
Speeds up decoding of the following test files:
H300 (cf) C200 (arm7tdmi) ipod classic (arm9e)
16 kbps (silk) 14.28 MHz 4.00 MHz 2.61 MHz
64 kbps (celt) 4.09 MHz 8.08 MHz 6.24 MHz
128 kbps (celt) 1.93 MHz 8.83 MHz 6.53 MHz
Change-Id: I851733a8a5824b61feb363a173091bc7e6629b58
Diffstat (limited to 'lib/rbcodec/codecs/libopus/opus_decoder.c')
-rw-r--r-- | lib/rbcodec/codecs/libopus/opus_decoder.c | 85 |
1 files changed, 47 insertions, 38 deletions
diff --git a/lib/rbcodec/codecs/libopus/opus_decoder.c b/lib/rbcodec/codecs/libopus/opus_decoder.c index 198d168898..5d35ed2675 100644 --- a/lib/rbcodec/codecs/libopus/opus_decoder.c +++ b/lib/rbcodec/codecs/libopus/opus_decoder.c | |||
@@ -77,12 +77,6 @@ struct OpusDecoder { | |||
77 | opus_uint32 rangeFinal; | 77 | opus_uint32 rangeFinal; |
78 | }; | 78 | }; |
79 | 79 | ||
80 | #ifdef FIXED_POINT | ||
81 | static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { | ||
82 | return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; | ||
83 | } | ||
84 | #endif | ||
85 | |||
86 | 80 | ||
87 | int opus_decoder_get_size(int channels) | 81 | int opus_decoder_get_size(int channels) |
88 | { | 82 | { |
@@ -222,7 +216,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
222 | VARDECL(opus_val16, pcm_transition_silk); | 216 | VARDECL(opus_val16, pcm_transition_silk); |
223 | int pcm_transition_celt_size; | 217 | int pcm_transition_celt_size; |
224 | VARDECL(opus_val16, pcm_transition_celt); | 218 | VARDECL(opus_val16, pcm_transition_celt); |
225 | opus_val16 *pcm_transition = NULL; /* Silence false positive "may be used uninitialized" warning */ | 219 | opus_val16 *pcm_transition=NULL; |
226 | int redundant_audio_size; | 220 | int redundant_audio_size; |
227 | VARDECL(opus_val16, redundant_audio); | 221 | VARDECL(opus_val16, redundant_audio); |
228 | 222 | ||
@@ -237,6 +231,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
237 | int F2_5, F5, F10, F20; | 231 | int F2_5, F5, F10, F20; |
238 | const opus_val16 *window; | 232 | const opus_val16 *window; |
239 | opus_uint32 redundant_rng = 0; | 233 | opus_uint32 redundant_rng = 0; |
234 | int celt_accum; | ||
240 | ALLOC_STACK; | 235 | ALLOC_STACK; |
241 | 236 | ||
242 | silk_dec = (char*)st+st->silk_dec_offset; | 237 | silk_dec = (char*)st+st->silk_dec_offset; |
@@ -302,6 +297,14 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
302 | } | 297 | } |
303 | } | 298 | } |
304 | 299 | ||
300 | /* In fixed-point, we can tell CELT to do the accumulation on top of the | ||
301 | SILK PCM buffer. This saves some stack space. */ | ||
302 | #ifdef FIXED_POINT | ||
303 | celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); | ||
304 | #else | ||
305 | celt_accum = 0; | ||
306 | #endif | ||
307 | |||
305 | pcm_transition_silk_size = ALLOC_NONE; | 308 | pcm_transition_silk_size = ALLOC_NONE; |
306 | pcm_transition_celt_size = ALLOC_NONE; | 309 | pcm_transition_celt_size = ALLOC_NONE; |
307 | if (data!=NULL && st->prev_mode > 0 && ( | 310 | if (data!=NULL && st->prev_mode > 0 && ( |
@@ -332,14 +335,20 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
332 | } | 335 | } |
333 | 336 | ||
334 | /* Don't allocate any memory when in CELT-only mode */ | 337 | /* Don't allocate any memory when in CELT-only mode */ |
335 | pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; | 338 | pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; |
336 | ALLOC(pcm_silk, pcm_silk_size, opus_int16); | 339 | ALLOC(pcm_silk, pcm_silk_size, opus_int16); |
337 | 340 | ||
338 | /* SILK processing */ | 341 | /* SILK processing */ |
339 | if (mode != MODE_CELT_ONLY) | 342 | if (mode != MODE_CELT_ONLY) |
340 | { | 343 | { |
341 | int lost_flag, decoded_samples; | 344 | int lost_flag, decoded_samples; |
342 | opus_int16 *pcm_ptr = pcm_silk; | 345 | opus_int16 *pcm_ptr; |
346 | #ifdef FIXED_POINT | ||
347 | if (celt_accum) | ||
348 | pcm_ptr = pcm; | ||
349 | else | ||
350 | #endif | ||
351 | pcm_ptr = pcm_silk; | ||
343 | 352 | ||
344 | if (st->prev_mode==MODE_CELT_ONLY) | 353 | if (st->prev_mode==MODE_CELT_ONLY) |
345 | silk_InitDecoder( silk_dec ); | 354 | silk_InitDecoder( silk_dec ); |
@@ -469,7 +478,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
469 | { | 478 | { |
470 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); | 479 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
471 | celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, | 480 | celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, |
472 | redundant_audio, F5, NULL); | 481 | redundant_audio, F5, NULL, 0); |
473 | celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); | 482 | celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); |
474 | } | 483 | } |
475 | 484 | ||
@@ -484,25 +493,28 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
484 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); | 493 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
485 | /* Decode CELT */ | 494 | /* Decode CELT */ |
486 | celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, | 495 | celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, |
487 | len, pcm, celt_frame_size, &dec); | 496 | len, pcm, celt_frame_size, &dec, celt_accum); |
488 | } else { | 497 | } else { |
489 | unsigned char silence[2] = {0xFF, 0xFF}; | 498 | unsigned char silence[2] = {0xFF, 0xFF}; |
490 | for (i=0;i<frame_size*st->channels;i++) | 499 | if (!celt_accum) |
491 | pcm[i] = 0; | 500 | { |
501 | for (i=0;i<frame_size*st->channels;i++) | ||
502 | pcm[i] = 0; | ||
503 | } | ||
492 | /* For hybrid -> SILK transitions, we let the CELT MDCT | 504 | /* For hybrid -> SILK transitions, we let the CELT MDCT |
493 | do a fade-out by decoding a silence frame */ | 505 | do a fade-out by decoding a silence frame */ |
494 | if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) | 506 | if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) |
495 | { | 507 | { |
496 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); | 508 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
497 | celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL); | 509 | celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); |
498 | } | 510 | } |
499 | } | 511 | } |
500 | 512 | ||
501 | if (mode != MODE_CELT_ONLY) | 513 | if (mode != MODE_CELT_ONLY && !celt_accum) |
502 | { | 514 | { |
503 | #ifdef FIXED_POINT | 515 | #ifdef FIXED_POINT |
504 | for (i=0;i<frame_size*st->channels;i++) | 516 | for (i=0;i<frame_size*st->channels;i++) |
505 | pcm[i] = SAT16(pcm[i] + pcm_silk[i]); | 517 | pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); |
506 | #else | 518 | #else |
507 | for (i=0;i<frame_size*st->channels;i++) | 519 | for (i=0;i<frame_size*st->channels;i++) |
508 | pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); | 520 | pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); |
@@ -521,7 +533,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, | |||
521 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); | 533 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
522 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); | 534 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
523 | 535 | ||
524 | celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL); | 536 | celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); |
525 | celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); | 537 | celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); |
526 | smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, | 538 | smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, |
527 | pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); | 539 | pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); |
@@ -717,6 +729,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, | |||
717 | { | 729 | { |
718 | VARDECL(opus_int16, out); | 730 | VARDECL(opus_int16, out); |
719 | int ret, i; | 731 | int ret, i; |
732 | int nb_samples; | ||
720 | ALLOC_STACK; | 733 | ALLOC_STACK; |
721 | 734 | ||
722 | if(frame_size<=0) | 735 | if(frame_size<=0) |
@@ -724,6 +737,14 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, | |||
724 | RESTORE_STACK; | 737 | RESTORE_STACK; |
725 | return OPUS_BAD_ARG; | 738 | return OPUS_BAD_ARG; |
726 | } | 739 | } |
740 | if (data != NULL && len > 0 && !decode_fec) | ||
741 | { | ||
742 | nb_samples = opus_decoder_get_nb_samples(st, data, len); | ||
743 | if (nb_samples>0) | ||
744 | frame_size = IMIN(frame_size, nb_samples); | ||
745 | else | ||
746 | return OPUS_INVALID_PACKET; | ||
747 | } | ||
727 | ALLOC(out, frame_size*st->channels, opus_int16); | 748 | ALLOC(out, frame_size*st->channels, opus_int16); |
728 | 749 | ||
729 | ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); | 750 | ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); |
@@ -744,6 +765,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, | |||
744 | { | 765 | { |
745 | VARDECL(float, out); | 766 | VARDECL(float, out); |
746 | int ret, i; | 767 | int ret, i; |
768 | int nb_samples; | ||
747 | ALLOC_STACK; | 769 | ALLOC_STACK; |
748 | 770 | ||
749 | if(frame_size<=0) | 771 | if(frame_size<=0) |
@@ -752,6 +774,14 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, | |||
752 | return OPUS_BAD_ARG; | 774 | return OPUS_BAD_ARG; |
753 | } | 775 | } |
754 | 776 | ||
777 | if (data != NULL && len > 0 && !decode_fec) | ||
778 | { | ||
779 | nb_samples = opus_decoder_get_nb_samples(st, data, len); | ||
780 | if (nb_samples>0) | ||
781 | frame_size = IMIN(frame_size, nb_samples); | ||
782 | else | ||
783 | return OPUS_INVALID_PACKET; | ||
784 | } | ||
755 | ALLOC(out, frame_size*st->channels, float); | 785 | ALLOC(out, frame_size*st->channels, float); |
756 | 786 | ||
757 | ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); | 787 | ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); |
@@ -911,27 +941,6 @@ int opus_packet_get_bandwidth(const unsigned char *data) | |||
911 | return bandwidth; | 941 | return bandwidth; |
912 | } | 942 | } |
913 | 943 | ||
914 | int opus_packet_get_samples_per_frame(const unsigned char *data, | ||
915 | opus_int32 Fs) | ||
916 | { | ||
917 | int audiosize; | ||
918 | if (data[0]&0x80) | ||
919 | { | ||
920 | audiosize = ((data[0]>>3)&0x3); | ||
921 | audiosize = (Fs<<audiosize)/400; | ||
922 | } else if ((data[0]&0x60) == 0x60) | ||
923 | { | ||
924 | audiosize = (data[0]&0x08) ? Fs/50 : Fs/100; | ||
925 | } else { | ||
926 | audiosize = ((data[0]>>3)&0x3); | ||
927 | if (audiosize == 3) | ||
928 | audiosize = Fs*60/1000; | ||
929 | else | ||
930 | audiosize = (Fs<<audiosize)/100; | ||
931 | } | ||
932 | return audiosize; | ||
933 | } | ||
934 | |||
935 | int opus_packet_get_nb_channels(const unsigned char *data) | 944 | int opus_packet_get_nb_channels(const unsigned char *data) |
936 | { | 945 | { |
937 | return (data[0]&0x4) ? 2 : 1; | 946 | return (data[0]&0x4) ? 2 : 1; |