Mercurial > libavformat.hg
annotate wv.c @ 2660:022174d849d5 libavformat
fix issue 225, instead of stoping when wrong atom size is found,
limit atom size to what is left, assuming container atom has correct size..
cricket4.3g2 has incorrect moov atom size which indicates that file size should be
2 bytes bigger than it is and quicktime reads it correctly though.
author | bcoudurier |
---|---|
date | Mon, 22 Oct 2007 14:36:14 +0000 |
parents | c226029c8df4 |
children | d52c718e83f9 |
rev | line source |
---|---|
1324 | 1 /* |
2 * WavPack demuxer | |
3 * Copyright (c) 2006 Konstantin Shishkov. | |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1324
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1324
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1324
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
1324 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1324
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
1324 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1324
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
1324 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1324
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
1324 | 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 */ | |
21 | |
22 #include "avformat.h" | |
23 #include "bswap.h" | |
24 | |
25 // specs say that maximum block size is 1Mb | |
26 #define WV_BLOCK_LIMIT 1047576 | |
27 | |
28 #define WV_EXTRA_SIZE 12 | |
29 | |
30 enum WV_FLAGS{ | |
31 WV_MONO = 0x0004, | |
32 WV_HYBRID = 0x0008, | |
33 WV_JOINT = 0x0010, | |
34 WV_CROSSD = 0x0020, | |
35 WV_HSHAPE = 0x0040, | |
36 WV_FLOAT = 0x0080, | |
37 WV_INT32 = 0x0100, | |
38 WV_HBR = 0x0200, | |
39 WV_HBAL = 0x0400, | |
40 WV_MCINIT = 0x0800, | |
41 WV_MCEND = 0x1000, | |
42 }; | |
43 | |
44 static const int wv_rates[16] = { | |
45 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, | |
46 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1 | |
47 }; | |
48 | |
49 typedef struct{ | |
50 uint32_t blksize, flags; | |
51 int rate, chan, bpp; | |
1743 | 52 uint32_t samples, soff; |
1324 | 53 int block_parsed; |
54 uint8_t extra[WV_EXTRA_SIZE]; | |
1743 | 55 int64_t pos; |
1324 | 56 }WVContext; |
57 | |
58 static int wv_probe(AVProbeData *p) | |
59 { | |
60 /* check file header */ | |
61 if (p->buf_size <= 32) | |
62 return 0; | |
63 if (p->buf[0] == 'w' && p->buf[1] == 'v' && | |
64 p->buf[2] == 'p' && p->buf[3] == 'k') | |
65 return AVPROBE_SCORE_MAX; | |
66 else | |
67 return 0; | |
68 } | |
69 | |
70 static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb) | |
71 { | |
72 WVContext *wc = ctx->priv_data; | |
73 uint32_t tag, ver; | |
74 int size; | |
75 int rate, bpp, chan; | |
76 | |
1743 | 77 wc->pos = url_ftell(pb); |
1324 | 78 tag = get_le32(pb); |
79 if (tag != MKTAG('w', 'v', 'p', 'k')) | |
80 return -1; | |
81 size = get_le32(pb); | |
82 if(size < 24 || size > WV_BLOCK_LIMIT){ | |
83 av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size); | |
84 return -1; | |
85 } | |
86 wc->blksize = size; | |
87 ver = get_le16(pb); | |
2380
41c9871ea3c4
Support for WavPack version 0x410 (false stereo chunks)
kostya
parents:
2314
diff
changeset
|
88 if(ver < 0x402 || ver > 0x410){ |
1324 | 89 av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); |
90 return -1; | |
91 } | |
92 get_byte(pb); // track no | |
93 get_byte(pb); // track sub index | |
1743 | 94 wc->samples = get_le32(pb); // total samples in file |
95 wc->soff = get_le32(pb); // offset in samples of current block | |
1324 | 96 get_buffer(pb, wc->extra, WV_EXTRA_SIZE); |
1673 | 97 wc->flags = AV_RL32(wc->extra + 4); |
1324 | 98 //parse flags |
99 if(wc->flags & WV_FLOAT){ | |
100 av_log(ctx, AV_LOG_ERROR, "Floating point data is not supported\n"); | |
101 return -1; | |
102 } | |
103 if(wc->flags & WV_HYBRID){ | |
104 av_log(ctx, AV_LOG_ERROR, "Hybrid coding mode is not supported\n"); | |
105 return -1; | |
106 } | |
107 | |
108 bpp = ((wc->flags & 3) + 1) << 3; | |
109 chan = 1 + !(wc->flags & WV_MONO); | |
110 rate = wv_rates[(wc->flags >> 23) & 0xF]; | |
111 if(rate == -1){ | |
112 av_log(ctx, AV_LOG_ERROR, "Unknown sampling rate\n"); | |
113 return -1; | |
114 } | |
115 if(!wc->bpp) wc->bpp = bpp; | |
116 if(!wc->chan) wc->chan = chan; | |
117 if(!wc->rate) wc->rate = rate; | |
118 | |
1389
9ed80abc8eb7
Ignore blocks with no samples and flags (but usually with MD5 sum)
kostya
parents:
1387
diff
changeset
|
119 if(wc->flags && bpp != wc->bpp){ |
1324 | 120 av_log(ctx, AV_LOG_ERROR, "Bits per sample differ, this block: %i, header block: %i\n", bpp, wc->bpp); |
121 return -1; | |
122 } | |
1389
9ed80abc8eb7
Ignore blocks with no samples and flags (but usually with MD5 sum)
kostya
parents:
1387
diff
changeset
|
123 if(wc->flags && chan != wc->chan){ |
1324 | 124 av_log(ctx, AV_LOG_ERROR, "Channels differ, this block: %i, header block: %i\n", chan, wc->chan); |
125 return -1; | |
126 } | |
1389
9ed80abc8eb7
Ignore blocks with no samples and flags (but usually with MD5 sum)
kostya
parents:
1387
diff
changeset
|
127 if(wc->flags && rate != wc->rate){ |
1324 | 128 av_log(ctx, AV_LOG_ERROR, "Sampling rate differ, this block: %i, header block: %i\n", rate, wc->rate); |
129 return -1; | |
130 } | |
131 wc->blksize = size - 24; | |
132 return 0; | |
133 } | |
134 | |
135 static int wv_read_header(AVFormatContext *s, | |
136 AVFormatParameters *ap) | |
137 { | |
138 ByteIOContext *pb = &s->pb; | |
139 WVContext *wc = s->priv_data; | |
140 AVStream *st; | |
141 | |
142 if(wv_read_block_header(s, pb) < 0) | |
143 return -1; | |
144 | |
145 wc->block_parsed = 0; | |
146 /* now we are ready: build format streams */ | |
147 st = av_new_stream(s, 0); | |
148 if (!st) | |
149 return -1; | |
150 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
151 st->codec->codec_id = CODEC_ID_WAVPACK; | |
152 st->codec->channels = wc->chan; | |
153 st->codec->sample_rate = wc->rate; | |
154 st->codec->bits_per_sample = wc->bpp; | |
155 av_set_pts_info(st, 64, 1, wc->rate); | |
1743 | 156 s->start_time = 0; |
157 s->duration = (int64_t)wc->samples * AV_TIME_BASE / st->codec->sample_rate; | |
1324 | 158 return 0; |
159 } | |
160 | |
161 static int wv_read_packet(AVFormatContext *s, | |
162 AVPacket *pkt) | |
163 { | |
164 WVContext *wc = s->priv_data; | |
1391 | 165 int ret; |
1324 | 166 |
167 if (url_feof(&s->pb)) | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1743
diff
changeset
|
168 return AVERROR(EIO); |
1324 | 169 if(wc->block_parsed){ |
170 if(wv_read_block_header(s, &s->pb) < 0) | |
171 return -1; | |
172 } | |
173 | |
174 if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE) < 0) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
1787
diff
changeset
|
175 return AVERROR(ENOMEM); |
1324 | 176 memcpy(pkt->data, wc->extra, WV_EXTRA_SIZE); |
177 ret = get_buffer(&s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize); | |
178 if(ret != wc->blksize){ | |
179 av_free_packet(pkt); | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
180 return AVERROR(EIO); |
1324 | 181 } |
182 pkt->stream_index = 0; | |
183 wc->block_parsed = 1; | |
184 pkt->size = ret + WV_EXTRA_SIZE; | |
1743 | 185 pkt->pts = wc->soff; |
186 av_add_index_entry(s->streams[0], wc->pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME); | |
1324 | 187 return 0; |
188 } | |
189 | |
190 static int wv_read_close(AVFormatContext *s) | |
191 { | |
192 return 0; | |
193 } | |
194 | |
1743 | 195 static int wv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
196 { | |
197 AVStream *st = s->streams[stream_index]; | |
198 WVContext *wc = s->priv_data; | |
199 AVPacket pkt1, *pkt = &pkt1; | |
200 int ret; | |
201 int index = av_index_search_timestamp(st, timestamp, flags); | |
202 int64_t pos, pts; | |
203 | |
204 /* if found, seek there */ | |
205 if (index >= 0){ | |
206 wc->block_parsed = 1; | |
207 url_fseek(&s->pb, st->index_entries[index].pos, SEEK_SET); | |
208 return 0; | |
209 } | |
210 /* if timestamp is out of bounds, return error */ | |
211 if(timestamp < 0 || timestamp >= s->duration) | |
212 return -1; | |
213 | |
214 pos = url_ftell(&s->pb); | |
215 do{ | |
216 ret = av_read_frame(s, pkt); | |
217 if (ret < 0){ | |
218 url_fseek(&s->pb, pos, SEEK_SET); | |
219 return -1; | |
220 } | |
221 pts = pkt->pts; | |
222 av_free_packet(pkt); | |
223 }while(pts < timestamp); | |
224 return 0; | |
225 } | |
226 | |
1324 | 227 AVInputFormat wv_demuxer = { |
228 "wv", | |
229 "WavPack", | |
230 sizeof(WVContext), | |
231 wv_probe, | |
232 wv_read_header, | |
233 wv_read_packet, | |
234 wv_read_close, | |
1743 | 235 wv_read_seek, |
1324 | 236 }; |