ffmpeg / libavformat / ape.c @ 2912e87a
History | View | Annotate | Download (14.3 KB)
1 | bf4a1f17 | Kostya Shishkov | /*
|
---|---|---|---|
2 | * Monkey's Audio APE demuxer
|
||
3 | * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
|
||
4 | * based upon libdemac from Dave Chapman.
|
||
5 | *
|
||
6 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
7 | bf4a1f17 | Kostya Shishkov | *
|
8 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
9 | bf4a1f17 | Kostya Shishkov | * 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 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
14 | bf4a1f17 | Kostya Shishkov | * 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 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
20 | bf4a1f17 | Kostya Shishkov | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
21 | */
|
||
22 | |||
23 | #include <stdio.h> |
||
24 | |||
25 | 6a5d31ac | Diego Biurrun | #include "libavutil/intreadwrite.h" |
26 | bf4a1f17 | Kostya Shishkov | #include "avformat.h" |
27 | 191e34cd | Kostya Shishkov | #include "apetag.h" |
28 | bf4a1f17 | Kostya Shishkov | |
29 | 7f559eb1 | Aurelien Jacobs | #define ENABLE_DEBUG 0 |
30 | |||
31 | bf4a1f17 | Kostya Shishkov | /* The earliest and latest file formats supported by this library */
|
32 | c1f3c630 | Kostya Shishkov | #define APE_MIN_VERSION 3950 |
33 | bf4a1f17 | Kostya Shishkov | #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 | |||
97 | 76b9092f | Benoit Fouet | static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx) |
98 | bf4a1f17 | Kostya Shishkov | { |
99 | 7f559eb1 | Aurelien Jacobs | #if ENABLE_DEBUG
|
100 | bf4a1f17 | Kostya Shishkov | int i;
|
101 | |||
102 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "Descriptor Block:\n\n");
|
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]); |
||
104 | av_log(s, AV_LOG_DEBUG, "fileversion = %d\n", ape_ctx->fileversion);
|
||
105 | av_log(s, AV_LOG_DEBUG, "descriptorlength = %d\n", ape_ctx->descriptorlength);
|
||
106 | av_log(s, AV_LOG_DEBUG, "headerlength = %d\n", ape_ctx->headerlength);
|
||
107 | av_log(s, AV_LOG_DEBUG, "seektablelength = %d\n", ape_ctx->seektablelength);
|
||
108 | av_log(s, AV_LOG_DEBUG, "wavheaderlength = %d\n", ape_ctx->wavheaderlength);
|
||
109 | av_log(s, AV_LOG_DEBUG, "audiodatalength = %d\n", ape_ctx->audiodatalength);
|
||
110 | av_log(s, AV_LOG_DEBUG, "audiodatalength_high = %d\n", ape_ctx->audiodatalength_high);
|
||
111 | av_log(s, AV_LOG_DEBUG, "wavtaillength = %d\n", ape_ctx->wavtaillength);
|
||
112 | av_log(s, AV_LOG_DEBUG, "md5 = ");
|
||
113 | bf4a1f17 | Kostya Shishkov | for (i = 0; i < 16; i++) |
114 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "%02x", ape_ctx->md5[i]);
|
115 | av_log(s, AV_LOG_DEBUG, "\n");
|
||
116 | bf4a1f17 | Kostya Shishkov | |
117 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "\nHeader Block:\n\n");
|
118 | bf4a1f17 | Kostya Shishkov | |
119 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "compressiontype = %d\n", ape_ctx->compressiontype);
|
120 | av_log(s, AV_LOG_DEBUG, "formatflags = %d\n", ape_ctx->formatflags);
|
||
121 | av_log(s, AV_LOG_DEBUG, "blocksperframe = %d\n", ape_ctx->blocksperframe);
|
||
122 | av_log(s, AV_LOG_DEBUG, "finalframeblocks = %d\n", ape_ctx->finalframeblocks);
|
||
123 | av_log(s, AV_LOG_DEBUG, "totalframes = %d\n", ape_ctx->totalframes);
|
||
124 | av_log(s, AV_LOG_DEBUG, "bps = %d\n", ape_ctx->bps);
|
||
125 | av_log(s, AV_LOG_DEBUG, "channels = %d\n", ape_ctx->channels);
|
||
126 | av_log(s, AV_LOG_DEBUG, "samplerate = %d\n", ape_ctx->samplerate);
|
||
127 | bf4a1f17 | Kostya Shishkov | |
128 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "\nSeektable\n\n");
|
129 | bf4a1f17 | Kostya Shishkov | if ((ape_ctx->seektablelength / sizeof(uint32_t)) != ape_ctx->totalframes) { |
130 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "No seektable\n");
|
131 | bf4a1f17 | Kostya Shishkov | } else {
|
132 | for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) { |
||
133 | if (i < ape_ctx->totalframes - 1) { |
||
134 | 76b9092f | Benoit Fouet | 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]); |
135 | bf4a1f17 | Kostya Shishkov | } else {
|
136 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "%8d %d\n", i, ape_ctx->seektable[i]);
|
137 | bf4a1f17 | Kostya Shishkov | } |
138 | } |
||
139 | } |
||
140 | |||
141 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "\nFrames\n\n");
|
142 | bf4a1f17 | Kostya Shishkov | for (i = 0; i < ape_ctx->totalframes; i++) |
143 | 76b9092f | Benoit Fouet | 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);
|
144 | bf4a1f17 | Kostya Shishkov | |
145 | 76b9092f | Benoit Fouet | av_log(s, AV_LOG_DEBUG, "\nCalculated information:\n\n");
|
146 | av_log(s, AV_LOG_DEBUG, "junklength = %d\n", ape_ctx->junklength);
|
||
147 | av_log(s, AV_LOG_DEBUG, "firstframe = %d\n", ape_ctx->firstframe);
|
||
148 | av_log(s, AV_LOG_DEBUG, "totalsamples = %d\n", ape_ctx->totalsamples);
|
||
149 | 7f559eb1 | Aurelien Jacobs | #endif
|
150 | bf4a1f17 | Kostya Shishkov | } |
151 | |||
152 | static int ape_read_header(AVFormatContext * s, AVFormatParameters * ap) |
||
153 | { |
||
154 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
155 | bf4a1f17 | Kostya Shishkov | 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 | b7effd4e | Anton Khirnov | tag = avio_rl32(pb); |
166 | bf4a1f17 | Kostya Shishkov | if (tag != MKTAG('M', 'A', 'C', ' ')) |
167 | return -1; |
||
168 | |||
169 | b7effd4e | Anton Khirnov | ape->fileversion = avio_rl16(pb); |
170 | bf4a1f17 | Kostya Shishkov | |
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 | b7effd4e | Anton Khirnov | ape->padding1 = avio_rl16(pb); |
178 | ape->descriptorlength = avio_rl32(pb); |
||
179 | ape->headerlength = avio_rl32(pb); |
||
180 | ape->seektablelength = avio_rl32(pb); |
||
181 | ape->wavheaderlength = avio_rl32(pb); |
||
182 | ape->audiodatalength = avio_rl32(pb); |
||
183 | ape->audiodatalength_high = avio_rl32(pb); |
||
184 | ape->wavtaillength = avio_rl32(pb); |
||
185 | avio_read(pb, ape->md5, 16);
|
||
186 | bf4a1f17 | Kostya Shishkov | |
187 | /* Skip any unknown bytes at the end of the descriptor.
|
||
188 | This is for future compatibility */
|
||
189 | if (ape->descriptorlength > 52) |
||
190 | 45a8a02a | Anton Khirnov | avio_skip(pb, ape->descriptorlength - 52);
|
191 | bf4a1f17 | Kostya Shishkov | |
192 | /* Read header data */
|
||
193 | b7effd4e | Anton Khirnov | ape->compressiontype = avio_rl16(pb); |
194 | ape->formatflags = avio_rl16(pb); |
||
195 | ape->blocksperframe = avio_rl32(pb); |
||
196 | ape->finalframeblocks = avio_rl32(pb); |
||
197 | ape->totalframes = avio_rl32(pb); |
||
198 | ape->bps = avio_rl16(pb); |
||
199 | ape->channels = avio_rl16(pb); |
||
200 | ape->samplerate = avio_rl32(pb); |
||
201 | bf4a1f17 | Kostya Shishkov | } else {
|
202 | ape->descriptorlength = 0;
|
||
203 | ape->headerlength = 32;
|
||
204 | |||
205 | b7effd4e | Anton Khirnov | ape->compressiontype = avio_rl16(pb); |
206 | ape->formatflags = avio_rl16(pb); |
||
207 | ape->channels = avio_rl16(pb); |
||
208 | ape->samplerate = avio_rl32(pb); |
||
209 | ape->wavheaderlength = avio_rl32(pb); |
||
210 | ape->wavtaillength = avio_rl32(pb); |
||
211 | ape->totalframes = avio_rl32(pb); |
||
212 | ape->finalframeblocks = avio_rl32(pb); |
||
213 | bf4a1f17 | Kostya Shishkov | |
214 | if (ape->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) {
|
||
215 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4); /* Skip the peak level */ |
216 | bf4a1f17 | Kostya Shishkov | ape->headerlength += 4;
|
217 | } |
||
218 | |||
219 | if (ape->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS) {
|
||
220 | b7effd4e | Anton Khirnov | ape->seektablelength = avio_rl32(pb); |
221 | bf4a1f17 | Kostya Shishkov | 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 | 45a8a02a | Anton Khirnov | avio_skip(pb, ape->wavheaderlength); |
243 | bf4a1f17 | Kostya Shishkov | } |
244 | |||
245 | 8312e3fc | Kostya | if(!ape->totalframes){
|
246 | av_log(s, AV_LOG_ERROR, "No frames in the file!\n");
|
||
247 | return AVERROR(EINVAL);
|
||
248 | } |
||
249 | bf4a1f17 | Kostya Shishkov | if(ape->totalframes > UINT_MAX / sizeof(APEFrame)){ |
250 | av_log(s, AV_LOG_ERROR, "Too many frames: %d\n", ape->totalframes);
|
||
251 | return -1; |
||
252 | } |
||
253 | ape->frames = av_malloc(ape->totalframes * sizeof(APEFrame));
|
||
254 | if(!ape->frames)
|
||
255 | 2874c81c | Stefano Sabatini | return AVERROR(ENOMEM);
|
256 | bf4a1f17 | Kostya Shishkov | ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength; |
257 | ape->currentframe = 0;
|
||
258 | |||
259 | |||
260 | ape->totalsamples = ape->finalframeblocks; |
||
261 | if (ape->totalframes > 1) |
||
262 | ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1);
|
||
263 | |||
264 | if (ape->seektablelength > 0) { |
||
265 | ape->seektable = av_malloc(ape->seektablelength); |
||
266 | for (i = 0; i < ape->seektablelength / sizeof(uint32_t); i++) |
||
267 | b7effd4e | Anton Khirnov | ape->seektable[i] = avio_rl32(pb); |
268 | bf4a1f17 | Kostya Shishkov | } |
269 | |||
270 | ape->frames[0].pos = ape->firstframe;
|
||
271 | ape->frames[0].nblocks = ape->blocksperframe;
|
||
272 | ape->frames[0].skip = 0; |
||
273 | for (i = 1; i < ape->totalframes; i++) { |
||
274 | ape->frames[i].pos = ape->seektable[i]; //ape->frames[i-1].pos + ape->blocksperframe;
|
||
275 | ape->frames[i].nblocks = ape->blocksperframe; |
||
276 | ape->frames[i - 1].size = ape->frames[i].pos - ape->frames[i - 1].pos; |
||
277 | ape->frames[i].skip = (ape->frames[i].pos - ape->frames[0].pos) & 3; |
||
278 | } |
||
279 | ape->frames[ape->totalframes - 1].size = ape->finalframeblocks * 4; |
||
280 | ape->frames[ape->totalframes - 1].nblocks = ape->finalframeblocks;
|
||
281 | |||
282 | for (i = 0; i < ape->totalframes; i++) { |
||
283 | if(ape->frames[i].skip){
|
||
284 | ape->frames[i].pos -= ape->frames[i].skip; |
||
285 | ape->frames[i].size += ape->frames[i].skip; |
||
286 | } |
||
287 | ape->frames[i].size = (ape->frames[i].size + 3) & ~3; |
||
288 | } |
||
289 | |||
290 | |||
291 | 76b9092f | Benoit Fouet | ape_dumpinfo(s, ape); |
292 | bf4a1f17 | Kostya Shishkov | |
293 | 781ad2f5 | Benjamin Zores | /* try to read APE tags */
|
294 | if (!url_is_streamed(pb)) {
|
||
295 | 191e34cd | Kostya Shishkov | ff_ape_parse_tag(s); |
296 | 6b4aa5da | Anton Khirnov | avio_seek(pb, 0, SEEK_SET);
|
297 | 781ad2f5 | Benjamin Zores | } |
298 | |||
299 | bf4a1f17 | Kostya Shishkov | av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype); |
300 | |||
301 | /* now we are ready: build format streams */
|
||
302 | st = av_new_stream(s, 0);
|
||
303 | if (!st)
|
||
304 | return -1; |
||
305 | |||
306 | total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks; |
||
307 | |||
308 | 72415b2a | Stefano Sabatini | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
309 | bf4a1f17 | Kostya Shishkov | st->codec->codec_id = CODEC_ID_APE; |
310 | st->codec->codec_tag = MKTAG('A', 'P', 'E', ' '); |
||
311 | st->codec->channels = ape->channels; |
||
312 | st->codec->sample_rate = ape->samplerate; |
||
313 | dd1c8f3e | Luca Abeni | st->codec->bits_per_coded_sample = ape->bps; |
314 | bf4a1f17 | Kostya Shishkov | st->codec->frame_size = MAC_SUBFRAME_SIZE; |
315 | |||
316 | st->nb_frames = ape->totalframes; |
||
317 | 0fc07ad9 | David Conrad | st->start_time = 0;
|
318 | st->duration = total_blocks / MAC_SUBFRAME_SIZE; |
||
319 | bf4a1f17 | Kostya Shishkov | av_set_pts_info(st, 64, MAC_SUBFRAME_SIZE, ape->samplerate);
|
320 | |||
321 | st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE); |
||
322 | st->codec->extradata_size = APE_EXTRADATA_SIZE; |
||
323 | AV_WL16(st->codec->extradata + 0, ape->fileversion);
|
||
324 | AV_WL16(st->codec->extradata + 2, ape->compressiontype);
|
||
325 | AV_WL16(st->codec->extradata + 4, ape->formatflags);
|
||
326 | |||
327 | pts = 0;
|
||
328 | for (i = 0; i < ape->totalframes; i++) { |
||
329 | ape->frames[i].pts = pts; |
||
330 | av_add_index_entry(st, ape->frames[i].pos, ape->frames[i].pts, 0, 0, AVINDEX_KEYFRAME); |
||
331 | pts += ape->blocksperframe / MAC_SUBFRAME_SIZE; |
||
332 | } |
||
333 | |||
334 | return 0; |
||
335 | } |
||
336 | |||
337 | static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) |
||
338 | { |
||
339 | int ret;
|
||
340 | int nblocks;
|
||
341 | APEContext *ape = s->priv_data; |
||
342 | uint32_t extra_size = 8;
|
||
343 | |||
344 | 66e5b1df | Anton Khirnov | if (s->pb->eof_reached)
|
345 | 5ae092ee | Stefano Sabatini | return AVERROR(EIO);
|
346 | bf4a1f17 | Kostya Shishkov | if (ape->currentframe > ape->totalframes)
|
347 | 5ae092ee | Stefano Sabatini | return AVERROR(EIO);
|
348 | bf4a1f17 | Kostya Shishkov | |
349 | 6b4aa5da | Anton Khirnov | avio_seek (s->pb, ape->frames[ape->currentframe].pos, SEEK_SET); |
350 | bf4a1f17 | Kostya Shishkov | |
351 | /* Calculate how many blocks there are in this frame */
|
||
352 | if (ape->currentframe == (ape->totalframes - 1)) |
||
353 | nblocks = ape->finalframeblocks; |
||
354 | else
|
||
355 | nblocks = ape->blocksperframe; |
||
356 | |||
357 | if (av_new_packet(pkt, ape->frames[ape->currentframe].size + extra_size) < 0) |
||
358 | 2874c81c | Stefano Sabatini | return AVERROR(ENOMEM);
|
359 | bf4a1f17 | Kostya Shishkov | |
360 | AV_WL32(pkt->data , nblocks); |
||
361 | AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip);
|
||
362 | b7effd4e | Anton Khirnov | ret = avio_read(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size); |
363 | bf4a1f17 | Kostya Shishkov | |
364 | pkt->pts = ape->frames[ape->currentframe].pts; |
||
365 | pkt->stream_index = 0;
|
||
366 | |||
367 | /* note: we need to modify the packet size here to handle the last
|
||
368 | packet */
|
||
369 | pkt->size = ret + extra_size; |
||
370 | |||
371 | ape->currentframe++; |
||
372 | |||
373 | return 0; |
||
374 | } |
||
375 | |||
376 | static int ape_read_close(AVFormatContext * s) |
||
377 | { |
||
378 | APEContext *ape = s->priv_data; |
||
379 | |||
380 | av_freep(&ape->frames); |
||
381 | av_freep(&ape->seektable); |
||
382 | return 0; |
||
383 | } |
||
384 | |||
385 | static int ape_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
||
386 | { |
||
387 | AVStream *st = s->streams[stream_index]; |
||
388 | APEContext *ape = s->priv_data; |
||
389 | int index = av_index_search_timestamp(st, timestamp, flags);
|
||
390 | |||
391 | if (index < 0) |
||
392 | return -1; |
||
393 | |||
394 | ape->currentframe = index; |
||
395 | return 0; |
||
396 | } |
||
397 | |||
398 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_ape_demuxer = { |
399 | bf4a1f17 | Kostya Shishkov | "ape",
|
400 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("Monkey's Audio"),
|
401 | bf4a1f17 | Kostya Shishkov | sizeof(APEContext),
|
402 | ape_probe, |
||
403 | ape_read_header, |
||
404 | ape_read_packet, |
||
405 | ape_read_close, |
||
406 | ape_read_seek, |
||
407 | .extensions = "ape,apl,mac"
|
||
408 | }; |