Mercurial > libavcodec.hg
changeset 11211:dfeaae916502 libavcodec
Since WavPack chunk can contain more samples than FFmpeg is guaranteed to
hold, decode it in several iterations outputting as many samples as possible.
author | kostya |
---|---|
date | Fri, 19 Feb 2010 14:05:41 +0000 |
parents | 0c0c6c954942 |
children | 4a0b77af9d9c |
files | wavpack.c |
diffstat | 1 files changed, 75 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/wavpack.c Fri Feb 19 08:26:35 2010 +0000 +++ b/wavpack.c Fri Feb 19 14:05:41 2010 +0000 @@ -67,6 +67,13 @@ 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 @@ 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 @@ 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 @@ *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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } *data_size = samplecount * bpp; - return buf_size; + return s->samples_left > 0 ? 0 : buf_size; } AVCodec wavpack_decoder = {