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
release/0.6
Kostya Shishkov 15 years ago
parent 245d5a48ef
commit 965828bb66
  1. 87
      libavcodec/wavpack.c

@ -67,6 +67,13 @@ enum WP_ID{
WP_ID_CHANINFO WP_ID_CHANINFO
}; };
typedef struct SavedContext {
int offset;
int size;
int bits_used;
uint32_t crc;
} SavedContext;
#define MAX_TERMS 16 #define MAX_TERMS 16
typedef struct Decorr { typedef struct Decorr {
@ -107,6 +114,10 @@ typedef struct WavpackContext {
int float_shift; int float_shift;
int float_max_exp; int float_max_exp;
WvChannel ch[2]; WvChannel ch[2];
int samples_left;
int max_samples;
int pos;
SavedContext sc, extra_sc;
} WavpackContext; } WavpackContext;
// exponent table copied from WavPack source // 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; 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) static inline int wv_unpack_stereo(WavpackContext *s, GetBitContext *gb, void *dst, const int type)
{ {
int i, j, count = 0; int i, j, count = 0;
int last, t; int last, t;
int A, B, L, L2, R, R2; int A, B, L, L2, R, R2;
int pos = 0; int pos = s->pos;
uint32_t crc = 0xFFFFFFFF; uint32_t crc = s->sc.crc;
uint32_t crc_extra_bits = 0xFFFFFFFF; uint32_t crc_extra_bits = s->extra_sc.crc;
int16_t *dst16 = dst; int16_t *dst16 = dst;
int32_t *dst32 = dst; int32_t *dst32 = dst;
float *dstfl = dst; float *dstfl = dst;
if(s->samples_left == s->samples)
s->one = s->zero = s->zeroes = 0; s->one = s->zero = s->zeroes = 0;
do{ do{
L = wv_get_value(s, gb, 0, &last); 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); *dst16++ = wv_get_value_integer(s, &crc_extra_bits, R);
} }
count++; count++;
}while(!last && count < s->samples); }while(!last && count < s->max_samples);
s->samples_left -= count;
if(!s->samples_left){
if(crc != s->CRC){ if(crc != s->CRC){
av_log(s->avctx, AV_LOG_ERROR, "CRC error\n"); av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
return -1; 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"); av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
return -1; 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; 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 i, j, count = 0;
int last, t; int last, t;
int A, S, T; int A, S, T;
int pos = 0; int pos = s->pos;
uint32_t crc = 0xFFFFFFFF; uint32_t crc = s->sc.crc;
uint32_t crc_extra_bits = 0xFFFFFFFF; uint32_t crc_extra_bits = s->extra_sc.crc;
int16_t *dst16 = dst; int16_t *dst16 = dst;
int32_t *dst32 = dst; int32_t *dst32 = dst;
float *dstfl = dst; float *dstfl = dst;
if(s->samples_left == s->samples)
s->one = s->zero = s->zeroes = 0; s->one = s->zero = s->zeroes = 0;
do{ do{
T = wv_get_value(s, gb, 0, &last); 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++; count++;
}while(!last && count < s->samples); }while(!last && count < s->samples);
s->samples_left -= count;
if(!s->samples_left){
if(crc != s->CRC){ if(crc != s->CRC){
av_log(s->avctx, AV_LOG_ERROR, "CRC error\n"); av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
return -1; 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"); av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
return -1; 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; return count;
} }
@ -624,6 +667,8 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx)
avctx->sample_fmt = SAMPLE_FMT_S32; avctx->sample_fmt = SAMPLE_FMT_S32;
avctx->channel_layout = (avctx->channels==2) ? CH_LAYOUT_STEREO : CH_LAYOUT_MONO; avctx->channel_layout = (avctx->channels==2) ? CH_LAYOUT_STEREO : CH_LAYOUT_MONO;
wv_reset_saved_context(s);
return 0; return 0;
} }
@ -647,11 +692,13 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
return 0; return 0;
} }
if(!s->samples_left){
memset(s->decorr, 0, MAX_TERMS * sizeof(Decorr)); memset(s->decorr, 0, MAX_TERMS * sizeof(Decorr));
memset(s->ch, 0, sizeof(s->ch)); memset(s->ch, 0, sizeof(s->ch));
s->extra_bits = 0; s->extra_bits = 0;
s->and = s->or = s->shift = 0; s->and = s->or = s->shift = 0;
s->got_extra_bits = 0; s->got_extra_bits = 0;
}
s->samples = AV_RL32(buf); buf += 4; s->samples = AV_RL32(buf); buf += 4;
if(!s->samples){ 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->post_shift = 8 * (bpp-1-(s->frame_flags&0x03)) + ((s->frame_flags >> 13) & 0x1f);
s->CRC = AV_RL32(buf); buf += 4; s->CRC = AV_RL32(buf); buf += 4;
/* should not happen but who knows */ s->max_samples = *data_size / (bpp * avctx->channels);
if(s->samples * bpp * avctx->channels > *data_size){ s->max_samples = FFMIN(s->max_samples, s->samples);
av_log(avctx, AV_LOG_ERROR, "Packet size is too big to be handled in lavc!\n"); if(s->samples_left > 0){
return -1; s->max_samples = FFMIN(s->max_samples, s->samples_left);
buf = buf_end;
} }
// parse metadata blocks // parse metadata blocks
@ -847,6 +895,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
got_float = 1; got_float = 1;
break; break;
case WP_ID_DATA: case WP_ID_DATA:
s->sc.offset = buf - avpkt->data;
s->sc.size = size * 8;
init_get_bits(&s->gb, buf, size * 8); init_get_bits(&s->gb, buf, size * 8);
s->data_size = size * 8; s->data_size = size * 8;
buf += size; buf += size;
@ -858,6 +908,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
buf += size; buf += size;
continue; continue;
} }
s->extra_sc.offset = buf - avpkt->data;
s->extra_sc.size = size * 8;
init_get_bits(&s->gb_extra_bits, buf, size * 8); init_get_bits(&s->gb_extra_bits, buf, size * 8);
s->crc_extra_bits = get_bits_long(&s->gb_extra_bits, 32); s->crc_extra_bits = get_bits_long(&s->gb_extra_bits, 32);
buf += size; buf += size;
@ -868,6 +920,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
} }
if(id & WP_IDF_ODD) buf++; if(id & WP_IDF_ODD) buf++;
} }
if(!s->samples_left){
if(!got_terms){ if(!got_terms){
av_log(avctx, AV_LOG_ERROR, "No block with decorrelation terms\n"); av_log(avctx, AV_LOG_ERROR, "No block with decorrelation terms\n");
return -1; return -1;
@ -904,6 +957,16 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
s->got_extra_bits = 0; 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(s->stereo_in){
if(avctx->sample_fmt == SAMPLE_FMT_S16) if(avctx->sample_fmt == SAMPLE_FMT_S16)
@ -952,7 +1015,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx,
} }
*data_size = samplecount * bpp; *data_size = samplecount * bpp;
return buf_size; return s->samples_left > 0 ? 0 : buf_size;
} }
AVCodec wavpack_decoder = { AVCodec wavpack_decoder = {

Loading…
Cancel
Save