Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 && !avio_feof(pb)) { | |
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 (avio_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 | }; |