summaryrefslogtreecommitdiff
path: root/libavcodec/wavpack.c
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2010-02-19 14:05:41 +0000
committerKostya Shishkov <kostya.shishkov@gmail.com>2010-02-19 14:05:41 +0000
commit965828bb66c59ed2f5f7cb07f32840cf555d9cad (patch)
tree9af12ba0df472c6777a0cc906b0d23080b37f7ac /libavcodec/wavpack.c
parent245d5a48efdee972434d96646017c5267f538f65 (diff)
Since WavPack chunk can contain more samples than FFmpeg is guaranteed to
hold, decode it in several iterations outputting as many samples as possible. Originally committed as revision 21894 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/wavpack.c')
-rw-r--r--libavcodec/wavpack.c87
1 files changed, 75 insertions, 12 deletions
diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index 783e7d70bf..bcea7b528d 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -67,6 +67,13 @@ enum WP_ID{
WP_ID_CHANINFO
};
+typedef struct SavedContext {
+ int offset;
+ int size;
+ int bits_used;
+ uint32_t crc;
+} SavedContext;
+
#define MAX_TERMS 16
typedef struct Decorr {
@@ -107,6 +114,10 @@ typedef struct WavpackContext {
int float_shift;
int float_max_exp;
WvChannel ch[2];
+ int samples_left;
+ int max_samples;
+ int pos;
+ SavedContext sc, extra_sc;
} WavpackContext;
// exponent table copied from WavPack source
@@ -439,18 +450,25 @@ static float wv_get_value_float(WavpackContext *s, uint32_t *crc, int S)
return value.f;
}
+static void wv_reset_saved_context(WavpackContext *s)
+{
+ s->pos = 0;
+ s->sc.crc = s->extra_sc.crc = 0xFFFFFFFF;
+}
+
static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *dst, const int type)
{
int i, j, count = 0;
int last, t;
int A, B, L, L2, R, R2;
- int pos = 0;
- uint32_t crc = 0xFFFFFFFF;
- uint32_t crc_extra_bits = 0xFFFFFFFF;
+ int pos = s->pos;
+ uint32_t crc = s->sc.crc;
+ uint32_t crc_extra_bits = s->extra_sc.crc;
int16_t *dst16 = dst;
int32_t *dst32 = dst;
float *dstfl = dst;
+ if(s->samples_left == s->samples)
s->one = s->zero = s->zeroes = 0;
do{
L = wv_get_value(s, gb, 0, &last);
@@ -539,8 +557,10 @@ static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *d
*dst16++ = wv_get_value_integer(s, &crc_extra_bits, R);
}
count++;
- }while(!last && count < s->samples);
+ }while(!last && count < s->max_samples);
+ s->samples_left -= count;
+ if(!s->samples_left){
if(crc != s->CRC){
av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
return -1;
@@ -549,6 +569,16 @@ static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *d
av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
return -1;
}
+ wv_reset_saved_context(s);
+ }else{
+ s->pos = pos;
+ s->sc.crc = crc;
+ s->sc.bits_used = get_bits_count(&s->gb);
+ if(s->got_extra_bits){
+ s->extra_sc.crc = crc_extra_bits;
+ s->extra_sc.bits_used = get_bits_count(&s->gb_extra_bits);
+ }
+ }
return count * 2;
}
@@ -557,13 +587,14 @@ static inline int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, void *dst
int i, j, count = 0;
int last, t;
int A, S, T;
- int pos = 0;
- uint32_t crc = 0xFFFFFFFF;
- uint32_t crc_extra_bits = 0xFFFFFFFF;
+ int pos = s->pos;
+ uint32_t crc = s->sc.crc;
+ uint32_t crc_extra_bits = s->extra_sc.crc;
int16_t *dst16 = dst;
int32_t *dst32 = dst;
float *dstfl = dst;
+ if(s->samples_left == s->samples)
s->one = s->zero = s->zeroes = 0;
do{
T = wv_get_value(s, gb, 0, &last);
@@ -601,6 +632,8 @@ static inline int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, void *dst
count++;
}while(!last && count < s->samples);
+ s->samples_left -= count;
+ if(!s->samples_left){
if(crc != s->CRC){
av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
return -1;
@@ -609,6 +642,16 @@ static inline int wv_unpack_mono(WavpackContext *s, GetBitContext *gb, void *dst
av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
return -1;
}
+ wv_reset_saved_context(s);
+ }else{
+ s->pos = pos;
+ s->sc.crc = crc;
+ s->sc.bits_used = get_bits_count(&s->gb);
+ if(s->got_extra_bits){
+ s->extra_sc.crc = crc_extra_bits;
+ s->extra_sc.bits_used = get_bits_count(&s->gb_extra_bits);
+ }
+ }
return count;
}
@@ -624,6 +667,8 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx)
avctx->sample_fmt = SAMPLE_FMT_S32;
avctx->channel_layout = (avctx->channels==2) ? CH_LAYOUT_STEREO : CH_LAYOUT_MONO;
+ wv_reset_saved_context(s);
+
return 0;
}
@@ -647,11 +692,13 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
return 0;
}
+ if(!s->samples_left){
memset(s->decorr, 0, MAX_TERMS * sizeof(Decorr));
memset(s->ch, 0, sizeof(s->ch));
s->extra_bits = 0;
s->and = s->or = s->shift = 0;
s->got_extra_bits = 0;
+ }
s->samples = AV_RL32(buf); buf += 4;
if(!s->samples){
@@ -676,10 +723,11 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
s->post_shift = 8 * (bpp-1-(s->frame_flags&0x03)) + ((s->frame_flags >> 13) & 0x1f);
s->CRC = AV_RL32(buf); buf += 4;
- /* should not happen but who knows */
- if(s->samples * bpp * avctx->channels > *data_size){
- av_log(avctx, AV_LOG_ERROR, "Packet size is too big to be handled in lavc!\n");
- return -1;
+ s->max_samples = *data_size / (bpp * avctx->channels);
+ s->max_samples = FFMIN(s->max_samples, s->samples);
+ if(s->samples_left > 0){
+ s->max_samples = FFMIN(s->max_samples, s->samples_left);
+ buf = buf_end;
}
// parse metadata blocks
@@ -847,6 +895,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
got_float = 1;
break;
case WP_ID_DATA:
+ s->sc.offset = buf - avpkt->data;
+ s->sc.size = size * 8;
init_get_bits(&s->gb, buf, size * 8);
s->data_size = size * 8;
buf += size;
@@ -858,6 +908,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
buf += size;
continue;
}
+ s->extra_sc.offset = buf - avpkt->data;
+ s->extra_sc.size = size * 8;
init_get_bits(&s->gb_extra_bits, buf, size * 8);
s->crc_extra_bits = get_bits_long(&s->gb_extra_bits, 32);
buf += size;
@@ -868,6 +920,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
}
if(id & WP_IDF_ODD) buf++;
}
+ if(!s->samples_left){
if(!got_terms){
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation terms\n");
return -1;
@@ -904,6 +957,16 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
s->got_extra_bits = 0;
}
}
+ s->samples_left = s->samples;
+ }else{
+ init_get_bits(&s->gb, avpkt->data + s->sc.offset, s->sc.size);
+ skip_bits_long(&s->gb, s->sc.bits_used);
+ if(s->got_extra_bits){
+ init_get_bits(&s->gb_extra_bits, avpkt->data + s->extra_sc.offset,
+ s->extra_sc.size);
+ skip_bits_long(&s->gb_extra_bits, s->extra_sc.bits_used);
+ }
+ }
if(s->stereo_in){
if(avctx->sample_fmt == SAMPLE_FMT_S16)
@@ -952,7 +1015,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
}
*data_size = samplecount * bpp;
- return buf_size;
+ return s->samples_left > 0 ? 0 : buf_size;
}
AVCodec wavpack_decoder = {