summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 = {