It will be reused by other muxers and demuxers.
Anton Khirnov authored on 2013/05/28 16:33:43... | ... |
@@ -334,7 +334,7 @@ OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o |
334 | 334 |
OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o |
335 | 335 |
OBJS-$(CONFIG_WTV_DEMUXER) += wtv.o asfdec.o asf.o asfcrypt.o \ |
336 | 336 |
avlanguage.o mpegts.o isom.o |
337 |
-OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o apetag.o img2.o |
|
337 |
+OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o wv.o apetag.o img2.o |
|
338 | 338 |
OBJS-$(CONFIG_XA_DEMUXER) += xa.o |
339 | 339 |
OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o |
340 | 340 |
OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o |
341 | 341 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,52 @@ |
0 |
+/* |
|
1 |
+ * WavPack shared functions |
|
2 |
+ * |
|
3 |
+ * This file is part of Libav. |
|
4 |
+ * |
|
5 |
+ * Libav is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * Libav is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with Libav; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include <stdint.h> |
|
21 |
+#include <string.h> |
|
22 |
+ |
|
23 |
+#include "libavutil/common.h" |
|
24 |
+#include "libavutil/intreadwrite.h" |
|
25 |
+ |
|
26 |
+#include "wv.h" |
|
27 |
+ |
|
28 |
+int ff_wv_parse_header(WvHeader *wv, const uint8_t *data) |
|
29 |
+{ |
|
30 |
+ memset(wv, 0, sizeof(*wv)); |
|
31 |
+ |
|
32 |
+ if (AV_RL32(data) != MKTAG('w', 'v', 'p', 'k')) |
|
33 |
+ return AVERROR_INVALIDDATA; |
|
34 |
+ |
|
35 |
+ wv->blocksize = AV_RL32(data + 4); |
|
36 |
+ if (wv->blocksize < 24 || wv->blocksize > WV_BLOCK_LIMIT) |
|
37 |
+ return AVERROR_INVALIDDATA; |
|
38 |
+ wv->blocksize -= 24; |
|
39 |
+ |
|
40 |
+ wv->version = AV_RL16(data + 8); |
|
41 |
+ wv->total_samples = AV_RL32(data + 12); |
|
42 |
+ wv->block_idx = AV_RL32(data + 16); |
|
43 |
+ wv->samples = AV_RL32(data + 20); |
|
44 |
+ wv->flags = AV_RL32(data + 24); |
|
45 |
+ wv->crc = AV_RL32(data + 28); |
|
46 |
+ |
|
47 |
+ wv->initial = !!(wv->flags & WV_FLAG_INITIAL_BLOCK); |
|
48 |
+ wv->final = !!(wv->flags & WV_FLAG_FINAL_BLOCK); |
|
49 |
+ |
|
50 |
+ return 0; |
|
51 |
+} |
0 | 52 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,56 @@ |
0 |
+/* |
|
1 |
+ * WavPack shared functions |
|
2 |
+ * |
|
3 |
+ * This file is part of Libav. |
|
4 |
+ * |
|
5 |
+ * Libav is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * Libav is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with Libav; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef AVFORMAT_WV_H |
|
21 |
+#define AVFORMAT_WV_H |
|
22 |
+ |
|
23 |
+#include <stdint.h> |
|
24 |
+ |
|
25 |
+#define WV_HEADER_SIZE 32 |
|
26 |
+ |
|
27 |
+#define WV_FLAG_INITIAL_BLOCK (1 << 11) |
|
28 |
+#define WV_FLAG_FINAL_BLOCK (1 << 12) |
|
29 |
+ |
|
30 |
+// specs say that maximum block size is 1Mb |
|
31 |
+#define WV_BLOCK_LIMIT 1048576 |
|
32 |
+ |
|
33 |
+typedef struct WvHeader { |
|
34 |
+ uint32_t blocksize; //< size of the block data (excluding the header) |
|
35 |
+ uint16_t version; //< bitstream version |
|
36 |
+ uint32_t total_samples; //< total number of samples in the stream |
|
37 |
+ uint32_t block_idx; //< index of the first sample in this block |
|
38 |
+ uint32_t samples; //< number of samples in this block |
|
39 |
+ uint32_t flags; |
|
40 |
+ uint32_t crc; |
|
41 |
+ |
|
42 |
+ int initial, final; |
|
43 |
+} WvHeader; |
|
44 |
+ |
|
45 |
+/** |
|
46 |
+ * Parse a WavPack block header. |
|
47 |
+ * |
|
48 |
+ * @param wv this struct will be filled with parse header information |
|
49 |
+ * @param data header data, must be WV_HEADER_SIZE bytes long |
|
50 |
+ * |
|
51 |
+ * @return 0 on success, a negative AVERROR code on failure |
|
52 |
+ */ |
|
53 |
+int ff_wv_parse_header(WvHeader *wv, const uint8_t *data); |
|
54 |
+ |
|
55 |
+#endif /* AVFORMAT_WV_H */ |
... | ... |
@@ -26,15 +26,7 @@ |
26 | 26 |
#include "internal.h" |
27 | 27 |
#include "apetag.h" |
28 | 28 |
#include "id3v1.h" |
29 |
- |
|
30 |
-// specs say that maximum block size is 1Mb |
|
31 |
-#define WV_BLOCK_LIMIT 1047576 |
|
32 |
- |
|
33 |
-#define WV_HEADER_SIZE 32 |
|
34 |
- |
|
35 |
-#define WV_START_BLOCK 0x0800 |
|
36 |
-#define WV_END_BLOCK 0x1000 |
|
37 |
-#define WV_SINGLE_BLOCK (WV_START_BLOCK | WV_END_BLOCK) |
|
29 |
+#include "wv.h" |
|
38 | 30 |
|
39 | 31 |
enum WV_FLAGS { |
40 | 32 |
WV_MONO = 0x0004, |
... | ... |
@@ -57,10 +49,9 @@ static const int wv_rates[16] = { |
57 | 57 |
|
58 | 58 |
typedef struct { |
59 | 59 |
uint8_t block_header[WV_HEADER_SIZE]; |
60 |
- uint32_t blksize, flags; |
|
60 |
+ WvHeader header; |
|
61 | 61 |
int rate, chan, bpp; |
62 | 62 |
uint32_t chmask; |
63 |
- uint32_t samples, soff; |
|
64 | 63 |
int multichannel; |
65 | 64 |
int block_parsed; |
66 | 65 |
int64_t pos; |
... | ... |
@@ -83,10 +74,9 @@ static int wv_probe(AVProbeData *p) |
83 | 83 |
static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) |
84 | 84 |
{ |
85 | 85 |
WVContext *wc = ctx->priv_data; |
86 |
- uint32_t ver; |
|
87 |
- int size, ret; |
|
86 |
+ int ret; |
|
88 | 87 |
int rate, bpp, chan; |
89 |
- uint32_t chmask; |
|
88 |
+ uint32_t chmask, flags; |
|
90 | 89 |
|
91 | 90 |
wc->pos = avio_tell(pb); |
92 | 91 |
|
... | ... |
@@ -98,39 +88,34 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) |
98 | 98 |
if (ret != WV_HEADER_SIZE) |
99 | 99 |
return (ret < 0) ? ret : AVERROR_EOF; |
100 | 100 |
|
101 |
- if (AV_RL32(wc->block_header) != MKTAG('w', 'v', 'p', 'k')) |
|
102 |
- return AVERROR_INVALIDDATA; |
|
103 |
- |
|
104 |
- size = AV_RL32(wc->block_header + 4); |
|
105 |
- if (size < 24 || size > WV_BLOCK_LIMIT) { |
|
106 |
- av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size); |
|
107 |
- return AVERROR_INVALIDDATA; |
|
101 |
+ ret = ff_wv_parse_header(&wc->header, wc->block_header); |
|
102 |
+ if (ret < 0) { |
|
103 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid block header.\n"); |
|
104 |
+ return ret; |
|
108 | 105 |
} |
109 |
- wc->blksize = size; |
|
110 |
- ver = AV_RL32(wc->block_header + 8); |
|
111 |
- if (ver < 0x402 || ver > 0x410) { |
|
112 |
- av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); |
|
106 |
+ |
|
107 |
+ if (wc->header.version < 0x402 || wc->header.version > 0x410) { |
|
108 |
+ av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", wc->header.version); |
|
113 | 109 |
return AVERROR_PATCHWELCOME; |
114 | 110 |
} |
115 |
- wc->samples = AV_RL32(wc->block_header + 12); // total samples in file |
|
116 |
- wc->soff = AV_RL32(wc->block_header + 16); // offset in samples of current block |
|
117 |
- wc->flags = AV_RL32(wc->block_header + 24); |
|
111 |
+ |
|
118 | 112 |
/* Blocks with zero samples don't contain actual audio information |
119 | 113 |
* and should be ignored */ |
120 |
- if (!AV_RN32(wc->block_header + 20)) |
|
114 |
+ if (!wc->header.samples) |
|
121 | 115 |
return 0; |
122 | 116 |
// parse flags |
123 |
- bpp = ((wc->flags & 3) + 1) << 3; |
|
124 |
- chan = 1 + !(wc->flags & WV_MONO); |
|
125 |
- chmask = wc->flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; |
|
126 |
- rate = wv_rates[(wc->flags >> 23) & 0xF]; |
|
127 |
- wc->multichannel = !!((wc->flags & WV_SINGLE_BLOCK) != WV_SINGLE_BLOCK); |
|
117 |
+ flags = wc->header.flags; |
|
118 |
+ bpp = ((flags & 3) + 1) << 3; |
|
119 |
+ chan = 1 + !(flags & WV_MONO); |
|
120 |
+ chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; |
|
121 |
+ rate = wv_rates[(flags >> 23) & 0xF]; |
|
122 |
+ wc->multichannel = !(wc->header.initial && wc->header.final); |
|
128 | 123 |
if (wc->multichannel) { |
129 | 124 |
chan = wc->chan; |
130 | 125 |
chmask = wc->chmask; |
131 | 126 |
} |
132 | 127 |
if ((rate == -1 || !chan) && !wc->block_parsed) { |
133 |
- int64_t block_end = avio_tell(pb) + wc->blksize - 24; |
|
128 |
+ int64_t block_end = avio_tell(pb) + wc->header.blocksize; |
|
134 | 129 |
if (!pb->seekable) { |
135 | 130 |
av_log(ctx, AV_LOG_ERROR, |
136 | 131 |
"Cannot determine additional parameters\n"); |
... | ... |
@@ -189,7 +174,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) |
189 | 189 |
"Cannot determine custom sampling rate\n"); |
190 | 190 |
return AVERROR_INVALIDDATA; |
191 | 191 |
} |
192 |
- avio_seek(pb, block_end - wc->blksize + 24, SEEK_SET); |
|
192 |
+ avio_seek(pb, block_end - wc->header.blocksize, SEEK_SET); |
|
193 | 193 |
} |
194 | 194 |
if (!wc->bpp) |
195 | 195 |
wc->bpp = bpp; |
... | ... |
@@ -200,25 +185,24 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) |
200 | 200 |
if (!wc->rate) |
201 | 201 |
wc->rate = rate; |
202 | 202 |
|
203 |
- if (wc->flags && bpp != wc->bpp) { |
|
203 |
+ if (flags && bpp != wc->bpp) { |
|
204 | 204 |
av_log(ctx, AV_LOG_ERROR, |
205 | 205 |
"Bits per sample differ, this block: %i, header block: %i\n", |
206 | 206 |
bpp, wc->bpp); |
207 | 207 |
return AVERROR_INVALIDDATA; |
208 | 208 |
} |
209 |
- if (wc->flags && !wc->multichannel && chan != wc->chan) { |
|
209 |
+ if (flags && !wc->multichannel && chan != wc->chan) { |
|
210 | 210 |
av_log(ctx, AV_LOG_ERROR, |
211 | 211 |
"Channels differ, this block: %i, header block: %i\n", |
212 | 212 |
chan, wc->chan); |
213 | 213 |
return AVERROR_INVALIDDATA; |
214 | 214 |
} |
215 |
- if (wc->flags && rate != -1 && rate != wc->rate) { |
|
215 |
+ if (flags && rate != -1 && rate != wc->rate) { |
|
216 | 216 |
av_log(ctx, AV_LOG_ERROR, |
217 | 217 |
"Sampling rate differ, this block: %i, header block: %i\n", |
218 | 218 |
rate, wc->rate); |
219 | 219 |
return AVERROR_INVALIDDATA; |
220 | 220 |
} |
221 |
- wc->blksize = size - 24; |
|
222 | 221 |
return 0; |
223 | 222 |
} |
224 | 223 |
|
... | ... |
@@ -233,8 +217,8 @@ static int wv_read_header(AVFormatContext *s) |
233 | 233 |
for (;;) { |
234 | 234 |
if ((ret = wv_read_block_header(s, pb)) < 0) |
235 | 235 |
return ret; |
236 |
- if (!AV_RL32(wc->block_header + 20)) |
|
237 |
- avio_skip(pb, wc->blksize - 24); |
|
236 |
+ if (!wc->header.samples) |
|
237 |
+ avio_skip(pb, wc->header.blocksize); |
|
238 | 238 |
else |
239 | 239 |
break; |
240 | 240 |
} |
... | ... |
@@ -251,7 +235,7 @@ static int wv_read_header(AVFormatContext *s) |
251 | 251 |
st->codec->bits_per_coded_sample = wc->bpp; |
252 | 252 |
avpriv_set_pts_info(st, 64, 1, wc->rate); |
253 | 253 |
st->start_time = 0; |
254 |
- st->duration = wc->samples; |
|
254 |
+ st->duration = wc->header.total_samples; |
|
255 | 255 |
|
256 | 256 |
if (s->pb->seekable) { |
257 | 257 |
int64_t cur = avio_tell(s->pb); |
... | ... |
@@ -280,37 +264,37 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt) |
280 | 280 |
} |
281 | 281 |
|
282 | 282 |
pos = wc->pos; |
283 |
- if (av_new_packet(pkt, wc->blksize + WV_HEADER_SIZE) < 0) |
|
283 |
+ if (av_new_packet(pkt, wc->header.blocksize + WV_HEADER_SIZE) < 0) |
|
284 | 284 |
return AVERROR(ENOMEM); |
285 | 285 |
memcpy(pkt->data, wc->block_header, WV_HEADER_SIZE); |
286 |
- ret = avio_read(s->pb, pkt->data + WV_HEADER_SIZE, wc->blksize); |
|
287 |
- if (ret != wc->blksize) { |
|
286 |
+ ret = avio_read(s->pb, pkt->data + WV_HEADER_SIZE, wc->header.blocksize); |
|
287 |
+ if (ret != wc->header.blocksize) { |
|
288 | 288 |
av_free_packet(pkt); |
289 | 289 |
return AVERROR(EIO); |
290 | 290 |
} |
291 |
- while (!(wc->flags & WV_END_BLOCK)) { |
|
291 |
+ while (!(wc->header.flags & WV_FLAG_FINAL_BLOCK)) { |
|
292 | 292 |
if ((ret = wv_read_block_header(s, s->pb)) < 0) { |
293 | 293 |
av_free_packet(pkt); |
294 | 294 |
return ret; |
295 | 295 |
} |
296 | 296 |
|
297 | 297 |
off = pkt->size; |
298 |
- if ((ret = av_grow_packet(pkt, WV_HEADER_SIZE + wc->blksize)) < 0) { |
|
298 |
+ if ((ret = av_grow_packet(pkt, WV_HEADER_SIZE + wc->header.blocksize)) < 0) { |
|
299 | 299 |
av_free_packet(pkt); |
300 | 300 |
return ret; |
301 | 301 |
} |
302 | 302 |
memcpy(pkt->data + off, wc->block_header, WV_HEADER_SIZE); |
303 | 303 |
|
304 |
- ret = avio_read(s->pb, pkt->data + off + WV_HEADER_SIZE, wc->blksize); |
|
305 |
- if (ret != wc->blksize) { |
|
304 |
+ ret = avio_read(s->pb, pkt->data + off + WV_HEADER_SIZE, wc->header.blocksize); |
|
305 |
+ if (ret != wc->header.blocksize) { |
|
306 | 306 |
av_free_packet(pkt); |
307 | 307 |
return (ret < 0) ? ret : AVERROR_EOF; |
308 | 308 |
} |
309 | 309 |
} |
310 | 310 |
pkt->stream_index = 0; |
311 | 311 |
wc->block_parsed = 1; |
312 |
- pkt->pts = wc->soff; |
|
313 |
- block_samples = AV_RL32(wc->block_header + 20); |
|
312 |
+ pkt->pts = wc->header.block_idx; |
|
313 |
+ block_samples = wc->header.samples; |
|
314 | 314 |
if (block_samples > INT32_MAX) |
315 | 315 |
av_log(s, AV_LOG_WARNING, |
316 | 316 |
"Too many samples in block: %"PRIu32"\n", block_samples); |