Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * WavPack demuxer |
||
3 | * Copyright (c) 2006,2011 Konstantin Shishkov |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg 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 | * FFmpeg 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 FFmpeg; 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 | #include "wv.h" |
||
30 | |||
31 | enum WV_FLAGS { |
||
32 | WV_MONO = 0x0004, |
||
33 | WV_HYBRID = 0x0008, |
||
34 | WV_JOINT = 0x0010, |
||
35 | WV_CROSSD = 0x0020, |
||
36 | WV_HSHAPE = 0x0040, |
||
37 | WV_FLOAT = 0x0080, |
||
38 | WV_INT32 = 0x0100, |
||
39 | WV_HBR = 0x0200, |
||
40 | WV_HBAL = 0x0400, |
||
41 | WV_MCINIT = 0x0800, |
||
42 | WV_MCEND = 0x1000, |
||
43 | }; |
||
44 | |||
45 | static const int wv_rates[16] = { |
||
46 | 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
||
47 | 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1 |
||
48 | }; |
||
49 | |||
50 | typedef struct { |
||
51 | uint8_t block_header[WV_HEADER_SIZE]; |
||
52 | WvHeader header; |
||
53 | int rate, chan, bpp; |
||
54 | uint32_t chmask; |
||
55 | int multichannel; |
||
56 | int block_parsed; |
||
57 | int64_t pos; |
||
58 | |||
59 | int64_t apetag_start; |
||
60 | } WVContext; |
||
61 | |||
62 | static int wv_probe(AVProbeData *p) |
||
63 | { |
||
64 | /* check file header */ |
||
65 | if (p->buf_size <= 32) |
||
66 | return 0; |
||
67 | if (AV_RL32(&p->buf[0]) == MKTAG('w', 'v', 'p', 'k') && |
||
68 | AV_RL32(&p->buf[4]) >= 24 && |
||
69 | AV_RL32(&p->buf[4]) <= WV_BLOCK_LIMIT && |
||
70 | AV_RL16(&p->buf[8]) >= 0x402 && |
||
71 | AV_RL16(&p->buf[8]) <= 0x410) |
||
72 | return AVPROBE_SCORE_MAX; |
||
73 | else |
||
74 | return 0; |
||
75 | } |
||
76 | |||
77 | static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) |
||
78 | { |
||
79 | WVContext *wc = ctx->priv_data; |
||
80 | int ret; |
||
81 | int rate, bpp, chan; |
||
82 | uint32_t chmask, flags; |
||
83 | |||
84 | wc->pos = avio_tell(pb); |
||
85 | |||
86 | /* don't return bogus packets with the ape tag data */ |
||
87 | if (wc->apetag_start && wc->pos >= wc->apetag_start) |
||
88 | return AVERROR_EOF; |
||
89 | |||
90 | ret = avio_read(pb, wc->block_header, WV_HEADER_SIZE); |
||
91 | if (ret != WV_HEADER_SIZE) |
||
92 | return (ret < 0) ? ret : AVERROR_EOF; |
||
93 | |||
94 | ret = ff_wv_parse_header(&wc->header, wc->block_header); |
||
95 | if (ret < 0) { |
||
96 | av_log(ctx, AV_LOG_ERROR, "Invalid block header.\n"); |
||
97 | return ret; |
||
98 | } |
||
99 | |||
100 | if (wc->header.version < 0x402 || wc->header.version > 0x410) { |
||
101 | av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", wc->header.version); |
||
102 | return AVERROR_PATCHWELCOME; |
||
103 | } |
||
104 | |||
105 | /* Blocks with zero samples don't contain actual audio information |
||
106 | * and should be ignored */ |
||
107 | if (!wc->header.samples) |
||
108 | return 0; |
||
109 | // parse flags |
||
110 | flags = wc->header.flags; |
||
111 | bpp = ((flags & 3) + 1) << 3; |
||
112 | chan = 1 + !(flags & WV_MONO); |
||
113 | chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; |
||
114 | rate = wv_rates[(flags >> 23) & 0xF]; |
||
115 | wc->multichannel = !(wc->header.initial && wc->header.final); |
||
116 | if (wc->multichannel) { |
||
117 | chan = wc->chan; |
||
118 | chmask = wc->chmask; |
||
119 | } |
||
120 | if ((rate == -1 || !chan) && !wc->block_parsed) { |
||
121 | int64_t block_end = avio_tell(pb) + wc->header.blocksize; |
||
122 | if (!pb->seekable) { |
||
123 | av_log(ctx, AV_LOG_ERROR, |
||
124 | "Cannot determine additional parameters\n"); |
||
125 | return AVERROR_INVALIDDATA; |
||
126 | } |
||
127 | while (avio_tell(pb) < block_end) { |
||
128 | int id, size; |
||
129 | id = avio_r8(pb); |
||
130 | size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb); |
||
131 | size <<= 1; |
||
132 | if (id & 0x40) |
||
133 | size--; |
||
134 | switch (id & 0x3F) { |
||
135 | case 0xD: |
||
136 | if (size <= 1) { |
||
137 | av_log(ctx, AV_LOG_ERROR, |
||
138 | "Insufficient channel information\n"); |
||
139 | return AVERROR_INVALIDDATA; |
||
140 | } |
||
141 | chan = avio_r8(pb); |
||
142 | switch (size - 2) { |
||
143 | case 0: |
||
144 | chmask = avio_r8(pb); |
||
145 | break; |
||
146 | case 1: |
||
147 | chmask = avio_rl16(pb); |
||
148 | break; |
||
149 | case 2: |
||
150 | chmask = avio_rl24(pb); |
||
151 | break; |
||
152 | case 3: |
||
153 | chmask = avio_rl32(pb); |
||
154 | break; |
||
155 | case 5: |
||
156 | avio_skip(pb, 1); |
||
157 | chan |= (avio_r8(pb) & 0xF) << 8; |
||
158 | chmask = avio_rl24(pb); |
||
159 | break; |
||
160 | default: |
||
161 | av_log(ctx, AV_LOG_ERROR, |
||
162 | "Invalid channel info size %d\n", size); |
||
163 | return AVERROR_INVALIDDATA; |
||
164 | } |
||
165 | break; |
||
166 | case 0x27: |
||
167 | rate = avio_rl24(pb); |
||
168 | break; |
||
169 | default: |
||
170 | avio_skip(pb, size); |
||
171 | } |
||
172 | if (id & 0x40) |
||
173 | avio_skip(pb, 1); |
||
174 | } |
||
175 | if (rate == -1) { |
||
176 | av_log(ctx, AV_LOG_ERROR, |
||
177 | "Cannot determine custom sampling rate\n"); |
||
178 | return AVERROR_INVALIDDATA; |
||
179 | } |
||
180 | avio_seek(pb, block_end - wc->header.blocksize, SEEK_SET); |
||
181 | } |
||
182 | if (!wc->bpp) |
||
183 | wc->bpp = bpp; |
||
184 | if (!wc->chan) |
||
185 | wc->chan = chan; |
||
186 | if (!wc->chmask) |
||
187 | wc->chmask = chmask; |
||
188 | if (!wc->rate) |
||
189 | wc->rate = rate; |
||
190 | |||
191 | if (flags && bpp != wc->bpp) { |
||
192 | av_log(ctx, AV_LOG_ERROR, |
||
193 | "Bits per sample differ, this block: %i, header block: %i\n", |
||
194 | bpp, wc->bpp); |
||
195 | return AVERROR_INVALIDDATA; |
||
196 | } |
||
197 | if (flags && !wc->multichannel && chan != wc->chan) { |
||
198 | av_log(ctx, AV_LOG_ERROR, |
||
199 | "Channels differ, this block: %i, header block: %i\n", |
||
200 | chan, wc->chan); |
||
201 | return AVERROR_INVALIDDATA; |
||
202 | } |
||
203 | if (flags && rate != -1 && rate != wc->rate) { |
||
204 | av_log(ctx, AV_LOG_ERROR, |
||
205 | "Sampling rate differ, this block: %i, header block: %i\n", |
||
206 | rate, wc->rate); |
||
207 | return AVERROR_INVALIDDATA; |
||
208 | } |
||
209 | return 0; |
||
210 | } |
||
211 | |||
212 | static int wv_read_header(AVFormatContext *s) |
||
213 | { |
||
214 | AVIOContext *pb = s->pb; |
||
215 | WVContext *wc = s->priv_data; |
||
216 | AVStream *st; |
||
217 | int ret; |
||
218 | |||
219 | wc->block_parsed = 0; |
||
220 | for (;;) { |
||
221 | if ((ret = wv_read_block_header(s, pb)) < 0) |
||
222 | return ret; |
||
223 | if (!wc->header.samples) |
||
224 | avio_skip(pb, wc->header.blocksize); |
||
225 | else |
||
226 | break; |
||
227 | } |
||
228 | |||
229 | /* now we are ready: build format streams */ |
||
230 | st = avformat_new_stream(s, NULL); |
||
231 | if (!st) |
||
232 | return AVERROR(ENOMEM); |
||
233 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
||
234 | st->codec->codec_id = AV_CODEC_ID_WAVPACK; |
||
235 | st->codec->channels = wc->chan; |
||
236 | st->codec->channel_layout = wc->chmask; |
||
237 | st->codec->sample_rate = wc->rate; |
||
238 | st->codec->bits_per_coded_sample = wc->bpp; |
||
239 | avpriv_set_pts_info(st, 64, 1, wc->rate); |
||
240 | st->start_time = 0; |
||
241 | if (wc->header.total_samples != 0xFFFFFFFFu) |
||
242 | st->duration = wc->header.total_samples; |
||
243 | |||
244 | if (s->pb->seekable) { |
||
245 | int64_t cur = avio_tell(s->pb); |
||
246 | wc->apetag_start = ff_ape_parse_tag(s); |
||
247 | if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) |
||
248 | ff_id3v1_read(s); |
||
249 | avio_seek(s->pb, cur, SEEK_SET); |
||
250 | } |
||
251 | |||
252 | return 0; |
||
253 | } |
||
254 | |||
255 | static int wv_read_packet(AVFormatContext *s, AVPacket *pkt) |
||
256 | { |
||
257 | WVContext *wc = s->priv_data; |
||
258 | int ret; |
||
259 | int off; |
||
260 | int64_t pos; |
||
261 | uint32_t block_samples; |
||
262 | |||
263 | if (url_feof(s->pb)) |
||
264 | return AVERROR_EOF; |
||
265 | if (wc->block_parsed) { |
||
266 | if ((ret = wv_read_block_header(s, s->pb)) < 0) |
||
267 | return ret; |
||
268 | } |
||
269 | |||
270 | pos = wc->pos; |
||
271 | if (av_new_packet(pkt, wc->header.blocksize + WV_HEADER_SIZE) < 0) |
||
272 | return AVERROR(ENOMEM); |
||
273 | memcpy(pkt->data, wc->block_header, WV_HEADER_SIZE); |
||
274 | ret = avio_read(s->pb, pkt->data + WV_HEADER_SIZE, wc->header.blocksize); |
||
275 | if (ret != wc->header.blocksize) { |
||
276 | av_free_packet(pkt); |
||
277 | return AVERROR(EIO); |
||
278 | } |
||
279 | while (!(wc->header.flags & WV_FLAG_FINAL_BLOCK)) { |
||
280 | if ((ret = wv_read_block_header(s, s->pb)) < 0) { |
||
281 | av_free_packet(pkt); |
||
282 | return ret; |
||
283 | } |
||
284 | |||
285 | off = pkt->size; |
||
286 | if ((ret = av_grow_packet(pkt, WV_HEADER_SIZE + wc->header.blocksize)) < 0) { |
||
287 | av_free_packet(pkt); |
||
288 | return ret; |
||
289 | } |
||
290 | memcpy(pkt->data + off, wc->block_header, WV_HEADER_SIZE); |
||
291 | |||
292 | ret = avio_read(s->pb, pkt->data + off + WV_HEADER_SIZE, wc->header.blocksize); |
||
293 | if (ret != wc->header.blocksize) { |
||
294 | av_free_packet(pkt); |
||
295 | return (ret < 0) ? ret : AVERROR_EOF; |
||
296 | } |
||
297 | } |
||
298 | pkt->stream_index = 0; |
||
299 | wc->block_parsed = 1; |
||
300 | pkt->pts = wc->header.block_idx; |
||
301 | block_samples = wc->header.samples; |
||
302 | if (block_samples > INT32_MAX) |
||
303 | av_log(s, AV_LOG_WARNING, |
||
304 | "Too many samples in block: %"PRIu32"\n", block_samples); |
||
305 | else |
||
306 | pkt->duration = block_samples; |
||
307 | |||
308 | av_add_index_entry(s->streams[0], pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME); |
||
309 | return 0; |
||
310 | } |
||
311 | |||
312 | static int wv_read_seek(AVFormatContext *s, int stream_index, |
||
313 | int64_t timestamp, int flags) |
||
314 | { |
||
315 | AVStream *st = s->streams[stream_index]; |
||
316 | WVContext *wc = s->priv_data; |
||
317 | AVPacket pkt1, *pkt = &pkt1; |
||
318 | int ret; |
||
319 | int index = av_index_search_timestamp(st, timestamp, flags); |
||
320 | int64_t pos, pts; |
||
321 | |||
322 | /* if found, seek there */ |
||
323 | if (index >= 0 && |
||
324 | timestamp <= st->index_entries[st->nb_index_entries - 1].timestamp) { |
||
325 | wc->block_parsed = 1; |
||
326 | avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET); |
||
327 | return 0; |
||
328 | } |
||
329 | /* if timestamp is out of bounds, return error */ |
||
330 | if (timestamp < 0 || timestamp >= s->duration) |
||
331 | return AVERROR(EINVAL); |
||
332 | |||
333 | pos = avio_tell(s->pb); |
||
334 | do { |
||
335 | ret = av_read_frame(s, pkt); |
||
336 | if (ret < 0) { |
||
337 | avio_seek(s->pb, pos, SEEK_SET); |
||
338 | return ret; |
||
339 | } |
||
340 | pts = pkt->pts; |
||
341 | av_free_packet(pkt); |
||
342 | } while(pts < timestamp); |
||
343 | return 0; |
||
344 | } |
||
345 | |||
346 | AVInputFormat ff_wv_demuxer = { |
||
347 | .name = "wv", |
||
348 | .long_name = NULL_IF_CONFIG_SMALL("WavPack"), |
||
349 | .priv_data_size = sizeof(WVContext), |
||
350 | .read_probe = wv_probe, |
||
351 | .read_header = wv_read_header, |
||
352 | .read_packet = wv_read_packet, |
||
353 | .read_seek = wv_read_seek, |
||
354 | };>>>=>>>>>>>><>=>=><=>>><>>>>=>=>=> |