Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
wv.c
Go to the documentation of this file.
1
/*
2
* WavPack demuxer
3
* Copyright (c) 2006,2011 Konstantin Shishkov
4
*
5
* This file is part of Libav.
6
*
7
* Libav is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* Libav is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with Libav; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
#include "
libavutil/channel_layout.h
"
23
#include "
libavutil/intreadwrite.h
"
24
#include "
libavutil/dict.h
"
25
#include "
avformat.h
"
26
#include "
internal.h
"
27
#include "
apetag.h
"
28
#include "
id3v1.h
"
29
30
// specs say that maximum block size is 1Mb
31
#define WV_BLOCK_LIMIT 1047576
32
33
#define WV_EXTRA_SIZE 12
34
35
#define WV_START_BLOCK 0x0800
36
#define WV_END_BLOCK 0x1000
37
#define WV_SINGLE_BLOCK (WV_START_BLOCK | WV_END_BLOCK)
38
39
enum
WV_FLAGS
{
40
WV_MONO
= 0x0004,
41
WV_HYBRID
= 0x0008,
42
WV_JOINT
= 0x0010,
43
WV_CROSSD
= 0x0020,
44
WV_HSHAPE
= 0x0040,
45
WV_FLOAT
= 0x0080,
46
WV_INT32
= 0x0100,
47
WV_HBR
= 0x0200,
48
WV_HBAL
= 0x0400,
49
WV_MCINIT
= 0x0800,
50
WV_MCEND
= 0x1000,
51
};
52
53
static
const
int
wv_rates
[16] = {
54
6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
55
32000, 44100, 48000, 64000, 88200, 96000, 192000, -1
56
};
57
58
typedef
struct
{
59
uint32_t blksize,
flags
;
60
int
rate
, chan, bpp;
61
uint32_t
chmask
;
62
uint32_t
samples
,
soff
;
63
int
multichannel
;
64
int
block_parsed
;
65
uint8_t
extra[
WV_EXTRA_SIZE
];
66
int64_t
pos
;
67
68
int64_t
apetag_start
;
69
}
WVContext
;
70
71
static
int
wv_probe
(
AVProbeData
*p)
72
{
73
/* check file header */
74
if
(p->
buf_size
<= 32)
75
return
0;
76
if
(p->
buf
[0] ==
'w'
&& p->
buf
[1] ==
'v'
&&
77
p->
buf
[2] ==
'p'
&& p->
buf
[3] ==
'k'
)
78
return
AVPROBE_SCORE_MAX
;
79
else
80
return
0;
81
}
82
83
static
int
wv_read_block_header
(
AVFormatContext
*ctx,
AVIOContext
*pb,
84
int
append
)
85
{
86
WVContext
*wc = ctx->
priv_data
;
87
uint32_t
tag
, ver;
88
int
size
;
89
int
rate, bpp, chan;
90
uint32_t chmask;
91
92
wc->
pos
=
avio_tell
(pb);
93
94
/* don't return bogus packets with the ape tag data */
95
if
(wc->
apetag_start
&& wc->
pos
>= wc->
apetag_start
)
96
return
AVERROR_EOF
;
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
;
120
}
121
wc->
flags
=
AV_RL32
(wc->
extra
+ 4);
122
/* Blocks with zero samples don't contain actual audio information
123
* and should be ignored */
124
if
(!
AV_RN32
(wc->
extra
))
125
return
0;
126
// parse flags
127
bpp = ((wc->
flags
& 3) + 1) << 3;
128
chan = 1 + !(wc->
flags
&
WV_MONO
);
129
chmask = wc->
flags
&
WV_MONO
?
AV_CH_LAYOUT_MONO
:
AV_CH_LAYOUT_STEREO
;
130
rate =
wv_rates
[(wc->
flags
>> 23) & 0xF];
131
wc->
multichannel
= !!((wc->
flags
&
WV_SINGLE_BLOCK
) !=
WV_SINGLE_BLOCK
);
132
if
(wc->
multichannel
) {
133
chan = wc->
chan
;
134
chmask = wc->
chmask
;
135
}
136
if
((rate == -1 || !chan) && !wc->
block_parsed
) {
137
int64_t block_end =
avio_tell
(pb) + wc->
blksize
- 24;
138
if
(!pb->
seekable
) {
139
av_log
(ctx,
AV_LOG_ERROR
,
140
"Cannot determine additional parameters\n"
);
141
return
AVERROR_INVALIDDATA
;
142
}
143
while
(
avio_tell
(pb) < block_end) {
144
int
id
,
size
;
145
id
=
avio_r8
(pb);
146
size = (
id
& 0x80) ?
avio_rl24
(pb) :
avio_r8
(pb);
147
size <<= 1;
148
if
(
id
& 0x40)
149
size--;
150
switch
(
id
& 0x3F) {
151
case
0xD:
152
if
(size <= 1) {
153
av_log
(ctx,
AV_LOG_ERROR
,
154
"Insufficient channel information\n"
);
155
return
AVERROR_INVALIDDATA
;
156
}
157
chan =
avio_r8
(pb);
158
switch
(size - 2) {
159
case
0:
160
chmask =
avio_r8
(pb);
161
break
;
162
case
1:
163
chmask =
avio_rl16
(pb);
164
break
;
165
case
2:
166
chmask =
avio_rl24
(pb);
167
break
;
168
case
3:
169
chmask =
avio_rl32
(pb);
170
break
;
171
case
5:
172
avio_skip
(pb, 1);
173
chan |= (
avio_r8
(pb) & 0xF) << 8;
174
chmask =
avio_rl24
(pb);
175
break
;
176
default
:
177
av_log
(ctx,
AV_LOG_ERROR
,
178
"Invalid channel info size %d\n"
, size);
179
return
AVERROR_INVALIDDATA
;
180
}
181
break
;
182
case
0x27:
183
rate =
avio_rl24
(pb);
184
break
;
185
default
:
186
avio_skip
(pb, size);
187
}
188
if
(
id
& 0x40)
189
avio_skip
(pb, 1);
190
}
191
if
(rate == -1) {
192
av_log
(ctx,
AV_LOG_ERROR
,
193
"Cannot determine custom sampling rate\n"
);
194
return
AVERROR_INVALIDDATA
;
195
}
196
avio_seek
(pb, block_end - wc->
blksize
+ 24, SEEK_SET);
197
}
198
if
(!wc->
bpp
)
199
wc->
bpp
= bpp;
200
if
(!wc->
chan
)
201
wc->
chan
= chan;
202
if
(!wc->
chmask
)
203
wc->
chmask
= chmask;
204
if
(!wc->
rate
)
205
wc->
rate
= rate;
206
207
if
(wc->
flags
&& bpp != wc->
bpp
) {
208
av_log
(ctx,
AV_LOG_ERROR
,
209
"Bits per sample differ, this block: %i, header block: %i\n"
,
210
bpp, wc->
bpp
);
211
return
AVERROR_INVALIDDATA
;
212
}
213
if
(wc->
flags
&& !wc->
multichannel
&& chan != wc->
chan
) {
214
av_log
(ctx,
AV_LOG_ERROR
,
215
"Channels differ, this block: %i, header block: %i\n"
,
216
chan, wc->
chan
);
217
return
AVERROR_INVALIDDATA
;
218
}
219
if
(wc->
flags
&& rate != -1 && rate != wc->
rate
) {
220
av_log
(ctx,
AV_LOG_ERROR
,
221
"Sampling rate differ, this block: %i, header block: %i\n"
,
222
rate, wc->
rate
);
223
return
AVERROR_INVALIDDATA
;
224
}
225
wc->
blksize
= size - 24;
226
return
0;
227
}
228
229
static
int
wv_read_header
(
AVFormatContext
*s)
230
{
231
AVIOContext
*pb = s->
pb
;
232
WVContext
*wc = s->
priv_data
;
233
AVStream
*st;
234
int
ret;
235
236
wc->
block_parsed
= 0;
237
for
(;;) {
238
if
((ret =
wv_read_block_header
(s, pb, 0)) < 0)
239
return
ret;
240
if
(!
AV_RN32
(wc->
extra
))
241
avio_skip
(pb, wc->
blksize
- 24);
242
else
243
break
;
244
}
245
246
/* now we are ready: build format streams */
247
st =
avformat_new_stream
(s,
NULL
);
248
if
(!st)
249
return
AVERROR
(ENOMEM);
250
st->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
251
st->
codec
->
codec_id
=
AV_CODEC_ID_WAVPACK
;
252
st->
codec
->
channels
= wc->
chan
;
253
st->
codec
->
channel_layout
= wc->
chmask
;
254
st->
codec
->
sample_rate
= wc->
rate
;
255
st->
codec
->
bits_per_coded_sample
= wc->
bpp
;
256
avpriv_set_pts_info
(st, 64, 1, wc->
rate
);
257
st->
start_time
= 0;
258
st->
duration
= wc->
samples
;
259
260
if
(s->
pb
->
seekable
) {
261
int64_t cur =
avio_tell
(s->
pb
);
262
wc->
apetag_start
=
ff_ape_parse_tag
(s);
263
if
(!
av_dict_get
(s->
metadata
,
""
,
NULL
,
AV_DICT_IGNORE_SUFFIX
))
264
ff_id3v1_read
(s);
265
avio_seek
(s->
pb
, cur, SEEK_SET);
266
}
267
268
return
0;
269
}
270
271
static
int
wv_read_packet
(
AVFormatContext
*s,
AVPacket
*pkt)
272
{
273
WVContext
*wc = s->
priv_data
;
274
int
ret;
275
int
size
, ver,
off
;
276
int64_t pos;
277
uint32_t block_samples;
278
279
if
(s->
pb
->
eof_reached
)
280
return
AVERROR_EOF
;
281
if
(wc->
block_parsed
) {
282
if
((ret =
wv_read_block_header
(s, s->
pb
, 0)) < 0)
283
return
ret;
284
}
285
286
pos = wc->
pos
;
287
off = wc->
multichannel
? 4 : 0;
288
if
(
av_new_packet
(pkt, wc->
blksize
+
WV_EXTRA_SIZE
+ off) < 0)
289
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
);
294
if
(ret != wc->
blksize
) {
295
av_free_packet
(pkt);
296
return
AVERROR
(EIO);
297
}
298
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) {
304
av_free_packet
(pkt);
305
return
ret;
306
}
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
330
if
((ret =
wv_read_block_header
(s, s->
pb
, 1)) < 0) {
331
av_free_packet
(pkt);
332
return
ret;
333
}
334
ret =
av_append_packet
(s->
pb
, pkt, wc->
blksize
);
335
if
(ret < 0) {
336
av_free_packet
(pkt);
337
return
ret;
338
}
339
}
340
pkt->
stream_index
= 0;
341
wc->
block_parsed
= 1;
342
pkt->
pts
= wc->
soff
;
343
block_samples =
AV_RN32
(wc->
extra
);
344
if
(block_samples > INT32_MAX)
345
av_log
(s,
AV_LOG_WARNING
,
346
"Too many samples in block: %"
PRIu32
"\n"
, block_samples);
347
else
348
pkt->
duration
= block_samples;
349
350
av_add_index_entry
(s->
streams
[0], pos, pkt->
pts
, 0, 0,
AVINDEX_KEYFRAME
);
351
return
0;
352
}
353
354
static
int
wv_read_seek
(
AVFormatContext
*s,
int
stream_index,
355
int64_t timestamp,
int
flags
)
356
{
357
AVStream
*st = s->
streams
[stream_index];
358
WVContext
*wc = s->
priv_data
;
359
AVPacket
pkt1, *pkt = &pkt1;
360
int
ret;
361
int
index
=
av_index_search_timestamp
(st, timestamp, flags);
362
int64_t pos, pts;
363
364
/* if found, seek there */
365
if
(index >= 0 &&
366
timestamp <= st->index_entries[st->
nb_index_entries
- 1].timestamp) {
367
wc->
block_parsed
= 1;
368
avio_seek
(s->
pb
, st->
index_entries
[index].
pos
, SEEK_SET);
369
return
0;
370
}
371
/* if timestamp is out of bounds, return error */
372
if
(timestamp < 0 || timestamp >= s->
duration
)
373
return
AVERROR
(EINVAL);
374
375
pos =
avio_tell
(s->
pb
);
376
do
{
377
ret =
av_read_frame
(s, pkt);
378
if
(ret < 0) {
379
avio_seek
(s->
pb
, pos, SEEK_SET);
380
return
ret;
381
}
382
pts = pkt->
pts
;
383
av_free_packet
(pkt);
384
}
while
(pts < timestamp);
385
return
0;
386
}
387
388
AVInputFormat
ff_wv_demuxer
= {
389
.
name
=
"wv"
,
390
.long_name =
NULL_IF_CONFIG_SMALL
(
"WavPack"
),
391
.priv_data_size =
sizeof
(
WVContext
),
392
.
read_probe
=
wv_probe
,
393
.
read_header
=
wv_read_header
,
394
.
read_packet
=
wv_read_packet
,
395
.
read_seek
=
wv_read_seek
,
396
};