Commit 965828bb authored by Kostya Shishkov's avatar Kostya Shishkov
Browse files

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
parent 245d5a48
......@@ -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 = {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment