[FFmpeg-cvslog] r21894 - trunk/libavcodec/wavpack.c

kostya subversion
Fri Feb 19 15:05:42 CET 2010


Author: kostya
Date: Fri Feb 19 15:05:41 2010
New Revision: 21894

Log:
Since WavPack chunk can contain more samples than FFmpeg is guaranteed to
hold, decode it in several iterations outputting as many samples as possible.

Modified:
   trunk/libavcodec/wavpack.c

Modified: trunk/libavcodec/wavpack.c
==============================================================================
--- trunk/libavcodec/wavpack.c	Fri Feb 19 09:26:35 2010	(r21893)
+++ trunk/libavcodec/wavpack.c	Fri Feb 19 15:05:41 2010	(r21894)
@@ -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(WavpackC
     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(Wavpa
             *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(Wavpa
         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(Wavpack
     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(Wavpack
         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(Wavpack
         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(A
         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(AVCodecC
         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(AVCodecC
     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(AVCodecC
             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(AVCodecC
                 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(AVCodecC
         }
         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(AVCodecC
             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(AVCodecC
     }
     *data_size = samplecount * bpp;
 
-    return buf_size;
+    return s->samples_left > 0 ? 0 : buf_size;
 }
 
 AVCodec wavpack_decoder = {



More information about the ffmpeg-cvslog mailing list