Browse code

wavpack demuxer: export full wavpack blocks.

Currently the demuxer shaves the blocks and exports only the
information that is useful to the decoder.

Exporting the blocks just as they are stored is simpler to understand
and will make remuxing wavpack easier.

Anton Khirnov authored on 2013/05/27 04:09:22
Showing 2 changed files
... ...
@@ -33,6 +33,8 @@
33 33
  * WavPack lossless audio decoder
34 34
  */
35 35
 
36
+#define WV_HEADER_SIZE    32
37
+
36 38
 #define WV_MONO           0x00000004
37 39
 #define WV_JOINT_STEREO   0x00000010
38 40
 #define WV_FALSE_STEREO   0x40000000
... ...
@@ -1145,7 +1147,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
1145 1145
     AVFrame *frame     = data;
1146 1146
     int frame_size, ret, frame_flags;
1147 1147
 
1148
-    if (avpkt->size < 12 + s->multichannel * 4)
1148
+    if (avpkt->size <= WV_HEADER_SIZE)
1149 1149
         return AVERROR_INVALIDDATA;
1150 1150
 
1151 1151
     s->block     = 0;
... ...
@@ -1157,13 +1159,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
1157 1157
         buf        += 4;
1158 1158
         frame_flags = AV_RL32(buf);
1159 1159
     } else {
1160
-        if (s->multichannel) {
1161
-            s->samples  = AV_RL32(buf + 4);
1162
-            frame_flags = AV_RL32(buf + 8);
1163
-        } else {
1164
-            s->samples  = AV_RL32(buf);
1165
-            frame_flags = AV_RL32(buf + 4);
1166
-        }
1160
+        s->samples  = AV_RL32(buf + 20);
1161
+        frame_flags = AV_RL32(buf + 24);
1167 1162
     }
1168 1163
     if (s->samples <= 0) {
1169 1164
         av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
... ...
@@ -1188,18 +1185,16 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
1188 1188
     }
1189 1189
 
1190 1190
     while (buf_size > 0) {
1191
-        if (!s->multichannel) {
1192
-            frame_size = buf_size;
1191
+        if (!s->mkv_mode) {
1192
+            if (buf_size <= WV_HEADER_SIZE)
1193
+                break;
1194
+            frame_size = AV_RL32(buf + 4) - 12;
1195
+            buf       += 20;
1196
+            buf_size  -= 20;
1193 1197
         } else {
1194
-            if (!s->mkv_mode) {
1195
-                frame_size = AV_RL32(buf) - 12;
1196
-                buf       += 4;
1197
-                buf_size  -= 4;
1198
-            } else {
1199
-                if (buf_size < 12) // MKV files can have zero flags after last block
1200
-                    break;
1201
-                frame_size = AV_RL32(buf + 8) + 12;
1202
-            }
1198
+            if (buf_size < 12) // MKV files can have zero flags after last block
1199
+                break;
1200
+            frame_size = AV_RL32(buf + 8) + 12;
1203 1201
         }
1204 1202
         if (frame_size <= 0 || frame_size > buf_size) {
1205 1203
             av_log(avctx, AV_LOG_ERROR,
... ...
@@ -30,7 +30,7 @@
30 30
 // specs say that maximum block size is 1Mb
31 31
 #define WV_BLOCK_LIMIT 1047576
32 32
 
33
-#define WV_EXTRA_SIZE 12
33
+#define WV_HEADER_SIZE 32
34 34
 
35 35
 #define WV_START_BLOCK  0x0800
36 36
 #define WV_END_BLOCK    0x1000
... ...
@@ -56,13 +56,13 @@ static const int wv_rates[16] = {
56 56
 };
57 57
 
58 58
 typedef struct {
59
+    uint8_t block_header[WV_HEADER_SIZE];
59 60
     uint32_t blksize, flags;
60 61
     int rate, chan, bpp;
61 62
     uint32_t chmask;
62 63
     uint32_t samples, soff;
63 64
     int multichannel;
64 65
     int block_parsed;
65
-    uint8_t extra[WV_EXTRA_SIZE];
66 66
     int64_t pos;
67 67
 
68 68
     int64_t apetag_start;
... ...
@@ -80,12 +80,11 @@ static int wv_probe(AVProbeData *p)
80 80
         return 0;
81 81
 }
82 82
 
83
-static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb,
84
-                                int append)
83
+static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb)
85 84
 {
86 85
     WVContext *wc = ctx->priv_data;
87
-    uint32_t tag, ver;
88
-    int size;
86
+    uint32_t ver;
87
+    int size, ret;
89 88
     int rate, bpp, chan;
90 89
     uint32_t chmask;
91 90
 
... ...
@@ -95,33 +94,30 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb,
95 95
     if (wc->apetag_start && wc->pos >= wc->apetag_start)
96 96
         return AVERROR_EOF;
97 97
 
98
-    if (!append) {
99
-        tag = avio_rl32(pb);
100
-        if (tag != MKTAG('w', 'v', 'p', 'k'))
101
-            return AVERROR_INVALIDDATA;
102
-        size = avio_rl32(pb);
103
-        if (size < 24 || size > WV_BLOCK_LIMIT) {
104
-            av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size);
105
-            return AVERROR_INVALIDDATA;
106
-        }
107
-        wc->blksize = size;
108
-        ver = avio_rl16(pb);
109
-        if (ver < 0x402 || ver > 0x410) {
110
-            av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
111
-            return AVERROR_PATCHWELCOME;
112
-        }
113
-        avio_r8(pb); // track no
114
-        avio_r8(pb); // track sub index
115
-        wc->samples = avio_rl32(pb); // total samples in file
116
-        wc->soff    = avio_rl32(pb); // offset in samples of current block
117
-        avio_read(pb, wc->extra, WV_EXTRA_SIZE);
118
-    } else {
119
-        size = wc->blksize;
98
+    ret = avio_read(pb, wc->block_header, WV_HEADER_SIZE);
99
+    if (ret != WV_HEADER_SIZE)
100
+        return (ret < 0) ? ret : AVERROR_EOF;
101
+
102
+    if (AV_RL32(wc->block_header) != MKTAG('w', 'v', 'p', 'k'))
103
+        return AVERROR_INVALIDDATA;
104
+
105
+    size = AV_RL32(wc->block_header + 4);
106
+    if (size < 24 || size > WV_BLOCK_LIMIT) {
107
+        av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size);
108
+        return AVERROR_INVALIDDATA;
109
+    }
110
+    wc->blksize = size;
111
+    ver = AV_RL32(wc->block_header + 8);
112
+    if (ver < 0x402 || ver > 0x410) {
113
+        av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
114
+        return AVERROR_PATCHWELCOME;
120 115
     }
121
-    wc->flags = AV_RL32(wc->extra + 4);
116
+    wc->samples = AV_RL32(wc->block_header + 12); // total samples in file
117
+    wc->soff    = AV_RL32(wc->block_header + 16); // offset in samples of current block
118
+    wc->flags   = AV_RL32(wc->block_header + 24);
122 119
     /* Blocks with zero samples don't contain actual audio information
123 120
      * and should be ignored */
124
-    if (!AV_RN32(wc->extra))
121
+    if (!AV_RN32(wc->block_header + 20))
125 122
         return 0;
126 123
     // parse flags
127 124
     bpp    = ((wc->flags & 3) + 1) << 3;
... ...
@@ -235,9 +231,9 @@ static int wv_read_header(AVFormatContext *s)
235 235
 
236 236
     wc->block_parsed = 0;
237 237
     for (;;) {
238
-        if ((ret = wv_read_block_header(s, pb, 0)) < 0)
238
+        if ((ret = wv_read_block_header(s, pb)) < 0)
239 239
             return ret;
240
-        if (!AV_RN32(wc->extra))
240
+        if (!AV_RL32(wc->block_header + 20))
241 241
             avio_skip(pb, wc->blksize - 24);
242 242
         else
243 243
             break;
... ...
@@ -272,75 +268,49 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt)
272 272
 {
273 273
     WVContext *wc = s->priv_data;
274 274
     int ret;
275
-    int size, ver, off;
275
+    int off;
276 276
     int64_t pos;
277 277
     uint32_t block_samples;
278 278
 
279 279
     if (s->pb->eof_reached)
280 280
         return AVERROR_EOF;
281 281
     if (wc->block_parsed) {
282
-        if ((ret = wv_read_block_header(s, s->pb, 0)) < 0)
282
+        if ((ret = wv_read_block_header(s, s->pb)) < 0)
283 283
             return ret;
284 284
     }
285 285
 
286 286
     pos = wc->pos;
287
-    off = wc->multichannel ? 4 : 0;
288
-    if (av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE + off) < 0)
287
+    if (av_new_packet(pkt, wc->blksize + WV_HEADER_SIZE) < 0)
289 288
         return AVERROR(ENOMEM);
290
-    if (wc->multichannel)
291
-        AV_WL32(pkt->data, wc->blksize + WV_EXTRA_SIZE + 12);
292
-    memcpy(pkt->data + off, wc->extra, WV_EXTRA_SIZE);
293
-    ret = avio_read(s->pb, pkt->data + WV_EXTRA_SIZE + off, wc->blksize);
289
+    memcpy(pkt->data, wc->block_header, WV_HEADER_SIZE);
290
+    ret = avio_read(s->pb, pkt->data + WV_HEADER_SIZE, wc->blksize);
294 291
     if (ret != wc->blksize) {
295 292
         av_free_packet(pkt);
296 293
         return AVERROR(EIO);
297 294
     }
298 295
     while (!(wc->flags & WV_END_BLOCK)) {
299
-        if (avio_rl32(s->pb) != MKTAG('w', 'v', 'p', 'k')) {
300
-            av_free_packet(pkt);
301
-            return AVERROR_INVALIDDATA;
302
-        }
303
-        if ((ret = av_append_packet(s->pb, pkt, 4)) < 0) {
296
+        if ((ret = wv_read_block_header(s, s->pb)) < 0) {
304 297
             av_free_packet(pkt);
305 298
             return ret;
306 299
         }
307
-        size = AV_RL32(pkt->data + pkt->size - 4);
308
-        if (size < 24 || size > WV_BLOCK_LIMIT) {
309
-            av_free_packet(pkt);
310
-            av_log(s, AV_LOG_ERROR, "Incorrect block size %d\n", size);
311
-            return AVERROR_INVALIDDATA;
312
-        }
313
-        wc->blksize = size;
314
-        ver         = avio_rl16(s->pb);
315
-        if (ver < 0x402 || ver > 0x410) {
316
-            av_free_packet(pkt);
317
-            av_log(s, AV_LOG_ERROR, "Unsupported version %03X\n", ver);
318
-            return AVERROR_PATCHWELCOME;
319
-        }
320
-        avio_r8(s->pb); // track no
321
-        avio_r8(s->pb); // track sub index
322
-        wc->samples = avio_rl32(s->pb); // total samples in file
323
-        wc->soff    = avio_rl32(s->pb); // offset in samples of current block
324
-        if ((ret = av_append_packet(s->pb, pkt, WV_EXTRA_SIZE)) < 0) {
325
-            av_free_packet(pkt);
326
-            return ret;
327
-        }
328
-        memcpy(wc->extra, pkt->data + pkt->size - WV_EXTRA_SIZE, WV_EXTRA_SIZE);
329 300
 
330
-        if ((ret = wv_read_block_header(s, s->pb, 1)) < 0) {
301
+        off = pkt->size;
302
+        if ((ret = av_grow_packet(pkt, WV_HEADER_SIZE + wc->blksize)) < 0) {
331 303
             av_free_packet(pkt);
332 304
             return ret;
333 305
         }
334
-        ret = av_append_packet(s->pb, pkt, wc->blksize);
335
-        if (ret < 0) {
306
+        memcpy(pkt->data + off, wc->block_header, WV_HEADER_SIZE);
307
+
308
+        ret = avio_read(s->pb, pkt->data + off + WV_HEADER_SIZE, wc->blksize);
309
+        if (ret != wc->blksize) {
336 310
             av_free_packet(pkt);
337
-            return ret;
311
+            return (ret < 0) ? ret : AVERROR_EOF;
338 312
         }
339 313
     }
340 314
     pkt->stream_index = 0;
341 315
     wc->block_parsed  = 1;
342 316
     pkt->pts          = wc->soff;
343
-    block_samples     = AV_RN32(wc->extra);
317
+    block_samples     = AV_RL32(wc->block_header + 20);
344 318
     if (block_samples > INT32_MAX)
345 319
         av_log(s, AV_LOG_WARNING,
346 320
                "Too many samples in block: %"PRIu32"\n", block_samples);