Mercurial > libavformat.hg
annotate ape.c @ 6085:72c7c3d5c4e9 libavformat
matroskaenc: Mux clusters better
Start them on keyframes when reasonable, and delay writing audio packets
to help ensure that there's audio samples available for the first frame in
clusters.
Patch by James Zern <jzern at google>
author | conrad |
---|---|
date | Fri, 04 Jun 2010 22:40:50 +0000 |
parents | 08cd1179a20d |
children |
rev | line source |
---|---|
2548 | 1 /* |
2 * Monkey's Audio APE demuxer | |
3 * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> | |
4 * based upon libdemac from Dave Chapman. | |
5 * | |
6 * This file is part of FFmpeg. | |
7 * | |
8 * FFmpeg is free software; you can redistribute it and/or | |
9 * modify it under the terms of the GNU Lesser General Public | |
10 * License as published by the Free Software Foundation; either | |
11 * version 2.1 of the License, or (at your option) any later version. | |
12 * | |
13 * FFmpeg is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Lesser General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
19 * License along with FFmpeg; if not, write to the Free Software | |
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 */ | |
22 | |
23 #include <stdio.h> | |
24 | |
4201
7d2f3f1b68d8
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
3908
diff
changeset
|
25 #include "libavutil/intreadwrite.h" |
2548 | 26 #include "avformat.h" |
5134 | 27 #include "apetag.h" |
2548 | 28 |
2556
cb131102b256
disable loads of debug messages to reduce object size
aurel
parents:
2554
diff
changeset
|
29 #define ENABLE_DEBUG 0 |
cb131102b256
disable loads of debug messages to reduce object size
aurel
parents:
2554
diff
changeset
|
30 |
2548 | 31 /* The earliest and latest file formats supported by this library */ |
2568
59f7ce8ad381
Looks like this APE decoder support versions starting from 3.95
kostya
parents:
2556
diff
changeset
|
32 #define APE_MIN_VERSION 3950 |
2548 | 33 #define APE_MAX_VERSION 3990 |
34 | |
35 #define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE] | |
36 #define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection [OBSOLETE] | |
37 #define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // uint32 nPeakLevel after the header [OBSOLETE] | |
38 #define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit [OBSOLETE] | |
39 #define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level | |
40 #define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored) | |
41 | |
42 #define MAC_SUBFRAME_SIZE 4608 | |
43 | |
44 #define APE_EXTRADATA_SIZE 6 | |
45 | |
46 typedef struct { | |
47 int64_t pos; | |
48 int nblocks; | |
49 int size; | |
50 int skip; | |
51 int64_t pts; | |
52 } APEFrame; | |
53 | |
54 typedef struct { | |
55 /* Derived fields */ | |
56 uint32_t junklength; | |
57 uint32_t firstframe; | |
58 uint32_t totalsamples; | |
59 int currentframe; | |
60 APEFrame *frames; | |
61 | |
62 /* Info from Descriptor Block */ | |
63 char magic[4]; | |
64 int16_t fileversion; | |
65 int16_t padding1; | |
66 uint32_t descriptorlength; | |
67 uint32_t headerlength; | |
68 uint32_t seektablelength; | |
69 uint32_t wavheaderlength; | |
70 uint32_t audiodatalength; | |
71 uint32_t audiodatalength_high; | |
72 uint32_t wavtaillength; | |
73 uint8_t md5[16]; | |
74 | |
75 /* Info from Header Block */ | |
76 uint16_t compressiontype; | |
77 uint16_t formatflags; | |
78 uint32_t blocksperframe; | |
79 uint32_t finalframeblocks; | |
80 uint32_t totalframes; | |
81 uint16_t bps; | |
82 uint16_t channels; | |
83 uint32_t samplerate; | |
84 | |
85 /* Seektable */ | |
86 uint32_t *seektable; | |
87 } APEContext; | |
88 | |
89 static int ape_probe(AVProbeData * p) | |
90 { | |
91 if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ') | |
92 return AVPROBE_SCORE_MAX; | |
93 | |
94 return 0; | |
95 } | |
96 | |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
97 static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx) |
2548 | 98 { |
2556
cb131102b256
disable loads of debug messages to reduce object size
aurel
parents:
2554
diff
changeset
|
99 #if ENABLE_DEBUG |
2548 | 100 int i; |
101 | |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
102 av_log(s, AV_LOG_DEBUG, "Descriptor Block:\n\n"); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
103 av_log(s, AV_LOG_DEBUG, "magic = \"%c%c%c%c\"\n", ape_ctx->magic[0], ape_ctx->magic[1], ape_ctx->magic[2], ape_ctx->magic[3]); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
104 av_log(s, AV_LOG_DEBUG, "fileversion = %d\n", ape_ctx->fileversion); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
105 av_log(s, AV_LOG_DEBUG, "descriptorlength = %d\n", ape_ctx->descriptorlength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
106 av_log(s, AV_LOG_DEBUG, "headerlength = %d\n", ape_ctx->headerlength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
107 av_log(s, AV_LOG_DEBUG, "seektablelength = %d\n", ape_ctx->seektablelength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
108 av_log(s, AV_LOG_DEBUG, "wavheaderlength = %d\n", ape_ctx->wavheaderlength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
109 av_log(s, AV_LOG_DEBUG, "audiodatalength = %d\n", ape_ctx->audiodatalength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
110 av_log(s, AV_LOG_DEBUG, "audiodatalength_high = %d\n", ape_ctx->audiodatalength_high); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
111 av_log(s, AV_LOG_DEBUG, "wavtaillength = %d\n", ape_ctx->wavtaillength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
112 av_log(s, AV_LOG_DEBUG, "md5 = "); |
2548 | 113 for (i = 0; i < 16; i++) |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
114 av_log(s, AV_LOG_DEBUG, "%02x", ape_ctx->md5[i]); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
115 av_log(s, AV_LOG_DEBUG, "\n"); |
2548 | 116 |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
117 av_log(s, AV_LOG_DEBUG, "\nHeader Block:\n\n"); |
2548 | 118 |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
119 av_log(s, AV_LOG_DEBUG, "compressiontype = %d\n", ape_ctx->compressiontype); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
120 av_log(s, AV_LOG_DEBUG, "formatflags = %d\n", ape_ctx->formatflags); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
121 av_log(s, AV_LOG_DEBUG, "blocksperframe = %d\n", ape_ctx->blocksperframe); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
122 av_log(s, AV_LOG_DEBUG, "finalframeblocks = %d\n", ape_ctx->finalframeblocks); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
123 av_log(s, AV_LOG_DEBUG, "totalframes = %d\n", ape_ctx->totalframes); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
124 av_log(s, AV_LOG_DEBUG, "bps = %d\n", ape_ctx->bps); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
125 av_log(s, AV_LOG_DEBUG, "channels = %d\n", ape_ctx->channels); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
126 av_log(s, AV_LOG_DEBUG, "samplerate = %d\n", ape_ctx->samplerate); |
2548 | 127 |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
128 av_log(s, AV_LOG_DEBUG, "\nSeektable\n\n"); |
2548 | 129 if ((ape_ctx->seektablelength / sizeof(uint32_t)) != ape_ctx->totalframes) { |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
130 av_log(s, AV_LOG_DEBUG, "No seektable\n"); |
2548 | 131 } else { |
132 for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) { | |
133 if (i < ape_ctx->totalframes - 1) { | |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
134 av_log(s, AV_LOG_DEBUG, "%8d %d (%d bytes)\n", i, ape_ctx->seektable[i], ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]); |
2548 | 135 } else { |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
136 av_log(s, AV_LOG_DEBUG, "%8d %d\n", i, ape_ctx->seektable[i]); |
2548 | 137 } |
138 } | |
139 } | |
140 | |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
141 av_log(s, AV_LOG_DEBUG, "\nFrames\n\n"); |
2548 | 142 for (i = 0; i < ape_ctx->totalframes; i++) |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
143 av_log(s, AV_LOG_DEBUG, "%8d %8lld %8d (%d samples)\n", i, ape_ctx->frames[i].pos, ape_ctx->frames[i].size, ape_ctx->frames[i].nblocks); |
2548 | 144 |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
145 av_log(s, AV_LOG_DEBUG, "\nCalculated information:\n\n"); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
146 av_log(s, AV_LOG_DEBUG, "junklength = %d\n", ape_ctx->junklength); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
147 av_log(s, AV_LOG_DEBUG, "firstframe = %d\n", ape_ctx->firstframe); |
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
148 av_log(s, AV_LOG_DEBUG, "totalsamples = %d\n", ape_ctx->totalsamples); |
2556
cb131102b256
disable loads of debug messages to reduce object size
aurel
parents:
2554
diff
changeset
|
149 #endif |
2548 | 150 } |
151 | |
152 static int ape_read_header(AVFormatContext * s, AVFormatParameters * ap) | |
153 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2568
diff
changeset
|
154 ByteIOContext *pb = s->pb; |
2548 | 155 APEContext *ape = s->priv_data; |
156 AVStream *st; | |
157 uint32_t tag; | |
158 int i; | |
159 int total_blocks; | |
160 int64_t pts; | |
161 | |
162 /* TODO: Skip any leading junk such as id3v2 tags */ | |
163 ape->junklength = 0; | |
164 | |
165 tag = get_le32(pb); | |
166 if (tag != MKTAG('M', 'A', 'C', ' ')) | |
167 return -1; | |
168 | |
169 ape->fileversion = get_le16(pb); | |
170 | |
171 if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) { | |
172 av_log(s, AV_LOG_ERROR, "Unsupported file version - %d.%02d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10); | |
173 return -1; | |
174 } | |
175 | |
176 if (ape->fileversion >= 3980) { | |
177 ape->padding1 = get_le16(pb); | |
178 ape->descriptorlength = get_le32(pb); | |
179 ape->headerlength = get_le32(pb); | |
180 ape->seektablelength = get_le32(pb); | |
181 ape->wavheaderlength = get_le32(pb); | |
182 ape->audiodatalength = get_le32(pb); | |
183 ape->audiodatalength_high = get_le32(pb); | |
184 ape->wavtaillength = get_le32(pb); | |
185 get_buffer(pb, ape->md5, 16); | |
186 | |
187 /* Skip any unknown bytes at the end of the descriptor. | |
188 This is for future compatibility */ | |
189 if (ape->descriptorlength > 52) | |
190 url_fseek(pb, ape->descriptorlength - 52, SEEK_CUR); | |
191 | |
192 /* Read header data */ | |
193 ape->compressiontype = get_le16(pb); | |
194 ape->formatflags = get_le16(pb); | |
195 ape->blocksperframe = get_le32(pb); | |
196 ape->finalframeblocks = get_le32(pb); | |
197 ape->totalframes = get_le32(pb); | |
198 ape->bps = get_le16(pb); | |
199 ape->channels = get_le16(pb); | |
200 ape->samplerate = get_le32(pb); | |
201 } else { | |
202 ape->descriptorlength = 0; | |
203 ape->headerlength = 32; | |
204 | |
205 ape->compressiontype = get_le16(pb); | |
206 ape->formatflags = get_le16(pb); | |
207 ape->channels = get_le16(pb); | |
208 ape->samplerate = get_le32(pb); | |
209 ape->wavheaderlength = get_le32(pb); | |
210 ape->wavtaillength = get_le32(pb); | |
211 ape->totalframes = get_le32(pb); | |
212 ape->finalframeblocks = get_le32(pb); | |
213 | |
214 if (ape->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) { | |
215 url_fseek(pb, 4, SEEK_CUR); /* Skip the peak level */ | |
216 ape->headerlength += 4; | |
217 } | |
218 | |
219 if (ape->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS) { | |
220 ape->seektablelength = get_le32(pb); | |
221 ape->headerlength += 4; | |
222 ape->seektablelength *= sizeof(int32_t); | |
223 } else | |
224 ape->seektablelength = ape->totalframes * sizeof(int32_t); | |
225 | |
226 if (ape->formatflags & MAC_FORMAT_FLAG_8_BIT) | |
227 ape->bps = 8; | |
228 else if (ape->formatflags & MAC_FORMAT_FLAG_24_BIT) | |
229 ape->bps = 24; | |
230 else | |
231 ape->bps = 16; | |
232 | |
233 if (ape->fileversion >= 3950) | |
234 ape->blocksperframe = 73728 * 4; | |
235 else if (ape->fileversion >= 3900 || (ape->fileversion >= 3800 && ape->compressiontype >= 4000)) | |
236 ape->blocksperframe = 73728; | |
237 else | |
238 ape->blocksperframe = 9216; | |
239 | |
240 /* Skip any stored wav header */ | |
241 if (!(ape->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) | |
242 url_fskip(pb, ape->wavheaderlength); | |
243 } | |
244 | |
245 if(ape->totalframes > UINT_MAX / sizeof(APEFrame)){ | |
246 av_log(s, AV_LOG_ERROR, "Too many frames: %d\n", ape->totalframes); | |
247 return -1; | |
248 } | |
249 ape->frames = av_malloc(ape->totalframes * sizeof(APEFrame)); | |
250 if(!ape->frames) | |
5930
08cd1179a20d
Replace all remaining occurrences of AVERROR_NOMEM with
stefano
parents:
5910
diff
changeset
|
251 return AVERROR(ENOMEM); |
2548 | 252 ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength; |
253 ape->currentframe = 0; | |
254 | |
255 | |
256 ape->totalsamples = ape->finalframeblocks; | |
257 if (ape->totalframes > 1) | |
258 ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1); | |
259 | |
260 if (ape->seektablelength > 0) { | |
261 ape->seektable = av_malloc(ape->seektablelength); | |
262 for (i = 0; i < ape->seektablelength / sizeof(uint32_t); i++) | |
263 ape->seektable[i] = get_le32(pb); | |
264 } | |
265 | |
266 ape->frames[0].pos = ape->firstframe; | |
267 ape->frames[0].nblocks = ape->blocksperframe; | |
268 ape->frames[0].skip = 0; | |
269 for (i = 1; i < ape->totalframes; i++) { | |
270 ape->frames[i].pos = ape->seektable[i]; //ape->frames[i-1].pos + ape->blocksperframe; | |
271 ape->frames[i].nblocks = ape->blocksperframe; | |
272 ape->frames[i - 1].size = ape->frames[i].pos - ape->frames[i - 1].pos; | |
273 ape->frames[i].skip = (ape->frames[i].pos - ape->frames[0].pos) & 3; | |
274 } | |
275 ape->frames[ape->totalframes - 1].size = ape->finalframeblocks * 4; | |
276 ape->frames[ape->totalframes - 1].nblocks = ape->finalframeblocks; | |
277 | |
278 for (i = 0; i < ape->totalframes; i++) { | |
279 if(ape->frames[i].skip){ | |
280 ape->frames[i].pos -= ape->frames[i].skip; | |
281 ape->frames[i].size += ape->frames[i].skip; | |
282 } | |
283 ape->frames[i].size = (ape->frames[i].size + 3) & ~3; | |
284 } | |
285 | |
286 | |
4506
dfb8f047b552
Add a context to av_log() calls and extend ape_dumpinfo prototype to do that.
benoit
parents:
4201
diff
changeset
|
287 ape_dumpinfo(s, ape); |
2548 | 288 |
2554 | 289 /* try to read APE tags */ |
290 if (!url_is_streamed(pb)) { | |
5134 | 291 ff_ape_parse_tag(s); |
2554 | 292 url_fseek(pb, 0, SEEK_SET); |
293 } | |
294 | |
2548 | 295 av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype); |
296 | |
297 /* now we are ready: build format streams */ | |
298 st = av_new_stream(s, 0); | |
299 if (!st) | |
300 return -1; | |
301 | |
302 total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks; | |
303 | |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
5834
diff
changeset
|
304 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
2548 | 305 st->codec->codec_id = CODEC_ID_APE; |
306 st->codec->codec_tag = MKTAG('A', 'P', 'E', ' '); | |
307 st->codec->channels = ape->channels; | |
308 st->codec->sample_rate = ape->samplerate; | |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
309 st->codec->bits_per_coded_sample = ape->bps; |
2548 | 310 st->codec->frame_size = MAC_SUBFRAME_SIZE; |
311 | |
312 st->nb_frames = ape->totalframes; | |
5566
28094e9bd013
Set start_time and duration in AVStream instead of AVFormatContext for
conrad
parents:
5134
diff
changeset
|
313 st->start_time = 0; |
28094e9bd013
Set start_time and duration in AVStream instead of AVFormatContext for
conrad
parents:
5134
diff
changeset
|
314 st->duration = total_blocks / MAC_SUBFRAME_SIZE; |
2548 | 315 av_set_pts_info(st, 64, MAC_SUBFRAME_SIZE, ape->samplerate); |
316 | |
317 st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE); | |
318 st->codec->extradata_size = APE_EXTRADATA_SIZE; | |
319 AV_WL16(st->codec->extradata + 0, ape->fileversion); | |
320 AV_WL16(st->codec->extradata + 2, ape->compressiontype); | |
321 AV_WL16(st->codec->extradata + 4, ape->formatflags); | |
322 | |
323 pts = 0; | |
324 for (i = 0; i < ape->totalframes; i++) { | |
325 ape->frames[i].pts = pts; | |
326 av_add_index_entry(st, ape->frames[i].pos, ape->frames[i].pts, 0, 0, AVINDEX_KEYFRAME); | |
327 pts += ape->blocksperframe / MAC_SUBFRAME_SIZE; | |
328 } | |
329 | |
330 return 0; | |
331 } | |
332 | |
333 static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) | |
334 { | |
335 int ret; | |
336 int nblocks; | |
337 APEContext *ape = s->priv_data; | |
338 uint32_t extra_size = 8; | |
339 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2568
diff
changeset
|
340 if (url_feof(s->pb)) |
5834
134741dc8327
Replace all the occurrences of AVERROR_EIO with AVERROR(EIO), and mark
stefano
parents:
5566
diff
changeset
|
341 return AVERROR(EIO); |
2548 | 342 if (ape->currentframe > ape->totalframes) |
5834
134741dc8327
Replace all the occurrences of AVERROR_EIO with AVERROR(EIO), and mark
stefano
parents:
5566
diff
changeset
|
343 return AVERROR(EIO); |
2548 | 344 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2568
diff
changeset
|
345 url_fseek (s->pb, ape->frames[ape->currentframe].pos, SEEK_SET); |
2548 | 346 |
347 /* Calculate how many blocks there are in this frame */ | |
348 if (ape->currentframe == (ape->totalframes - 1)) | |
349 nblocks = ape->finalframeblocks; | |
350 else | |
351 nblocks = ape->blocksperframe; | |
352 | |
353 if (av_new_packet(pkt, ape->frames[ape->currentframe].size + extra_size) < 0) | |
5930
08cd1179a20d
Replace all remaining occurrences of AVERROR_NOMEM with
stefano
parents:
5910
diff
changeset
|
354 return AVERROR(ENOMEM); |
2548 | 355 |
356 AV_WL32(pkt->data , nblocks); | |
357 AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2568
diff
changeset
|
358 ret = get_buffer(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size); |
2548 | 359 |
360 pkt->pts = ape->frames[ape->currentframe].pts; | |
361 pkt->stream_index = 0; | |
362 | |
363 /* note: we need to modify the packet size here to handle the last | |
364 packet */ | |
365 pkt->size = ret + extra_size; | |
366 | |
367 ape->currentframe++; | |
368 | |
369 return 0; | |
370 } | |
371 | |
372 static int ape_read_close(AVFormatContext * s) | |
373 { | |
374 APEContext *ape = s->priv_data; | |
375 | |
376 av_freep(&ape->frames); | |
377 av_freep(&ape->seektable); | |
378 return 0; | |
379 } | |
380 | |
381 static int ape_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) | |
382 { | |
383 AVStream *st = s->streams[stream_index]; | |
384 APEContext *ape = s->priv_data; | |
385 int index = av_index_search_timestamp(st, timestamp, flags); | |
386 | |
387 if (index < 0) | |
388 return -1; | |
389 | |
390 ape->currentframe = index; | |
391 return 0; | |
392 } | |
393 | |
394 AVInputFormat ape_demuxer = { | |
395 "ape", | |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3266
diff
changeset
|
396 NULL_IF_CONFIG_SMALL("Monkey's Audio"), |
2548 | 397 sizeof(APEContext), |
398 ape_probe, | |
399 ape_read_header, | |
400 ape_read_packet, | |
401 ape_read_close, | |
402 ape_read_seek, | |
403 .extensions = "ape,apl,mac" | |
404 }; |