Mercurial > libavformat.hg
annotate mpc8.c @ 6118:6780dc315f36 libavformat
Remove support for pre-Haiku, non-POSIX, non-C99 BeOS variants.
BeOS support has been broken for many years and the "maintainer" of the port
has not reacted to countless requests to get the port fixed.
approved by Mans
author | diego |
---|---|
date | Thu, 10 Jun 2010 16:51:14 +0000 |
parents | 536e5527c1e0 |
children |
rev | line source |
---|---|
2709 | 1 /* |
2 * Musepack SV8 demuxer | |
3 * Copyright (c) 2007 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 */ | |
3286 | 21 |
4872 | 22 #include "libavcodec/get_bits.h" |
3286 | 23 #include "libavcodec/unary.h" |
2709 | 24 #include "avformat.h" |
25 | |
26 /// Two-byte MPC tag | |
27 #define MKMPCTAG(a, b) (a | (b << 8)) | |
28 | |
29 #define TAG_MPCK MKTAG('M','P','C','K') | |
30 | |
31 /// Reserved MPC tags | |
32 enum MPCPacketTags{ | |
33 TAG_STREAMHDR = MKMPCTAG('S','H'), | |
34 TAG_STREAMEND = MKMPCTAG('S','E'), | |
35 | |
36 TAG_AUDIOPACKET = MKMPCTAG('A','P'), | |
37 | |
38 TAG_SEEKTBLOFF = MKMPCTAG('S','O'), | |
39 TAG_SEEKTABLE = MKMPCTAG('S','T'), | |
40 | |
41 TAG_REPLAYGAIN = MKMPCTAG('R','G'), | |
42 TAG_ENCINFO = MKMPCTAG('E','I'), | |
43 }; | |
44 | |
45 static const int mpc8_rate[8] = { 44100, 48000, 37800, 32000, -1, -1, -1, -1 }; | |
46 | |
47 typedef struct { | |
48 int ver; | |
49 int frame; | |
50 int64_t header_pos; | |
51 int64_t samples; | |
52 } MPCContext; | |
53 | |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
54 static inline int64_t bs_get_v(uint8_t **bs) |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
55 { |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
56 int64_t v = 0; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
57 int br = 0; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
58 int c; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
59 |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
60 do { |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
61 c = **bs; (*bs)++; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
62 v <<= 7; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
63 v |= c & 0x7F; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
64 br++; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
65 if (br > 10) |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
66 return -1; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
67 } while (c & 0x80); |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
68 |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
69 return v - br; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
70 } |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
71 |
2709 | 72 static int mpc8_probe(AVProbeData *p) |
73 { | |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
74 uint8_t *bs = p->buf + 4; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
75 uint8_t *bs_end = bs + p->buf_size; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
76 int64_t size; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
77 |
5204 | 78 if (p->buf_size < 16) |
79 return 0; | |
80 if (AV_RL32(p->buf) != TAG_MPCK) | |
81 return 0; | |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
82 while (bs < bs_end + 3) { |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
83 int header_found = (bs[0] == 'S' && bs[1] == 'H'); |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
84 if (bs[0] < 'A' || bs[0] > 'Z' || bs[1] < 'A' || bs[1] > 'Z') |
5204 | 85 return 0; |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
86 bs += 2; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
87 size = bs_get_v(&bs); |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
88 if (size < 2) |
5204 | 89 return 0; |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
90 if (bs + size - 2 >= bs_end) |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
91 return AVPROBE_SCORE_MAX / 4 - 1; //seems to be valid MPC but no header yet |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
92 if (header_found) { |
5209
2b52ec1e8619
reindent after last commit and remove unneeded empty line
kostya
parents:
5208
diff
changeset
|
93 if (size < 11 || size > 28) |
2b52ec1e8619
reindent after last commit and remove unneeded empty line
kostya
parents:
5208
diff
changeset
|
94 return 0; |
2b52ec1e8619
reindent after last commit and remove unneeded empty line
kostya
parents:
5208
diff
changeset
|
95 if (!AV_RL32(bs)) //zero CRC is invalid |
2b52ec1e8619
reindent after last commit and remove unneeded empty line
kostya
parents:
5208
diff
changeset
|
96 return 0; |
2b52ec1e8619
reindent after last commit and remove unneeded empty line
kostya
parents:
5208
diff
changeset
|
97 return AVPROBE_SCORE_MAX; |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
98 } else { |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
99 bs += size - 2; |
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
100 } |
5204 | 101 } |
5208
af13c900ff26
Make MPC SV8 probe skip tags until stream header is found
kostya
parents:
5204
diff
changeset
|
102 return 0; |
2709 | 103 } |
104 | |
105 static inline int64_t gb_get_v(GetBitContext *gb) | |
106 { | |
107 int64_t v = 0; | |
108 int bits = 0; | |
109 while(get_bits1(gb) && bits < 64-7){ | |
110 v <<= 7; | |
111 v |= get_bits(gb, 7); | |
112 bits += 7; | |
113 } | |
114 v <<= 7; | |
115 v |= get_bits(gb, 7); | |
116 | |
117 return v; | |
118 } | |
119 | |
120 static void mpc8_get_chunk_header(ByteIOContext *pb, int *tag, int64_t *size) | |
121 { | |
122 int64_t pos; | |
123 pos = url_ftell(pb); | |
124 *tag = get_le16(pb); | |
125 *size = ff_get_v(pb); | |
126 *size -= url_ftell(pb) - pos; | |
127 } | |
128 | |
129 static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) | |
130 { | |
131 MPCContext *c = s->priv_data; | |
132 int tag; | |
133 int64_t size, pos, ppos[2]; | |
134 uint8_t *buf; | |
135 int i, t, seekd; | |
136 GetBitContext gb; | |
137 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
138 url_fseek(s->pb, off, SEEK_SET); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
139 mpc8_get_chunk_header(s->pb, &tag, &size); |
2709 | 140 if(tag != TAG_SEEKTABLE){ |
141 av_log(s, AV_LOG_ERROR, "No seek table at given position\n"); | |
142 return; | |
143 } | |
5030
06903f8f7247
Allocate a bit more memory for MPC SV8 seek table, so bitreader won't read
kostya
parents:
4872
diff
changeset
|
144 if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE))) |
2709 | 145 return; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
146 get_buffer(s->pb, buf, size); |
2709 | 147 init_get_bits(&gb, buf, size * 8); |
148 size = gb_get_v(&gb); | |
149 if(size > UINT_MAX/4 || size > c->samples/1152){ | |
150 av_log(s, AV_LOG_ERROR, "Seek table is too big\n"); | |
151 return; | |
152 } | |
153 seekd = get_bits(&gb, 4); | |
154 for(i = 0; i < 2; i++){ | |
155 pos = gb_get_v(&gb) + c->header_pos; | |
156 ppos[1 - i] = pos; | |
157 av_add_index_entry(s->streams[0], pos, i, 0, 0, AVINDEX_KEYFRAME); | |
158 } | |
159 for(; i < size; i++){ | |
160 t = get_unary(&gb, 1, 33) << 12; | |
161 t += get_bits(&gb, 12); | |
162 if(t & 1) | |
163 t = -(t & ~1); | |
164 pos = (t >> 1) + ppos[0]*2 - ppos[1]; | |
165 av_add_index_entry(s->streams[0], pos, i << seekd, 0, 0, AVINDEX_KEYFRAME); | |
166 ppos[1] = ppos[0]; | |
167 ppos[0] = pos; | |
168 } | |
169 av_free(buf); | |
170 } | |
171 | |
172 static void mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size) | |
173 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
174 ByteIOContext *pb = s->pb; |
2709 | 175 int64_t pos, off; |
176 | |
177 switch(tag){ | |
178 case TAG_SEEKTBLOFF: | |
179 pos = url_ftell(pb) + size; | |
180 off = ff_get_v(pb); | |
181 mpc8_parse_seektable(s, chunk_pos + off); | |
182 url_fseek(pb, pos, SEEK_SET); | |
183 break; | |
184 default: | |
185 url_fskip(pb, size); | |
186 } | |
187 } | |
188 | |
189 static int mpc8_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
190 { | |
191 MPCContext *c = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
192 ByteIOContext *pb = s->pb; |
2709 | 193 AVStream *st; |
194 int tag = 0; | |
195 int64_t size, pos; | |
196 | |
197 c->header_pos = url_ftell(pb); | |
198 if(get_le32(pb) != TAG_MPCK){ | |
199 av_log(s, AV_LOG_ERROR, "Not a Musepack8 file\n"); | |
200 return -1; | |
201 } | |
202 | |
203 while(!url_feof(pb)){ | |
204 pos = url_ftell(pb); | |
205 mpc8_get_chunk_header(pb, &tag, &size); | |
206 if(tag == TAG_STREAMHDR) | |
207 break; | |
208 mpc8_handle_chunk(s, tag, pos, size); | |
209 } | |
210 if(tag != TAG_STREAMHDR){ | |
211 av_log(s, AV_LOG_ERROR, "Stream header not found\n"); | |
212 return -1; | |
213 } | |
214 pos = url_ftell(pb); | |
215 url_fskip(pb, 4); //CRC | |
216 c->ver = get_byte(pb); | |
217 if(c->ver != 8){ | |
218 av_log(s, AV_LOG_ERROR, "Unknown stream version %d\n", c->ver); | |
219 return -1; | |
220 } | |
221 c->samples = ff_get_v(pb); | |
222 ff_get_v(pb); //silence samples at the beginning | |
223 | |
224 st = av_new_stream(s, 0); | |
225 if (!st) | |
226 return AVERROR(ENOMEM); | |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
5241
diff
changeset
|
227 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
2709 | 228 st->codec->codec_id = CODEC_ID_MUSEPACK8; |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
229 st->codec->bits_per_coded_sample = 16; |
2709 | 230 |
231 st->codec->extradata_size = 2; | |
232 st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
233 get_buffer(pb, st->codec->extradata, st->codec->extradata_size); | |
234 | |
235 st->codec->channels = (st->codec->extradata[1] >> 4) + 1; | |
236 st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5]; | |
237 av_set_pts_info(st, 32, 1152 << (st->codec->extradata[1]&3)*2, st->codec->sample_rate); | |
238 st->duration = c->samples / (1152 << (st->codec->extradata[1]&3)*2); | |
239 size -= url_ftell(pb) - pos; | |
240 | |
241 return 0; | |
242 } | |
243 | |
244 static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt) | |
245 { | |
246 MPCContext *c = s->priv_data; | |
247 int tag; | |
248 int64_t pos, size; | |
249 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
250 while(!url_feof(s->pb)){ |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
251 pos = url_ftell(s->pb); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
252 mpc8_get_chunk_header(s->pb, &tag, &size); |
5241
da61aef912cb
Return an error when the parsed mpc chunk size is negative, otherwise we
reimar
parents:
5209
diff
changeset
|
253 if (size < 0) |
da61aef912cb
Return an error when the parsed mpc chunk size is negative, otherwise we
reimar
parents:
5209
diff
changeset
|
254 return -1; |
2709 | 255 if(tag == TAG_AUDIOPACKET){ |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
256 if(av_get_packet(s->pb, pkt, size) < 0) |
2709 | 257 return AVERROR(ENOMEM); |
258 pkt->stream_index = 0; | |
259 pkt->pts = c->frame; | |
260 return 0; | |
261 } | |
262 if(tag == TAG_STREAMEND) | |
263 return AVERROR(EIO); | |
264 mpc8_handle_chunk(s, tag, pos, size); | |
265 } | |
266 return 0; | |
267 } | |
268 | |
269 static int mpc8_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) | |
270 { | |
271 AVStream *st = s->streams[stream_index]; | |
272 MPCContext *c = s->priv_data; | |
273 int index = av_index_search_timestamp(st, timestamp, flags); | |
274 | |
275 if(index < 0) return -1; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2709
diff
changeset
|
276 url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); |
2709 | 277 c->frame = st->index_entries[index].timestamp; |
278 return 0; | |
279 } | |
280 | |
281 | |
282 AVInputFormat mpc8_demuxer = { | |
283 "mpc8", | |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3286
diff
changeset
|
284 NULL_IF_CONFIG_SMALL("Musepack SV8"), |
2709 | 285 sizeof(MPCContext), |
286 mpc8_probe, | |
287 mpc8_read_header, | |
288 mpc8_read_packet, | |
289 NULL, | |
290 mpc8_read_seek, | |
291 }; |