Commit | Line | Data |
---|---|---|
6cea494e ZK |
1 | /* |
2 | * MOV decoder. | |
19720f15 | 3 | * Copyright (c) 2001 Fabrice Bellard. |
6cea494e | 4 | * |
19720f15 FB |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2 of the License, or (at your option) any later version. | |
6cea494e | 9 | * |
19720f15 | 10 | * This library is distributed in the hope that it will be useful, |
6cea494e | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19720f15 FB |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. | |
6cea494e | 14 | * |
19720f15 FB |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
6cea494e | 18 | */ |
d957696f MN |
19 | |
20 | #include <limits.h> | |
21 | ||
6cea494e ZK |
22 | #include "avformat.h" |
23 | #include "avi.h" | |
24 | ||
0147f198 FR |
25 | #ifdef CONFIG_ZLIB |
26 | #include <zlib.h> | |
27 | #endif | |
28 | ||
6cea494e ZK |
29 | /* |
30 | * First version by Francois Revol revol@free.fr | |
baf25c9d | 31 | * Seek function by Gael Chardon gael.dev@4now.net |
5ca1d879 | 32 | * |
6cea494e | 33 | * Features and limitations: |
5ca1d879 | 34 | * - reads most of the QT files I have (at least the structure), |
6cea494e | 35 | * the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement. |
0147f198 | 36 | * FIXED, Francois Revol, 07/17/2002 |
6cea494e ZK |
37 | * - ffmpeg has nearly none of the usual QuickTime codecs, |
38 | * although I succesfully dumped raw and mp3 audio tracks off .mov files. | |
39 | * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html | |
40 | * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes | |
41 | * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at | |
42 | * http://mpeg.telecomitalialab.com/faq.htm | |
43 | * - the code is quite ugly... maybe I won't do it recursive next time :-) | |
baf25c9d | 44 | * - seek is not supported with files that contain edit list |
5ca1d879 | 45 | * |
6cea494e ZK |
46 | * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ |
47 | * when coding this :) (it's a writer anyway) | |
5ca1d879 | 48 | * |
6cea494e ZK |
49 | * Reference documents: |
50 | * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt | |
51 | * Apple: | |
baf25c9d GC |
52 | * http://developer.apple.com/documentation/QuickTime/QTFF/ |
53 | * http://developer.apple.com/documentation/QuickTime/PDF/QTFileFormat.pdf | |
6cea494e ZK |
54 | * QuickTime is a trademark of Apple (AFAIK :)) |
55 | */ | |
56 | ||
c9a65ca8 | 57 | //#define DEBUG |
9ed83b0a ZK |
58 | #ifdef DEBUG |
59 | #include <stdio.h> | |
60 | #include <fcntl.h> | |
61 | #endif | |
6cea494e | 62 | |
b595afaa MM |
63 | #include "qtpalette.h" |
64 | ||
baf25c9d GC |
65 | |
66 | /* Allows seeking (MOV_SPLIT_CHUNKS should also be defined) */ | |
67 | #define MOV_SEEK | |
68 | ||
3ffe3793 FR |
69 | /* allows chunk splitting - should work now... */ |
70 | /* in case you can't read a file, try commenting */ | |
71 | #define MOV_SPLIT_CHUNKS | |
72 | ||
14342fd5 JC |
73 | /* Special handling for movies created with Minolta Dimaxe Xi*/ |
74 | /* this fix should not interfere with other .mov files, but just in case*/ | |
75 | #define MOV_MINOLTA_FIX | |
76 | ||
6cea494e ZK |
77 | /* some streams in QT (and in MP4 mostly) aren't either video nor audio */ |
78 | /* so we first list them as this, then clean up the list of streams we give back, */ | |
79 | /* getting rid of these */ | |
b6a17df4 | 80 | #define CODEC_TYPE_MOV_OTHER (enum CodecType) 2 |
6cea494e | 81 | |
a266644f | 82 | static const CodecTag mov_video_tags[] = { |
6cea494e | 83 | /* { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */ |
0147f198 FR |
84 | /* { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, *//* Uncompressed RGB */ |
85 | /* { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, *//* Uncompressed YUV422 */ | |
53e27dd5 | 86 | /* { CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'U', 'I') }, *//* YUV with alpha-channel (AVID Uncompressed) */ |
6cea494e ZK |
87 | /* Graphics */ |
88 | /* Animation */ | |
89 | /* Apple video */ | |
90 | /* Kodak Photo CD */ | |
3ffe3793 | 91 | { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */ |
6cea494e | 92 | { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */ |
3ffe3793 | 93 | { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */ |
6cea494e | 94 | { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */ |
53e27dd5 SB |
95 | { CODEC_ID_MJPEG, MKTAG('A', 'V', 'D', 'J') }, /* MJPEG with alpha-channel (AVID JFIF meridien compressed) */ |
96 | /* { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, *//* MJPEG with alpha-channel (AVID ABVB/Truevision NuVista) */ | |
6cea494e ZK |
97 | /* { CODEC_ID_GIF, MKTAG('g', 'i', 'f', ' ') }, *//* embedded gif files as frames (usually one "click to play movie" frame) */ |
98 | /* Sorenson video */ | |
0147f198 FR |
99 | { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') }, /* Sorenson Video v1 */ |
100 | { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') }, /* Sorenson Video v1 */ | |
3ffe3793 | 101 | { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', 'i') }, /* Sorenson Video v1 (from QT specs)*/ |
8b82a956 | 102 | { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') }, /* Sorenson Video v3 */ |
0e7eed09 | 103 | { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, |
6cea494e | 104 | { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, /* OpenDiVX *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */ |
8dafdb88 | 105 | { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, |
6cea494e | 106 | /* { CODEC_ID_, MKTAG('I', 'V', '5', '0') }, *//* Indeo 5.0 */ |
0147f198 | 107 | { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, /* H263 */ |
25fa62e1 | 108 | { CODEC_ID_H263, MKTAG('s', '2', '6', '3') }, /* H263 ?? works */ |
e1687cc0 FB |
109 | { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */ |
110 | { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */ | |
53e27dd5 | 111 | /* { CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, *//* AVID dv */ |
d86053a4 | 112 | { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, /* On2 VP3 */ |
2fdf638b MM |
113 | { CODEC_ID_RPZA, MKTAG('r', 'p', 'z', 'a') }, /* Apple Video (RPZA) */ |
114 | { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') }, /* Cinepak */ | |
1dc1ed99 | 115 | { CODEC_ID_8BPS, MKTAG('8', 'B', 'P', 'S') }, /* Planar RGB (8BPS) */ |
b595afaa | 116 | { CODEC_ID_SMC, MKTAG('s', 'm', 'c', ' ') }, /* Apple Graphics (SMC) */ |
070ed1bc | 117 | { CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') }, /* Apple Animation (RLE) */ |
5ca1d879 | 118 | { CODEC_ID_NONE, 0 }, |
6cea494e ZK |
119 | }; |
120 | ||
a266644f | 121 | static const CodecTag mov_audio_tags[] = { |
6cea494e ZK |
122 | /* { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, *//* uncompressed */ |
123 | { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */ | |
5ca1d879 | 124 | /* { CODEC_ID_PCM_S8, MKTAG('t', 'w', 'o', 's') },*/ /* 8 bits */ |
5cd62665 | 125 | { CODEC_ID_PCM_U8, MKTAG('r', 'a', 'w', ' ') }, /* 8 bits unsigned */ |
6cea494e ZK |
126 | { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /* */ |
127 | { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /* */ | |
128 | { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /* */ | |
0147f198 | 129 | { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, /* IMA-4 ADPCM */ |
3f95e843 FR |
130 | { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, /* Macintosh Audio Compression and Expansion 3:1 */ |
131 | { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, /* Macintosh Audio Compression and Expansion 6:1 */ | |
6cea494e ZK |
132 | |
133 | { CODEC_ID_MP2, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */ | |
134 | { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */ | |
135 | { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */ | |
136 | /* { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */ | |
137 | /* MP4 tags */ | |
4cb3f3b6 | 138 | { CODEC_ID_MPEG4AAC, MKTAG('m', 'p', '4', 'a') }, /* MPEG-4 AAC */ |
5ca1d879 | 139 | /* The standard for mpeg4 audio is still not normalised AFAIK anyway */ |
891f64b3 | 140 | { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') }, /* AMR-NB 3gp */ |
d663a1fd | 141 | { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') }, /* AMR-WB 3gp */ |
8dafdb88 | 142 | { CODEC_ID_AC3, MKTAG('m', 's', 0x20, 0x00) }, /* Dolby AC-3 */ |
5ca1d879 | 143 | { CODEC_ID_NONE, 0 }, |
6cea494e ZK |
144 | }; |
145 | ||
146 | /* the QuickTime file format is quite convoluted... | |
147 | * it has lots of index tables, each indexing something in another one... | |
148 | * Here we just use what is needed to read the chunks | |
149 | */ | |
150 | ||
151 | typedef struct MOV_sample_to_chunk_tbl { | |
152 | long first; | |
153 | long count; | |
154 | long id; | |
155 | } MOV_sample_to_chunk_tbl; | |
156 | ||
5cd62665 | 157 | typedef struct { |
5ca1d879 ZK |
158 | uint32_t type; |
159 | int64_t offset; | |
160 | int64_t size; /* total size (excluding the size and type fields) */ | |
161 | } MOV_atom_t; | |
162 | ||
163 | typedef struct { | |
164 | int seed; | |
165 | int flags; | |
166 | int size; | |
167 | void* clrs; | |
168 | } MOV_ctab_t; | |
169 | ||
170 | typedef struct { | |
5cd62665 ZK |
171 | uint8_t version; |
172 | uint32_t flags; // 24bit | |
173 | ||
174 | /* 0x03 ESDescrTag */ | |
175 | uint16_t es_id; | |
176 | #define MP4ODescrTag 0x01 | |
177 | #define MP4IODescrTag 0x02 | |
178 | #define MP4ESDescrTag 0x03 | |
179 | #define MP4DecConfigDescrTag 0x04 | |
180 | #define MP4DecSpecificDescrTag 0x05 | |
181 | #define MP4SLConfigDescrTag 0x06 | |
182 | #define MP4ContentIdDescrTag 0x07 | |
183 | #define MP4SupplContentIdDescrTag 0x08 | |
184 | #define MP4IPIPtrDescrTag 0x09 | |
185 | #define MP4IPMPPtrDescrTag 0x0A | |
186 | #define MP4IPMPDescrTag 0x0B | |
187 | #define MP4RegistrationDescrTag 0x0D | |
188 | #define MP4ESIDIncDescrTag 0x0E | |
189 | #define MP4ESIDRefDescrTag 0x0F | |
190 | #define MP4FileIODescrTag 0x10 | |
191 | #define MP4FileODescrTag 0x11 | |
192 | #define MP4ExtProfileLevelDescrTag 0x13 | |
193 | #define MP4ExtDescrTagsStart 0x80 | |
194 | #define MP4ExtDescrTagsEnd 0xFE | |
195 | uint8_t stream_priority; | |
196 | ||
197 | /* 0x04 DecConfigDescrTag */ | |
198 | uint8_t object_type_id; | |
199 | uint8_t stream_type; | |
200 | /* XXX: really streamType is | |
201 | * only 6bit, followed by: | |
202 | * 1bit upStream | |
203 | * 1bit reserved | |
204 | */ | |
205 | uint32_t buffer_size_db; // 24 | |
206 | uint32_t max_bitrate; | |
207 | uint32_t avg_bitrate; | |
208 | ||
209 | /* 0x05 DecSpecificDescrTag */ | |
210 | uint8_t decoder_cfg_len; | |
211 | uint8_t *decoder_cfg; | |
212 | ||
213 | /* 0x06 SLConfigDescrTag */ | |
214 | uint8_t sl_config_len; | |
215 | uint8_t *sl_config; | |
216 | } MOV_esds_t; | |
217 | ||
b6a17df4 ZK |
218 | struct MOVParseTableEntry; |
219 | ||
6cea494e ZK |
220 | typedef struct MOVStreamContext { |
221 | int ffindex; /* the ffmpeg stream id */ | |
222 | int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */ | |
223 | long next_chunk; | |
224 | long chunk_count; | |
0c1a9eda | 225 | int64_t *chunk_offsets; |
baf25c9d GC |
226 | int32_t stts_count; |
227 | uint64_t *stts_data; /* concatenated data from the time-to-sample atom (count|duration) */ | |
228 | int32_t edit_count; /* number of 'edit' (elst atom) */ | |
6cea494e ZK |
229 | long sample_to_chunk_sz; |
230 | MOV_sample_to_chunk_tbl *sample_to_chunk; | |
3ffe3793 | 231 | long sample_to_chunk_index; |
6cea494e ZK |
232 | long sample_size; |
233 | long sample_count; | |
234 | long *sample_sizes; | |
247d56f5 BB |
235 | long keyframe_count; |
236 | long *keyframes; | |
5cd62665 | 237 | int time_scale; |
3ffe3793 FR |
238 | long current_sample; |
239 | long left_in_chunk; /* how many samples before next chunk */ | |
0e7eed09 FB |
240 | /* specific MPEG4 header which is added at the beginning of the stream */ |
241 | int header_len; | |
242 | uint8_t *header_data; | |
5ca1d879 | 243 | MOV_esds_t esds; |
6cea494e ZK |
244 | } MOVStreamContext; |
245 | ||
246 | typedef struct MOVContext { | |
247 | int mp4; /* set to 1 as soon as we are sure that the file is an .mp4 file (even some header parsing depends on this) */ | |
248 | AVFormatContext *fc; | |
5cd62665 ZK |
249 | int time_scale; |
250 | int duration; /* duration of the longest track */ | |
6cea494e ZK |
251 | int found_moov; /* when both 'moov' and 'mdat' sections has been found */ |
252 | int found_mdat; /* we suppose we have enough data to read the file */ | |
0c1a9eda ZK |
253 | int64_t mdat_size; |
254 | int64_t mdat_offset; | |
6cea494e ZK |
255 | int total_streams; |
256 | /* some streams listed here aren't presented to the ffmpeg API, since they aren't either video nor audio | |
257 | * but we need the info to be able to skip data from those streams in the 'mdat' section | |
258 | */ | |
259 | MOVStreamContext *streams[MAX_STREAMS]; | |
5cd62665 | 260 | |
0c1a9eda | 261 | int64_t next_chunk_offset; |
5cd62665 | 262 | MOVStreamContext *partial; /* != 0 : there is still to read in the current chunk */ |
5ca1d879 ZK |
263 | int ctab_size; |
264 | MOV_ctab_t **ctab; /* color tables */ | |
b6a17df4 ZK |
265 | const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */ |
266 | /* NOTE: for recursion save to/ restore from local variable! */ | |
b595afaa MM |
267 | |
268 | AVPaletteControl palette_control; | |
6cea494e ZK |
269 | } MOVContext; |
270 | ||
271 | ||
6cea494e ZK |
272 | /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */ |
273 | ||
274 | /* those functions parse an atom */ | |
275 | /* return code: | |
276 | 1: found what I wanted, exit | |
277 | 0: continue to parse next atom | |
278 | -1: error occured, exit | |
279 | */ | |
5ca1d879 | 280 | typedef int (*mov_parse_function)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom); |
6cea494e ZK |
281 | |
282 | /* links atom IDs to parse functions */ | |
283 | typedef struct MOVParseTableEntry { | |
0c1a9eda | 284 | uint32_t type; |
6cea494e ZK |
285 | mov_parse_function func; |
286 | } MOVParseTableEntry; | |
287 | ||
5ca1d879 ZK |
288 | #ifdef DEBUG |
289 | /* | |
290 | * XXX: static sux, even more in a multithreaded environment... | |
291 | * Avoid them. This is here just to help debugging. | |
292 | */ | |
293 | static int debug_indent = 0; | |
294 | void print_atom(const char *str, MOV_atom_t atom) | |
295 | { | |
296 | unsigned int tag, i; | |
297 | tag = (unsigned int) atom.type; | |
298 | i=debug_indent; | |
299 | if(tag == 0) tag = MKTAG('N', 'U', 'L', 'L'); | |
300 | while(i--) | |
baf25c9d GC |
301 | av_log(NULL, AV_LOG_DEBUG, "|"); |
302 | av_log(NULL, AV_LOG_DEBUG, "parse:"); | |
303 | av_log(NULL, AV_LOG_DEBUG, " %s: tag=%c%c%c%c offset=0x%x size=0x%x\n", | |
5ca1d879 ZK |
304 | str, tag & 0xff, |
305 | (tag >> 8) & 0xff, | |
306 | (tag >> 16) & 0xff, | |
307 | (tag >> 24) & 0xff, | |
308 | (unsigned int)atom.offset, | |
309 | (unsigned int)atom.size); | |
310 | assert((unsigned int)atom.size < 0x7fffffff);// catching errors | |
311 | } | |
312 | #else | |
313 | #define print_atom(a,b) | |
314 | #endif | |
315 | ||
316 | ||
317 | static int mov_read_leaf(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
6cea494e | 318 | { |
5ca1d879 | 319 | print_atom("leaf", atom); |
b6a17df4 | 320 | |
5ca1d879 ZK |
321 | if (atom.size>1) |
322 | url_fskip(pb, atom.size); | |
323 | /* url_seek(pb, atom_offset+atom.size, SEEK_SET); */ | |
6cea494e ZK |
324 | return 0; |
325 | } | |
326 | ||
5ca1d879 | 327 | static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
6cea494e | 328 | { |
b6a17df4 | 329 | int64_t total_size = 0; |
5ca1d879 | 330 | MOV_atom_t a; |
6cea494e ZK |
331 | int i; |
332 | int err = 0; | |
5ca1d879 | 333 | |
6cea494e | 334 | #ifdef DEBUG |
5ca1d879 | 335 | print_atom("default", atom); |
6cea494e ZK |
336 | debug_indent++; |
337 | #endif | |
5cd62665 | 338 | |
5ca1d879 | 339 | a.offset = atom.offset; |
6cea494e | 340 | |
9ed83b0a ZK |
341 | if (atom.size < 0) |
342 | atom.size = 0x7fffffffffffffffLL; | |
5ca1d879 ZK |
343 | while(((total_size + 8) < atom.size) && !url_feof(pb) && !err) { |
344 | a.size = atom.size; | |
345 | a.type=0L; | |
346 | if(atom.size >= 8) { | |
347 | a.size = get_be32(pb); | |
348 | a.type = get_le32(pb); | |
6cea494e | 349 | } |
5cd62665 | 350 | total_size += 8; |
5ca1d879 | 351 | a.offset += 8; |
baf25c9d | 352 | //av_log(NULL, AV_LOG_DEBUG, "type: %08x %.4s sz: %Lx %Lx %Lx\n", type, (char*)&type, size, atom.size, total_size); |
5ca1d879 ZK |
353 | if (a.size == 1) { /* 64 bit extended size */ |
354 | a.size = get_be64(pb) - 8; | |
355 | a.offset += 8; | |
356 | total_size += 8; | |
6cea494e | 357 | } |
5ca1d879 ZK |
358 | if (a.size == 0) { |
359 | a.size = atom.size - total_size; | |
360 | if (a.size <= 8) | |
5cd62665 ZK |
361 | break; |
362 | } | |
5ca1d879 ZK |
363 | for (i = 0; c->parse_table[i].type != 0L |
364 | && c->parse_table[i].type != a.type; i++) | |
5cd62665 ZK |
365 | /* empty */; |
366 | ||
5ca1d879 | 367 | a.size -= 8; |
baf25c9d | 368 | // av_log(NULL, AV_LOG_DEBUG, " i=%ld\n", i); |
b6a17df4 | 369 | if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ |
5ca1d879 | 370 | // url_seek(pb, atom.offset+atom.size, SEEK_SET); |
6cea494e | 371 | #ifdef DEBUG |
5ca1d879 | 372 | print_atom("unknown", a); |
6cea494e | 373 | #endif |
5ca1d879 | 374 | url_fskip(pb, a.size); |
b6a17df4 ZK |
375 | } else { |
376 | #ifdef DEBUG | |
377 | //char b[5] = { type & 0xff, (type >> 8) & 0xff, (type >> 16) & 0xff, (type >> 24) & 0xff, 0 }; | |
378 | //print_atom(b, type, offset, size); | |
379 | #endif | |
5ca1d879 | 380 | err = (c->parse_table[i].func)(c, pb, a); |
b6a17df4 | 381 | } |
6cea494e | 382 | |
5ca1d879 ZK |
383 | a.offset += a.size; |
384 | total_size += a.size; | |
6cea494e ZK |
385 | } |
386 | ||
5ca1d879 | 387 | if (!err && total_size < atom.size && atom.size < 0x7ffff) { |
baf25c9d | 388 | //av_log(NULL, AV_LOG_DEBUG, "RESET %Ld %Ld err:%d\n", atom.size, total_size, err); |
5ca1d879 | 389 | url_fskip(pb, atom.size - total_size); |
5cd62665 ZK |
390 | } |
391 | ||
6cea494e ZK |
392 | #ifdef DEBUG |
393 | debug_indent--; | |
394 | #endif | |
395 | return err; | |
396 | } | |
397 | ||
5ca1d879 | 398 | static int mov_read_ctab(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
6cea494e | 399 | { |
5ca1d879 ZK |
400 | unsigned int len; |
401 | MOV_ctab_t *t; | |
402 | //url_fskip(pb, atom.size); // for now | |
403 | c->ctab = av_realloc(c->ctab, ++c->ctab_size); | |
404 | t = c->ctab[c->ctab_size]; | |
405 | t->seed = get_be32(pb); | |
406 | t->flags = get_be16(pb); | |
407 | t->size = get_be16(pb) + 1; | |
408 | len = 2 * t->size * 4; | |
409 | if (len > 0) { | |
410 | t->clrs = av_malloc(len); // 16bit A R G B | |
411 | if (t->clrs) | |
412 | get_buffer(pb, t->clrs, len); | |
3ffe3793 | 413 | } |
5cd62665 | 414 | |
0147f198 FR |
415 | return 0; |
416 | } | |
417 | ||
5ca1d879 | 418 | static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
6cea494e | 419 | { |
5ca1d879 | 420 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; |
3ffe3793 | 421 | int len = 0; |
0c1a9eda | 422 | uint32_t type; |
0c1a9eda | 423 | uint32_t ctype; |
b6a17df4 | 424 | |
5ca1d879 | 425 | print_atom("hdlr", atom); |
6cea494e ZK |
426 | |
427 | get_byte(pb); /* version */ | |
428 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
429 | ||
430 | /* component type */ | |
431 | ctype = get_le32(pb); | |
432 | type = get_le32(pb); /* component subtype */ | |
433 | ||
434 | #ifdef DEBUG | |
baf25c9d GC |
435 | av_log(NULL, AV_LOG_DEBUG, "ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype); |
436 | av_log(NULL, AV_LOG_DEBUG, "stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); | |
6cea494e ZK |
437 | #endif |
438 | #ifdef DEBUG | |
439 | /* XXX: yeah this is ugly... */ | |
440 | if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */ | |
441 | if(type == MKTAG('v', 'i', 'd', 'e')) | |
442 | puts("hdlr: vide"); | |
443 | else if(type == MKTAG('s', 'o', 'u', 'n')) | |
444 | puts("hdlr: soun"); | |
445 | } else if(ctype == 0) { /* MP4 */ | |
446 | if(type == MKTAG('v', 'i', 'd', 'e')) | |
447 | puts("hdlr: vide"); | |
448 | else if(type == MKTAG('s', 'o', 'u', 'n')) | |
449 | puts("hdlr: soun"); | |
450 | else if(type == MKTAG('o', 'd', 's', 'm')) | |
451 | puts("hdlr: odsm"); | |
452 | else if(type == MKTAG('s', 'd', 's', 'm')) | |
453 | puts("hdlr: sdsm"); | |
454 | } else puts("hdlr: meta"); | |
455 | #endif | |
456 | ||
457 | if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */ | |
0147f198 FR |
458 | /* helps parsing the string hereafter... */ |
459 | c->mp4 = 0; | |
6cea494e ZK |
460 | if(type == MKTAG('v', 'i', 'd', 'e')) |
461 | st->codec.codec_type = CODEC_TYPE_VIDEO; | |
462 | else if(type == MKTAG('s', 'o', 'u', 'n')) | |
463 | st->codec.codec_type = CODEC_TYPE_AUDIO; | |
464 | } else if(ctype == 0) { /* MP4 */ | |
0147f198 FR |
465 | /* helps parsing the string hereafter... */ |
466 | c->mp4 = 1; | |
6cea494e ZK |
467 | if(type == MKTAG('v', 'i', 'd', 'e')) |
468 | st->codec.codec_type = CODEC_TYPE_VIDEO; | |
469 | else if(type == MKTAG('s', 'o', 'u', 'n')) | |
470 | st->codec.codec_type = CODEC_TYPE_AUDIO; | |
471 | } | |
472 | get_be32(pb); /* component manufacture */ | |
473 | get_be32(pb); /* component flags */ | |
474 | get_be32(pb); /* component flags mask */ | |
475 | ||
5ca1d879 | 476 | if(atom.size <= 24) |
6cea494e ZK |
477 | return 0; /* nothing left to read */ |
478 | /* XXX: MP4 uses a C string, not a pascal one */ | |
479 | /* component name */ | |
0147f198 FR |
480 | |
481 | if(c->mp4) { | |
482 | /* .mp4: C string */ | |
5ca1d879 | 483 | while(get_byte(pb) && (++len < (atom.size - 24))); |
0147f198 FR |
484 | } else { |
485 | /* .mov: PASCAL string */ | |
9ed83b0a ZK |
486 | #ifdef DEBUG |
487 | char* buf; | |
488 | #endif | |
0147f198 | 489 | len = get_byte(pb); |
5ca1d879 | 490 | #ifdef DEBUG |
b6a17df4 ZK |
491 | buf = (uint8_t*) av_malloc(len+1); |
492 | if (buf) { | |
493 | get_buffer(pb, buf, len); | |
b6a17df4 | 494 | buf[len] = '\0'; |
baf25c9d | 495 | av_log(NULL, AV_LOG_DEBUG, "**buf='%s'\n", buf); |
b6a17df4 ZK |
496 | av_free(buf); |
497 | } else | |
6cea494e | 498 | #endif |
5ca1d879 | 499 | url_fskip(pb, len); |
6cea494e | 500 | } |
5cd62665 | 501 | |
3c13647a | 502 | url_fskip(pb, atom.size - (url_ftell(pb) - atom.offset)); |
6cea494e ZK |
503 | return 0; |
504 | } | |
505 | ||
5ca1d879 | 506 | static int mov_mp4_read_descr_len(ByteIOContext *pb) |
0e7eed09 | 507 | { |
5cd62665 | 508 | int len = 0; |
5ca1d879 ZK |
509 | int count = 4; |
510 | while (count--) { | |
5cd62665 ZK |
511 | int c = get_byte(pb); |
512 | len = (len << 7) | (c & 0x7f); | |
5ca1d879 ZK |
513 | if (!(c & 0x80)) |
514 | break; | |
0e7eed09 FB |
515 | } |
516 | return len; | |
517 | } | |
518 | ||
5ca1d879 | 519 | static int mov_mp4_read_descr(ByteIOContext *pb, int *tag) |
0e7eed09 FB |
520 | { |
521 | int len; | |
522 | *tag = get_byte(pb); | |
5ca1d879 | 523 | len = mov_mp4_read_descr_len(pb); |
0e7eed09 | 524 | #ifdef DEBUG |
baf25c9d | 525 | av_log(NULL, AV_LOG_DEBUG, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); |
0e7eed09 FB |
526 | #endif |
527 | return len; | |
528 | } | |
529 | ||
5cd62665 ZK |
530 | static inline unsigned int get_be24(ByteIOContext *s) |
531 | { | |
532 | unsigned int val; | |
533 | val = get_byte(s) << 16; | |
534 | val |= get_byte(s) << 8; | |
535 | val |= get_byte(s); | |
536 | return val; | |
537 | } | |
538 | ||
5ca1d879 | 539 | static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
5cd62665 | 540 | { |
5cd62665 ZK |
541 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; |
542 | MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; | |
5ca1d879 | 543 | int64_t start_pos = url_ftell(pb); |
5cd62665 | 544 | int tag, len; |
b6a17df4 | 545 | |
5ca1d879 | 546 | print_atom("esds", atom); |
5cd62665 ZK |
547 | |
548 | /* Well, broken but suffisant for some MP4 streams */ | |
549 | get_be32(pb); /* version + flags */ | |
5ca1d879 | 550 | len = mov_mp4_read_descr(pb, &tag); |
5cd62665 ZK |
551 | if (tag == MP4ESDescrTag) { |
552 | get_be16(pb); /* ID */ | |
553 | get_byte(pb); /* priority */ | |
554 | } else | |
555 | get_be16(pb); /* ID */ | |
556 | ||
5ca1d879 | 557 | len = mov_mp4_read_descr(pb, &tag); |
5cd62665 ZK |
558 | if (tag == MP4DecConfigDescrTag) { |
559 | sc->esds.object_type_id = get_byte(pb); | |
5ca1d879 ZK |
560 | sc->esds.stream_type = get_byte(pb); |
561 | sc->esds.buffer_size_db = get_be24(pb); | |
5cd62665 ZK |
562 | sc->esds.max_bitrate = get_be32(pb); |
563 | sc->esds.avg_bitrate = get_be32(pb); | |
564 | ||
5ca1d879 | 565 | len = mov_mp4_read_descr(pb, &tag); |
baf25c9d | 566 | //av_log(NULL, AV_LOG_DEBUG, "LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate); |
5cd62665 ZK |
567 | if (tag == MP4DecSpecificDescrTag) { |
568 | #ifdef DEBUG | |
baf25c9d | 569 | av_log(NULL, AV_LOG_DEBUG, "Specific MPEG4 header len=%d\n", len); |
5cd62665 | 570 | #endif |
5ca1d879 ZK |
571 | st->codec.extradata = (uint8_t*) av_mallocz(len); |
572 | if (st->codec.extradata) { | |
573 | get_buffer(pb, st->codec.extradata, len); | |
574 | st->codec.extradata_size = len; | |
5cd62665 ZK |
575 | } |
576 | } | |
577 | } | |
578 | /* in any case, skip garbage */ | |
5ca1d879 | 579 | url_fskip(pb, atom.size - ((url_ftell(pb) - start_pos))); |
5cd62665 ZK |
580 | return 0; |
581 | } | |
582 | ||
5ca1d879 ZK |
583 | /* this atom contains actual media data */ |
584 | static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
6cea494e | 585 | { |
5ca1d879 ZK |
586 | print_atom("mdat", atom); |
587 | ||
588 | if(atom.size == 0) /* wrong one (MP4) */ | |
589 | return 0; | |
590 | c->found_mdat=1; | |
591 | c->mdat_offset = atom.offset; | |
592 | c->mdat_size = atom.size; | |
593 | if(c->found_moov) | |
594 | return 1; /* found both, just go */ | |
595 | url_fskip(pb, atom.size); | |
596 | return 0; /* now go for moov */ | |
597 | } | |
598 | ||
599 | /* this atom should contain all header atoms */ | |
600 | static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
601 | { | |
602 | int err; | |
b6a17df4 | 603 | |
5ca1d879 | 604 | print_atom("moov", atom); |
b6a17df4 | 605 | |
5ca1d879 ZK |
606 | err = mov_read_default(c, pb, atom); |
607 | /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */ | |
608 | /* so we don't parse the whole file if over a network */ | |
609 | c->found_moov=1; | |
610 | if(c->found_mdat) | |
611 | return 1; /* found both, just go */ | |
612 | return 0; /* now go for mdat */ | |
613 | } | |
614 | ||
615 | ||
616 | static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
617 | { | |
5ca1d879 ZK |
618 | print_atom("mdhd", atom); |
619 | ||
620 | get_byte(pb); /* version */ | |
621 | ||
622 | get_byte(pb); get_byte(pb); | |
623 | get_byte(pb); /* flags */ | |
624 | ||
625 | get_be32(pb); /* creation time */ | |
626 | get_be32(pb); /* modification time */ | |
627 | ||
baf25c9d | 628 | c->streams[c->fc->nb_streams-1]->time_scale = get_be32(pb); |
5ca1d879 ZK |
629 | |
630 | #ifdef DEBUG | |
baf25c9d | 631 | av_log(NULL, AV_LOG_DEBUG, "track[%i].time_scale = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->time_scale); /* time scale */ |
5ca1d879 ZK |
632 | #endif |
633 | get_be32(pb); /* duration */ | |
634 | ||
635 | get_be16(pb); /* language */ | |
636 | get_be16(pb); /* quality */ | |
637 | ||
638 | return 0; | |
639 | } | |
640 | ||
641 | static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
642 | { | |
643 | print_atom("mvhd", atom); | |
644 | ||
645 | get_byte(pb); /* version */ | |
646 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
647 | ||
648 | get_be32(pb); /* creation time */ | |
649 | get_be32(pb); /* modification time */ | |
650 | c->time_scale = get_be32(pb); /* time scale */ | |
651 | #ifdef DEBUG | |
baf25c9d | 652 | av_log(NULL, AV_LOG_DEBUG, "time scale = %i\n", c->time_scale); |
5ca1d879 ZK |
653 | #endif |
654 | c->duration = get_be32(pb); /* duration */ | |
655 | get_be32(pb); /* preferred scale */ | |
656 | ||
657 | get_be16(pb); /* preferred volume */ | |
658 | ||
659 | url_fskip(pb, 10); /* reserved */ | |
660 | ||
661 | url_fskip(pb, 36); /* display matrix */ | |
662 | ||
663 | get_be32(pb); /* preview time */ | |
664 | get_be32(pb); /* preview duration */ | |
665 | get_be32(pb); /* poster time */ | |
666 | get_be32(pb); /* selection time */ | |
667 | get_be32(pb); /* selection duration */ | |
668 | get_be32(pb); /* current time */ | |
669 | get_be32(pb); /* next track ID */ | |
670 | ||
671 | return 0; | |
672 | } | |
673 | ||
9ed83b0a ZK |
674 | static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
675 | { | |
676 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
677 | ||
678 | // currently SVQ3 decoder expect full STSD header - so let's fake it | |
679 | // this should be fixed and just SMI header should be passed | |
680 | av_free(st->codec.extradata); | |
681 | st->codec.extradata_size = 0x5a + atom.size; | |
682 | st->codec.extradata = (uint8_t*) av_mallocz(st->codec.extradata_size); | |
683 | ||
684 | if (st->codec.extradata) { | |
9ed83b0a ZK |
685 | strcpy(st->codec.extradata, "SVQ3"); // fake |
686 | get_buffer(pb, st->codec.extradata + 0x5a, atom.size); | |
baf25c9d | 687 | //av_log(NULL, AV_LOG_DEBUG, "Reading SMI %Ld %s\n", atom.size, (char*)st->codec.extradata + 0x5a); |
9ed83b0a ZK |
688 | } else |
689 | url_fskip(pb, atom.size); | |
690 | ||
691 | return 0; | |
692 | } | |
5ca1d879 ZK |
693 | |
694 | static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
695 | { | |
696 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
697 | MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; | |
698 | int entries, i; | |
699 | ||
700 | print_atom("stco", atom); | |
701 | ||
702 | get_byte(pb); /* version */ | |
703 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
704 | ||
705 | entries = get_be32(pb); | |
706 | sc->chunk_count = entries; | |
707 | sc->chunk_offsets = (int64_t*) av_malloc(entries * sizeof(int64_t)); | |
708 | if (!sc->chunk_offsets) | |
709 | return -1; | |
710 | if (atom.type == MKTAG('s', 't', 'c', 'o')) { | |
711 | for(i=0; i<entries; i++) { | |
712 | sc->chunk_offsets[i] = get_be32(pb); | |
713 | } | |
714 | } else if (atom.type == MKTAG('c', 'o', '6', '4')) { | |
715 | for(i=0; i<entries; i++) { | |
716 | sc->chunk_offsets[i] = get_be64(pb); | |
717 | } | |
718 | } else | |
719 | return -1; | |
720 | #ifdef DEBUG | |
721 | /* | |
722 | for(i=0; i<entries; i++) { | |
baf25c9d | 723 | av_log(NULL, AV_LOG_DEBUG, "chunk offset=0x%Lx\n", sc->chunk_offsets[i]); |
5ca1d879 ZK |
724 | } |
725 | */ | |
726 | #endif | |
727 | return 0; | |
728 | } | |
729 | ||
730 | static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
731 | { | |
732 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
fd6e513e | 733 | //MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; |
5ca1d879 ZK |
734 | int entries, frames_per_sample; |
735 | uint32_t format; | |
736 | ||
b595afaa MM |
737 | /* for palette traversal */ |
738 | int color_depth; | |
739 | int color_start; | |
740 | int color_count; | |
741 | int color_end; | |
742 | int color_index; | |
743 | int color_dec; | |
744 | int color_greyscale; | |
745 | unsigned char *color_table; | |
746 | int j; | |
747 | unsigned char r, g, b; | |
748 | ||
5ca1d879 | 749 | print_atom("stsd", atom); |
6cea494e ZK |
750 | |
751 | get_byte(pb); /* version */ | |
752 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
753 | ||
6cea494e ZK |
754 | entries = get_be32(pb); |
755 | ||
891f64b3 | 756 | while(entries--) { //Parsing Sample description table |
b6a17df4 | 757 | enum CodecID id; |
5ca1d879 | 758 | int size = get_be32(pb); /* size */ |
6cea494e | 759 | format = get_le32(pb); /* data format */ |
5cd62665 | 760 | |
6cea494e ZK |
761 | get_be32(pb); /* reserved */ |
762 | get_be16(pb); /* reserved */ | |
763 | get_be16(pb); /* index */ | |
0e7eed09 FB |
764 | |
765 | /* for MPEG4: set codec type by looking for it */ | |
766 | id = codec_get_id(mov_video_tags, format); | |
767 | if (id >= 0) { | |
768 | AVCodec *codec; | |
b6a17df4 | 769 | codec = avcodec_find_decoder(id); |
0e7eed09 | 770 | if (codec) |
b6a17df4 | 771 | st->codec.codec_type = codec->type; |
0e7eed09 FB |
772 | } |
773 | #ifdef DEBUG | |
baf25c9d | 774 | av_log(NULL, AV_LOG_DEBUG, "size=%d 4CC= %c%c%c%c codec_type=%d\n", |
5cd62665 | 775 | size, |
0e7eed09 FB |
776 | (format >> 0) & 0xff, |
777 | (format >> 8) & 0xff, | |
778 | (format >> 16) & 0xff, | |
779 | (format >> 24) & 0xff, | |
780 | st->codec.codec_type); | |
781 | #endif | |
5cd62665 | 782 | st->codec.codec_tag = format; |
5ca1d879 ZK |
783 | if(st->codec.codec_type==CODEC_TYPE_VIDEO) { |
784 | MOV_atom_t a = { 0, 0, 0 }; | |
785 | st->codec.codec_id = id; | |
6cea494e ZK |
786 | get_be16(pb); /* version */ |
787 | get_be16(pb); /* revision level */ | |
788 | get_be32(pb); /* vendor */ | |
789 | get_be32(pb); /* temporal quality */ | |
790 | get_be32(pb); /* spacial quality */ | |
791 | st->codec.width = get_be16(pb); /* width */ | |
792 | st->codec.height = get_be16(pb); /* height */ | |
0e7eed09 FB |
793 | #if 1 |
794 | if (st->codec.codec_id == CODEC_ID_MPEG4) { | |
795 | /* in some MPEG4 the width/height are not correct, so | |
796 | we ignore this info */ | |
797 | st->codec.width = 0; | |
798 | st->codec.height = 0; | |
799 | } | |
800 | #endif | |
6cea494e ZK |
801 | get_be32(pb); /* horiz resolution */ |
802 | get_be32(pb); /* vert resolution */ | |
803 | get_be32(pb); /* data size, always 0 */ | |
5cd62665 | 804 | frames_per_sample = get_be16(pb); /* frames per samples */ |
6cea494e | 805 | #ifdef DEBUG |
baf25c9d | 806 | av_log(NULL, AV_LOG_DEBUG, "frames/samples = %d\n", frames_per_sample); |
6cea494e | 807 | #endif |
b6a17df4 | 808 | get_buffer(pb, (uint8_t *)st->codec.codec_name, 32); /* codec name */ |
5cd62665 ZK |
809 | |
810 | st->codec.bits_per_sample = get_be16(pb); /* depth */ | |
811 | st->codec.color_table_id = get_be16(pb); /* colortable id */ | |
6cea494e | 812 | |
14342fd5 | 813 | /* These are set in mov_read_stts and might already be set! |
14bea432 MN |
814 | st->codec.frame_rate = 25; |
815 | st->codec.frame_rate_base = 1; | |
14342fd5 | 816 | */ |
5ca1d879 | 817 | size -= (16+8*4+2+32+2*2); |
5cd62665 ZK |
818 | #if 0 |
819 | while (size >= 8) { | |
5ca1d879 | 820 | MOV_atom_t a; |
0c1a9eda | 821 | int64_t start_pos; |
5cd62665 | 822 | |
5ca1d879 ZK |
823 | a.size = get_be32(pb); |
824 | a.type = get_le32(pb); | |
5cd62665 | 825 | size -= 8; |
0e7eed09 | 826 | #ifdef DEBUG |
baf25c9d | 827 | av_log(NULL, AV_LOG_DEBUG, "VIDEO: atom_type=%c%c%c%c atom.size=%Ld size_left=%d\n", |
5ca1d879 ZK |
828 | (a.type >> 0) & 0xff, |
829 | (a.type >> 8) & 0xff, | |
830 | (a.type >> 16) & 0xff, | |
831 | (a.type >> 24) & 0xff, | |
832 | a.size, size); | |
0e7eed09 FB |
833 | #endif |
834 | start_pos = url_ftell(pb); | |
835 | ||
5ca1d879 | 836 | switch(a.type) { |
0e7eed09 FB |
837 | case MKTAG('e', 's', 'd', 's'): |
838 | { | |
839 | int tag, len; | |
840 | /* Well, broken but suffisant for some MP4 streams */ | |
841 | get_be32(pb); /* version + flags */ | |
5ca1d879 | 842 | len = mov_mp4_read_descr(pb, &tag); |
0e7eed09 FB |
843 | if (tag == 0x03) { |
844 | /* MP4ESDescrTag */ | |
845 | get_be16(pb); /* ID */ | |
846 | get_byte(pb); /* priority */ | |
5ca1d879 | 847 | len = mov_mp4_read_descr(pb, &tag); |
0e7eed09 FB |
848 | if (tag != 0x04) |
849 | goto fail; | |
850 | /* MP4DecConfigDescrTag */ | |
851 | get_byte(pb); /* objectTypeId */ | |
852 | get_be32(pb); /* streamType + buffer size */ | |
5cd62665 | 853 | get_be32(pb); /* max bit rate */ |
0e7eed09 | 854 | get_be32(pb); /* avg bit rate */ |
891f64b3 | 855 | len = mov_mp4_read_descr(pb, &tag); |
0e7eed09 FB |
856 | if (tag != 0x05) |
857 | goto fail; | |
858 | /* MP4DecSpecificDescrTag */ | |
859 | #ifdef DEBUG | |
baf25c9d | 860 | av_log(NULL, AV_LOG_DEBUG, "Specific MPEG4 header len=%d\n", len); |
0e7eed09 FB |
861 | #endif |
862 | sc->header_data = av_mallocz(len); | |
863 | if (sc->header_data) { | |
864 | get_buffer(pb, sc->header_data, len); | |
5cd62665 | 865 | sc->header_len = len; |
0e7eed09 FB |
866 | } |
867 | } | |
868 | /* in any case, skip garbage */ | |
869 | } | |
870 | break; | |
871 | default: | |
872 | break; | |
873 | } | |
5cd62665 | 874 | fail: |
baf25c9d | 875 | av_log(NULL, AV_LOG_DEBUG, "ATOMENEWSIZE %Ld %d\n", atom.size, url_ftell(pb) - start_pos); |
5ca1d879 ZK |
876 | if (atom.size > 8) { |
877 | url_fskip(pb, (atom.size - 8) - | |
5cd62665 | 878 | ((url_ftell(pb) - start_pos))); |
5ca1d879 | 879 | size -= atom.size - 8; |
5cd62665 ZK |
880 | } |
881 | } | |
0e7eed09 FB |
882 | if (size > 0) { |
883 | /* unknown extension */ | |
884 | url_fskip(pb, size); | |
885 | } | |
5cd62665 | 886 | #else |
b595afaa MM |
887 | |
888 | /* figure out the palette situation */ | |
889 | color_depth = st->codec.bits_per_sample & 0x1F; | |
890 | color_greyscale = st->codec.bits_per_sample & 0x20; | |
891 | ||
892 | /* if the depth is 2, 4, or 8 bpp, file is palettized */ | |
893 | if ((color_depth == 2) || (color_depth == 4) || | |
894 | (color_depth == 8)) { | |
895 | ||
896 | if (color_greyscale) { | |
897 | ||
898 | /* compute the greyscale palette */ | |
899 | color_count = 1 << color_depth; | |
900 | color_index = 255; | |
901 | color_dec = 256 / (color_count - 1); | |
902 | for (j = 0; j < color_count; j++) { | |
903 | r = g = b = color_index; | |
904 | c->palette_control.palette[j] = | |
905 | (r << 16) | (g << 8) | (b); | |
906 | color_index -= color_dec; | |
907 | if (color_index < 0) | |
908 | color_index = 0; | |
909 | } | |
910 | ||
911 | } else if (st->codec.color_table_id & 0x08) { | |
912 | ||
913 | /* if flag bit 3 is set, use the default palette */ | |
914 | color_count = 1 << color_depth; | |
915 | if (color_depth == 2) | |
a90466f7 | 916 | color_table = ff_qt_default_palette_4; |
b595afaa | 917 | else if (color_depth == 4) |
a90466f7 | 918 | color_table = ff_qt_default_palette_16; |
b595afaa | 919 | else |
a90466f7 | 920 | color_table = ff_qt_default_palette_256; |
b595afaa MM |
921 | |
922 | for (j = 0; j < color_count; j++) { | |
923 | r = color_table[j * 4 + 0]; | |
924 | g = color_table[j * 4 + 1]; | |
925 | b = color_table[j * 4 + 2]; | |
926 | c->palette_control.palette[j] = | |
927 | (r << 16) | (g << 8) | (b); | |
928 | } | |
929 | ||
930 | } else { | |
931 | ||
932 | /* load the palette from the file */ | |
933 | color_start = get_be32(pb); | |
934 | color_count = get_be16(pb); | |
935 | color_end = get_be16(pb); | |
936 | for (j = color_start; j <= color_end; j++) { | |
937 | /* each R, G, or B component is 16 bits; | |
938 | * only use the top 8 bits; skip alpha bytes | |
939 | * up front */ | |
940 | get_byte(pb); | |
941 | get_byte(pb); | |
942 | r = get_byte(pb); | |
943 | get_byte(pb); | |
944 | g = get_byte(pb); | |
945 | get_byte(pb); | |
946 | b = get_byte(pb); | |
947 | get_byte(pb); | |
948 | c->palette_control.palette[j] = | |
949 | (r << 16) | (g << 8) | (b); | |
950 | } | |
951 | } | |
952 | ||
953 | st->codec.palctrl = &c->palette_control; | |
954 | st->codec.palctrl->palette_changed = 1; | |
955 | } else | |
956 | st->codec.palctrl = NULL; | |
957 | ||
5ca1d879 ZK |
958 | a.size = size; |
959 | mov_read_default(c, pb, a); | |
5cd62665 ZK |
960 | #endif |
961 | } else { | |
891f64b3 | 962 | st->codec.codec_id = codec_get_id(mov_audio_tags, format); |
d663a1fd | 963 | if(st->codec.codec_id==CODEC_ID_AMR_NB || st->codec.codec_id==CODEC_ID_AMR_WB) //from TS26.244 |
891f64b3 | 964 | { |
965 | #ifdef DEBUG | |
baf25c9d | 966 | av_log(NULL, AV_LOG_DEBUG, "AMR-NB or AMR-WB audio identified!!\n"); |
891f64b3 | 967 | #endif |
968 | get_be32(pb);get_be32(pb); //Reserved_8 | |
969 | get_be16(pb);//Reserved_2 | |
970 | get_be16(pb);//Reserved_2 | |
971 | get_be32(pb);//Reserved_4 | |
972 | get_be16(pb);//TimeScale | |
973 | get_be16(pb);//Reserved_2 | |
974 | ||
975 | //AMRSpecificBox.(10 bytes) | |
d663a1fd | 976 | |
891f64b3 | 977 | get_be32(pb); //size |
891f64b3 | 978 | get_be32(pb); //type=='damr' |
891f64b3 | 979 | get_be32(pb); //vendor |
980 | get_byte(pb); //decoder version | |
981 | get_be16(pb); //mode_set | |
982 | get_byte(pb); //mode_change_period | |
983 | get_byte(pb); //frames_per_sample | |
6cea494e | 984 | |
25c4950e | 985 | st->duration = AV_NOPTS_VALUE;//Not possible to get from this info, must count number of AMR frames |
d663a1fd MN |
986 | if(st->codec.codec_id==CODEC_ID_AMR_NB) |
987 | { | |
988 | st->codec.sample_rate=8000; | |
989 | st->codec.channels=1; | |
990 | } | |
991 | else //AMR-WB | |
992 | { | |
993 | st->codec.sample_rate=16000; | |
994 | st->codec.channels=1; | |
995 | } | |
891f64b3 | 996 | st->codec.bits_per_sample=16; |
997 | st->codec.bit_rate=0; /*It is not possible to tell this before we have | |
998 | an audio frame and even then every frame can be different*/ | |
5cd62665 | 999 | } |
14342fd5 JC |
1000 | else if( st->codec.codec_tag == MKTAG( 'm', 'p', '4', 's' )) |
1001 | { | |
1002 | //This is some stuff for the hint track, lets ignore it! | |
1003 | //Do some mp4 auto detect. | |
1004 | c->mp4=1; | |
1005 | size-=(16); | |
1006 | url_fskip(pb, size); /* The mp4s atom also contians a esds atom that we can skip*/ | |
1007 | } | |
2768b0d9 TR |
1008 | else if( st->codec.codec_tag == MKTAG( 'm', 'p', '4', 'a' )) |
1009 | { | |
1010 | /* Handle mp4 audio tag */ | |
1011 | get_be32(pb); /* version */ | |
1012 | get_be32(pb); | |
1013 | st->codec.channels = get_be16(pb); /* channels */ | |
1014 | st->codec.bits_per_sample = get_be16(pb); /* bits per sample */ | |
1015 | get_be32(pb); | |
1016 | st->codec.sample_rate = get_be16(pb); /* sample rate, not always correct */ | |
1017 | get_be16(pb); | |
1018 | c->mp4=1; | |
3ec34bfd | 1019 | { |
2768b0d9 TR |
1020 | MOV_atom_t a = { format, url_ftell(pb), size - (20 + 20 + 8) }; |
1021 | mov_read_default(c, pb, a); | |
3ec34bfd | 1022 | } |
2768b0d9 TR |
1023 | /* Get correct sample rate from extradata */ |
1024 | if(st->codec.extradata_size) { | |
1025 | const int samplerate_table[] = { | |
1026 | 96000, 88200, 64000, 48000, 44100, 32000, | |
1027 | 24000, 22050, 16000, 12000, 11025, 8000, | |
1028 | 7350, 0, 0, 0 | |
1029 | }; | |
1030 | unsigned char *px = st->codec.extradata; | |
1031 | // 5 bits objectTypeIndex, 4 bits sampleRateIndex, 4 bits channels | |
1032 | int samplerate_index = ((px[0] & 7) << 1) + ((px[1] >> 7) & 1); | |
1033 | st->codec.sample_rate = samplerate_table[samplerate_index]; | |
1034 | } | |
1035 | } | |
14342fd5 JC |
1036 | else if(size>=(16+20)) |
1037 | {//16 bytes read, reading atleast 20 more | |
1038 | #ifdef DEBUG | |
baf25c9d | 1039 | av_log(NULL, AV_LOG_DEBUG, "audio size=0x%X\n",size); |
14342fd5 JC |
1040 | #endif |
1041 | uint16_t version = get_be16(pb); /* version */ | |
891f64b3 | 1042 | get_be16(pb); /* revision level */ |
1043 | get_be32(pb); /* vendor */ | |
1044 | ||
1045 | st->codec.channels = get_be16(pb); /* channel count */ | |
1046 | st->codec.bits_per_sample = get_be16(pb); /* sample size */ | |
1047 | ||
1048 | /* handle specific s8 codec */ | |
1049 | get_be16(pb); /* compression id = 0*/ | |
1050 | get_be16(pb); /* packet size = 0 */ | |
1051 | ||
1052 | st->codec.sample_rate = ((get_be32(pb) >> 16)); | |
baf25c9d | 1053 | //av_log(NULL, AV_LOG_DEBUG, "CODECID %d %d %.4s\n", st->codec.codec_id, CODEC_ID_PCM_S16BE, (char*)&format); |
891f64b3 | 1054 | |
1055 | switch (st->codec.codec_id) { | |
1056 | case CODEC_ID_PCM_S16BE: | |
1057 | if (st->codec.bits_per_sample == 8) | |
1058 | st->codec.codec_id = CODEC_ID_PCM_S8; | |
1059 | /* fall */ | |
1060 | case CODEC_ID_PCM_U8: | |
1061 | st->codec.bit_rate = st->codec.sample_rate * 8; | |
1062 | break; | |
1063 | default: | |
1064 | ; | |
1065 | } | |
14342fd5 JC |
1066 | |
1067 | //Read QT version 1 fields. In version 0 theese dont exist | |
1068 | #ifdef DEBUG | |
baf25c9d GC |
1069 | av_log(NULL, AV_LOG_DEBUG, "version =%d mp4=%d\n",version,c->mp4); |
1070 | av_log(NULL, AV_LOG_DEBUG, "size-(16+20+16)=%d\n",size-(16+20+16)); | |
14342fd5 JC |
1071 | #endif |
1072 | if((version==1) && size>=(16+20+16)) | |
1073 | { | |
1074 | get_be32(pb); /* samples per packet */ | |
1075 | get_be32(pb); /* bytes per packet */ | |
1076 | get_be32(pb); /* bytes per frame */ | |
1077 | get_be32(pb); /* bytes per sample */ | |
1078 | if(size>(16+20+16)) | |
1079 | { | |
1080 | //Optional, additional atom-based fields | |
1081 | #ifdef DEBUG | |
baf25c9d | 1082 | av_log(NULL, AV_LOG_DEBUG, "offest=0x%X, sizeleft=%d=0x%x,format=%c%c%c%c\n",(int)url_ftell(pb),size - (16 + 20 + 16 ),size - (16 + 20 + 16 ), |
14342fd5 JC |
1083 | (format >> 0) & 0xff, |
1084 | (format >> 8) & 0xff, | |
1085 | (format >> 16) & 0xff, | |
1086 | (format >> 24) & 0xff); | |
1087 | #endif | |
1088 | MOV_atom_t a = { format, url_ftell(pb), size - (16 + 20 + 16 + 8) }; | |
1089 | mov_read_default(c, pb, a); | |
1090 | } | |
1091 | } | |
1092 | else | |
1093 | { | |
1094 | //We should be down to 0 bytes here, but lets make sure. | |
1095 | size-=(16+20); | |
1096 | #ifdef DEBUG | |
1097 | if(size>0) | |
baf25c9d | 1098 | av_log(NULL, AV_LOG_DEBUG, "skipping 0x%X bytes\n",size-(16+20)); |
14342fd5 JC |
1099 | #endif |
1100 | url_fskip(pb, size); | |
1101 | } | |
1102 | } | |
1103 | else | |
1104 | { | |
1105 | size-=16; | |
1106 | //Unknown size, but lets do our best and skip the rest. | |
1107 | #ifdef DEBUG | |
baf25c9d | 1108 | av_log(NULL, AV_LOG_DEBUG, "Strange size, skipping 0x%X bytes\n",size); |
14342fd5 JC |
1109 | #endif |
1110 | url_fskip(pb, size); | |
891f64b3 | 1111 | } |
6cea494e | 1112 | } |
6cea494e | 1113 | } |
5cd62665 | 1114 | |
6cea494e ZK |
1115 | return 0; |
1116 | } | |
1117 | ||
5ca1d879 | 1118 | static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
6cea494e | 1119 | { |
5ca1d879 ZK |
1120 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; |
1121 | MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; | |
6cea494e | 1122 | int entries, i; |
b6a17df4 | 1123 | |
5ca1d879 | 1124 | print_atom("stsc", atom); |
5cd62665 | 1125 | |
6cea494e ZK |
1126 | get_byte(pb); /* version */ |
1127 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
1128 | ||
1129 | entries = get_be32(pb); | |
3ffe3793 | 1130 | #ifdef DEBUG |
baf25c9d | 1131 | av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); |
3ffe3793 | 1132 | #endif |
6cea494e | 1133 | sc->sample_to_chunk_sz = entries; |
b6a17df4 ZK |
1134 | sc->sample_to_chunk = (MOV_sample_to_chunk_tbl*) av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl)); |
1135 | if (!sc->sample_to_chunk) | |
1136 | return -1; | |
6cea494e ZK |
1137 | for(i=0; i<entries; i++) { |
1138 | sc->sample_to_chunk[i].first = get_be32(pb); | |
1139 | sc->sample_to_chunk[i].count = get_be32(pb); | |
1140 | sc->sample_to_chunk[i].id = get_be32(pb); | |
1141 | #ifdef DEBUG | |
baf25c9d | 1142 | /* av_log(NULL, AV_LOG_DEBUG, "sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id); */ |
6cea494e ZK |
1143 | #endif |
1144 | } | |
1145 | return 0; | |
1146 | } | |
1147 | ||
247d56f5 BB |
1148 | static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
1149 | { | |
1150 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
1151 | MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; | |
1152 | int entries, i; | |
1153 | ||
1154 | print_atom("stss", atom); | |
1155 | ||
1156 | get_byte(pb); /* version */ | |
1157 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
1158 | ||
1159 | entries = get_be32(pb); | |
1160 | sc->keyframe_count = entries; | |
1161 | #ifdef DEBUG | |
1162 | av_log(NULL, AV_LOG_DEBUG, "keyframe_count = %ld\n", sc->keyframe_count); | |
1163 | #endif | |
1164 | sc->keyframes = (long*) av_malloc(entries * sizeof(long)); | |
1165 | if (!sc->keyframes) | |
1166 | return -1; | |
1167 | for(i=0; i<entries; i++) { | |
1168 | sc->keyframes[i] = get_be32(pb); | |
1169 | #ifdef DEBUG | |
1170 | /* av_log(NULL, AV_LOG_DEBUG, "keyframes[]=%ld\n", sc->keyframes[i]); */ | |
1171 | #endif | |
1172 | } | |
1173 | return 0; | |
1174 | } | |
1175 | ||
5ca1d879 | 1176 | static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
6cea494e | 1177 | { |
5ca1d879 ZK |
1178 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; |
1179 | MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; | |
6cea494e | 1180 | int entries, i; |
b6a17df4 | 1181 | |
5ca1d879 | 1182 | print_atom("stsz", atom); |
5cd62665 | 1183 | |
6cea494e ZK |
1184 | get_byte(pb); /* version */ |
1185 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
5cd62665 | 1186 | |
6cea494e ZK |
1187 | sc->sample_size = get_be32(pb); |
1188 | entries = get_be32(pb); | |
1189 | sc->sample_count = entries; | |
0147f198 | 1190 | #ifdef DEBUG |
baf25c9d | 1191 | av_log(NULL, AV_LOG_DEBUG, "sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count); |
0147f198 | 1192 | #endif |
6cea494e ZK |
1193 | if(sc->sample_size) |
1194 | return 0; /* there isn't any table following */ | |
b6a17df4 ZK |
1195 | sc->sample_sizes = (long*) av_malloc(entries * sizeof(long)); |
1196 | if (!sc->sample_sizes) | |
1197 | return -1; | |
6cea494e ZK |
1198 | for(i=0; i<entries; i++) { |
1199 | sc->sample_sizes[i] = get_be32(pb); | |
1200 | #ifdef DEBUG | |
baf25c9d | 1201 | /* av_log(NULL, AV_LOG_DEBUG, "sample_sizes[]=%ld\n", sc->sample_sizes[i]); */ |
6cea494e ZK |
1202 | #endif |
1203 | } | |
1204 | return 0; | |
1205 | } | |
1206 | ||
5ca1d879 | 1207 | static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
0147f198 | 1208 | { |
5ca1d879 | 1209 | AVStream *st = c->fc->streams[c->fc->nb_streams-1]; |
fd6e513e | 1210 | //MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; |
0147f198 | 1211 | int entries, i; |
d957696f MN |
1212 | int64_t duration=0; |
1213 | int64_t total_sample_count=0; | |
b6a17df4 | 1214 | |
5ca1d879 | 1215 | print_atom("stts", atom); |
0147f198 FR |
1216 | |
1217 | get_byte(pb); /* version */ | |
1218 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
1219 | entries = get_be32(pb); | |
891f64b3 | 1220 | |
baf25c9d GC |
1221 | c->streams[c->fc->nb_streams-1]->stts_count = entries; |
1222 | c->streams[c->fc->nb_streams-1]->stts_data = (uint64_t*) av_malloc(entries * sizeof(uint64_t)); | |
891f64b3 | 1223 | |
3ffe3793 | 1224 | #ifdef DEBUG |
baf25c9d | 1225 | av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); |
3ffe3793 | 1226 | #endif |
0147f198 | 1227 | for(i=0; i<entries; i++) { |
baf25c9d GC |
1228 | int32_t sample_duration; |
1229 | int32_t sample_count; | |
0147f198 | 1230 | |
891f64b3 | 1231 | sample_count=get_be32(pb); |
0147f198 | 1232 | sample_duration = get_be32(pb); |
baf25c9d | 1233 | c->streams[c->fc->nb_streams - 1]->stts_data[i] = (uint64_t)sample_count<<32 | (uint64_t)sample_duration; |
891f64b3 | 1234 | #ifdef DEBUG |
baf25c9d | 1235 | av_log(NULL, AV_LOG_DEBUG, "sample_count=%d, sample_duration=%d\n",sample_count,sample_duration); |
891f64b3 | 1236 | #endif |
1237 | duration+=sample_duration*sample_count; | |
1238 | total_sample_count+=sample_count; | |
1239 | ||
1240 | #if 0 //We calculate an average instead, needed by .mp4-files created with nec e606 3g phone | |
0147f198 FR |
1241 | |
1242 | if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) { | |
14bea432 | 1243 | st->codec.frame_rate_base = sample_duration ? sample_duration : 1; |
baf25c9d | 1244 | st->codec.frame_rate = c->streams[c->fc->nb_streams-1]->time_scale; |
0147f198 | 1245 | #ifdef DEBUG |
baf25c9d | 1246 | av_log(NULL, AV_LOG_DEBUG, "VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration); |
0147f198 FR |
1247 | #endif |
1248 | } | |
891f64b3 | 1249 | #endif |
1250 | } | |
1251 | ||
14342fd5 JC |
1252 | /*The stsd atom which contain codec type sometimes comes after the stts so we cannot check for codec_type*/ |
1253 | if(duration>0) | |
891f64b3 | 1254 | { |
d957696f MN |
1255 | av_reduce( |
1256 | &st->codec.frame_rate, | |
1257 | &st->codec.frame_rate_base, | |
baf25c9d | 1258 | c->streams[c->fc->nb_streams-1]->time_scale * total_sample_count, |
d957696f MN |
1259 | duration, |
1260 | INT_MAX | |
1261 | ); | |
14342fd5 | 1262 | |
891f64b3 | 1263 | #ifdef DEBUG |
baf25c9d | 1264 | av_log(NULL, AV_LOG_DEBUG, "FRAME RATE average (video or audio)= %f (tot sample count= %i ,tot dur= %i timescale=%d)\n", (float)st->codec.frame_rate/st->codec.frame_rate_base,total_sample_count,duration,c->streams[c->fc->nb_streams-1]->time_scale); |
891f64b3 | 1265 | #endif |
0147f198 | 1266 | } |
14342fd5 JC |
1267 | else |
1268 | { | |
1269 | st->codec.frame_rate_base = 1; | |
baf25c9d | 1270 | st->codec.frame_rate = c->streams[c->fc->nb_streams-1]->time_scale; |
14342fd5 | 1271 | } |
0147f198 FR |
1272 | return 0; |
1273 | } | |
1274 | ||
5ca1d879 ZK |
1275 | static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
1276 | { | |
1277 | AVStream *st; | |
1278 | MOVStreamContext *sc; | |
1279 | ||
1280 | print_atom("trak", atom); | |
1281 | ||
1282 | st = av_new_stream(c->fc, c->fc->nb_streams); | |
1283 | if (!st) return -2; | |
1284 | sc = (MOVStreamContext*) av_mallocz(sizeof(MOVStreamContext)); | |
1285 | if (!sc) { | |
1286 | av_free(st); | |
1287 | return -1; | |
1288 | } | |
1289 | ||
1290 | sc->sample_to_chunk_index = -1; | |
1291 | st->priv_data = sc; | |
1292 | st->codec.codec_type = CODEC_TYPE_MOV_OTHER; | |
25c4950e FB |
1293 | st->start_time = 0; /* XXX: check */ |
1294 | st->duration = (c->duration * (int64_t)AV_TIME_BASE) / c->time_scale; | |
5ca1d879 ZK |
1295 | c->streams[c->fc->nb_streams-1] = sc; |
1296 | ||
1297 | return mov_read_default(c, pb, atom); | |
1298 | } | |
1299 | ||
1300 | static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1301 | { | |
1302 | AVStream *st; | |
1303 | ||
1304 | print_atom("tkhd", atom); | |
1305 | ||
1306 | st = c->fc->streams[c->fc->nb_streams-1]; | |
1307 | ||
1308 | get_byte(pb); /* version */ | |
1309 | ||
1310 | get_byte(pb); get_byte(pb); | |
1311 | get_byte(pb); /* flags */ | |
1312 | /* | |
1313 | MOV_TRACK_ENABLED 0x0001 | |
1314 | MOV_TRACK_IN_MOVIE 0x0002 | |
1315 | MOV_TRACK_IN_PREVIEW 0x0004 | |
1316 | MOV_TRACK_IN_POSTER 0x0008 | |
1317 | */ | |
1318 | ||
1319 | get_be32(pb); /* creation time */ | |
1320 | get_be32(pb); /* modification time */ | |
1321 | st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/ | |
1322 | get_be32(pb); /* reserved */ | |
25c4950e FB |
1323 | st->start_time = 0; /* check */ |
1324 | st->duration = (get_be32(pb) * (int64_t)AV_TIME_BASE) / c->time_scale; /* duration */ | |
5ca1d879 ZK |
1325 | get_be32(pb); /* reserved */ |
1326 | get_be32(pb); /* reserved */ | |
1327 | ||
1328 | get_be16(pb); /* layer */ | |
1329 | get_be16(pb); /* alternate group */ | |
1330 | get_be16(pb); /* volume */ | |
1331 | get_be16(pb); /* reserved */ | |
1332 | ||
1333 | url_fskip(pb, 36); /* display matrix */ | |
1334 | ||
1335 | /* those are fixed-point */ | |
1336 | st->codec.width = get_be32(pb) >> 16; /* track width */ | |
1337 | st->codec.height = get_be32(pb) >> 16; /* track height */ | |
1338 | ||
1339 | return 0; | |
1340 | } | |
1341 | ||
1342 | /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */ | |
1343 | /* like the files created with Adobe Premiere 5.0, for samples see */ | |
1344 | /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */ | |
1345 | static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1346 | { | |
1347 | int err; | |
5ca1d879 ZK |
1348 | |
1349 | #ifdef DEBUG | |
1350 | print_atom("wide", atom); | |
1351 | debug_indent++; | |
1352 | #endif | |
1353 | if (atom.size < 8) | |
1354 | return 0; /* continue */ | |
1355 | if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */ | |
1356 | url_fskip(pb, atom.size - 4); | |
1357 | return 0; | |
1358 | } | |
1359 | atom.type = get_le32(pb); | |
1360 | atom.offset += 8; | |
1361 | atom.size -= 8; | |
fd6e513e | 1362 | if (atom.type != MKTAG('m', 'd', 'a', 't')) { |
5ca1d879 ZK |
1363 | url_fskip(pb, atom.size); |
1364 | return 0; | |
1365 | } | |
1366 | err = mov_read_mdat(c, pb, atom); | |
1367 | #ifdef DEBUG | |
1368 | debug_indent--; | |
1369 | #endif | |
1370 | return err; | |
1371 | } | |
1372 | ||
1373 | ||
0147f198 | 1374 | #ifdef CONFIG_ZLIB |
0c1a9eda | 1375 | static int null_read_packet(void *opaque, uint8_t *buf, int buf_size) |
0147f198 FR |
1376 | { |
1377 | return -1; | |
1378 | } | |
1379 | ||
5ca1d879 | 1380 | static int mov_read_cmov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
0147f198 | 1381 | { |
0147f198 | 1382 | ByteIOContext ctx; |
b6a17df4 ZK |
1383 | uint8_t *cmov_data; |
1384 | uint8_t *moov_data; /* uncompressed data */ | |
0147f198 FR |
1385 | long cmov_len, moov_len; |
1386 | int ret; | |
b6a17df4 | 1387 | |
5ca1d879 | 1388 | print_atom("cmov", atom); |
0147f198 FR |
1389 | |
1390 | get_be32(pb); /* dcom atom */ | |
1391 | if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) | |
1392 | return -1; | |
1393 | if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { | |
baf25c9d | 1394 | av_log(NULL, AV_LOG_DEBUG, "unknown compression for cmov atom !"); |
0147f198 FR |
1395 | return -1; |
1396 | } | |
1397 | get_be32(pb); /* cmvd atom */ | |
1398 | if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) | |
1399 | return -1; | |
1400 | moov_len = get_be32(pb); /* uncompressed size */ | |
5ca1d879 | 1401 | cmov_len = atom.size - 6 * 4; |
5cd62665 | 1402 | |
b6a17df4 | 1403 | cmov_data = (uint8_t *) av_malloc(cmov_len); |
0147f198 FR |
1404 | if (!cmov_data) |
1405 | return -1; | |
b6a17df4 | 1406 | moov_data = (uint8_t *) av_malloc(moov_len); |
0147f198 FR |
1407 | if (!moov_data) { |
1408 | av_free(cmov_data); | |
1409 | return -1; | |
1410 | } | |
1411 | get_buffer(pb, cmov_data, cmov_len); | |
b6a17df4 | 1412 | if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) |
0147f198 FR |
1413 | return -1; |
1414 | if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0) | |
1415 | return -1; | |
1416 | ctx.buf_end = ctx.buffer + moov_len; | |
5ca1d879 ZK |
1417 | atom.type = MKTAG( 'm', 'o', 'o', 'v' ); |
1418 | atom.offset = 0; | |
1419 | atom.size = moov_len; | |
9ed83b0a ZK |
1420 | #ifdef DEBUG |
1421 | { int fd = open("/tmp/uncompheader.mov", O_WRONLY | O_CREAT); write(fd, moov_data, moov_len); close(fd); } | |
1422 | #endif | |
5ca1d879 | 1423 | ret = mov_read_default(c, &ctx, atom); |
0147f198 FR |
1424 | av_free(moov_data); |
1425 | av_free(cmov_data); | |
9ed83b0a | 1426 | |
0147f198 FR |
1427 | return ret; |
1428 | } | |
1429 | #endif | |
1430 | ||
baf25c9d GC |
1431 | /* edit list atom */ |
1432 | static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1433 | { | |
58e555d4 | 1434 | int i, edit_count; |
baf25c9d GC |
1435 | print_atom("elst", atom); |
1436 | ||
1437 | get_byte(pb); /* version */ | |
1438 | get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
58e555d4 MN |
1439 | edit_count= c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */ |
1440 | ||
1441 | for(i=0; i<edit_count; i++){ | |
1442 | get_be32(pb); /* Track duration */ | |
1443 | get_be32(pb); /* Media time */ | |
1444 | get_be32(pb); /* Media rate */ | |
1445 | } | |
baf25c9d GC |
1446 | #ifdef DEBUG |
1447 | av_log(NULL, AV_LOG_DEBUG, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count); | |
1448 | #endif | |
1449 | return 0; | |
1450 | } | |
1451 | ||
6cea494e ZK |
1452 | static const MOVParseTableEntry mov_default_parse_table[] = { |
1453 | /* mp4 atoms */ | |
5ca1d879 ZK |
1454 | { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, |
1455 | { MKTAG( 'c', 'p', 'r', 't' ), mov_read_default }, | |
1456 | { MKTAG( 'c', 'r', 'h', 'd' ), mov_read_default }, | |
1457 | { MKTAG( 'c', 't', 't', 's' ), mov_read_leaf }, /* composition time to sample */ | |
1458 | { MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */ | |
1459 | { MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf }, | |
1460 | { MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf }, | |
1461 | { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, | |
58e555d4 | 1462 | { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, |
5ca1d879 ZK |
1463 | { MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf }, |
1464 | { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, | |
1465 | { MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf }, | |
1466 | { MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf }, | |
1467 | { MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf }, | |
1468 | { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat }, | |
1469 | { MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd }, | |
1470 | { MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default }, | |
1471 | { MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default }, | |
1472 | { MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov }, | |
1473 | { MKTAG( 'm', 'p', '4', 'a' ), mov_read_default }, | |
1474 | { MKTAG( 'm', 'p', '4', 's' ), mov_read_default }, | |
1475 | { MKTAG( 'm', 'p', '4', 'v' ), mov_read_default }, | |
1476 | { MKTAG( 'm', 'p', 'o', 'd' ), mov_read_leaf }, | |
1477 | { MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd }, | |
1478 | { MKTAG( 'n', 'm', 'h', 'd' ), mov_read_leaf }, | |
1479 | { MKTAG( 'o', 'd', 'h', 'd' ), mov_read_default }, | |
1480 | { MKTAG( 's', 'd', 'h', 'd' ), mov_read_default }, | |
3c13647a | 1481 | { MKTAG( 's', 'k', 'i', 'p' ), mov_read_leaf }, |
5ca1d879 | 1482 | { MKTAG( 's', 'm', 'h', 'd' ), mov_read_leaf }, /* sound media info header */ |
9ed83b0a | 1483 | { MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorrenson extension ??? */ |
5ca1d879 ZK |
1484 | { MKTAG( 's', 't', 'b', 'l' ), mov_read_default }, |
1485 | { MKTAG( 's', 't', 'c', 'o' ), mov_read_stco }, | |
1486 | { MKTAG( 's', 't', 'd', 'p' ), mov_read_default }, | |
1487 | { MKTAG( 's', 't', 's', 'c' ), mov_read_stsc }, | |
1488 | { MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */ | |
1489 | { MKTAG( 's', 't', 's', 'h' ), mov_read_default }, | |
247d56f5 | 1490 | { MKTAG( 's', 't', 's', 's' ), mov_read_stss }, /* sync sample */ |
5ca1d879 ZK |
1491 | { MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */ |
1492 | { MKTAG( 's', 't', 't', 's' ), mov_read_stts }, | |
1493 | { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */ | |
1494 | { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak }, | |
1495 | { MKTAG( 't', 'r', 'e', 'f' ), mov_read_default }, /* not really */ | |
1496 | { MKTAG( 'u', 'd', 't', 'a' ), mov_read_leaf }, | |
1497 | { MKTAG( 'u', 'r', 'l', ' ' ), mov_read_leaf }, | |
1498 | { MKTAG( 'u', 'r', 'n', ' ' ), mov_read_leaf }, | |
1499 | { MKTAG( 'u', 'u', 'i', 'd' ), mov_read_default }, | |
1500 | { MKTAG( 'v', 'm', 'h', 'd' ), mov_read_leaf }, /* video media info header */ | |
1501 | { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_default }, | |
6cea494e | 1502 | /* extra mp4 */ |
5ca1d879 | 1503 | { MKTAG( 'M', 'D', 'E', 'S' ), mov_read_leaf }, |
6cea494e | 1504 | /* QT atoms */ |
5ca1d879 ZK |
1505 | { MKTAG( 'c', 'h', 'a', 'p' ), mov_read_leaf }, |
1506 | { MKTAG( 'c', 'l', 'i', 'p' ), mov_read_default }, | |
1507 | { MKTAG( 'c', 'r', 'g', 'n' ), mov_read_leaf }, | |
1508 | { MKTAG( 'c', 't', 'a', 'b' ), mov_read_ctab }, | |
1509 | { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds }, | |
1510 | { MKTAG( 'k', 'm', 'a', 't' ), mov_read_leaf }, | |
1511 | { MKTAG( 'm', 'a', 't', 't' ), mov_read_default }, | |
1512 | { MKTAG( 'r', 'd', 'r', 'f' ), mov_read_leaf }, | |
1513 | { MKTAG( 'r', 'm', 'd', 'a' ), mov_read_default }, | |
1514 | { MKTAG( 'r', 'm', 'd', 'r' ), mov_read_leaf }, | |
1515 | { MKTAG( 'r', 'm', 'r', 'a' ), mov_read_default }, | |
1516 | { MKTAG( 's', 'c', 'p', 't' ), mov_read_leaf }, | |
1517 | { MKTAG( 's', 's', 'r', 'c' ), mov_read_leaf }, | |
1518 | { MKTAG( 's', 'y', 'n', 'c' ), mov_read_leaf }, | |
1519 | { MKTAG( 't', 'c', 'm', 'd' ), mov_read_leaf }, | |
1520 | { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */ | |
1521 | //{ MKTAG( 'r', 'm', 'q', 'u' ), mov_read_leaf }, | |
0147f198 | 1522 | #ifdef CONFIG_ZLIB |
5ca1d879 | 1523 | { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov }, |
0147f198 | 1524 | #else |
5ca1d879 | 1525 | { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_leaf }, |
0147f198 | 1526 | #endif |
5ca1d879 | 1527 | { 0L, mov_read_leaf } |
6cea494e ZK |
1528 | }; |
1529 | ||
1530 | static void mov_free_stream_context(MOVStreamContext *sc) | |
1531 | { | |
1532 | if(sc) { | |
1ea4f593 FB |
1533 | av_free(sc->chunk_offsets); |
1534 | av_free(sc->sample_to_chunk); | |
5cd62665 | 1535 | av_free(sc->sample_sizes); |
247d56f5 | 1536 | av_free(sc->keyframes); |
0e7eed09 | 1537 | av_free(sc->header_data); |
baf25c9d | 1538 | av_free(sc->stts_data); |
1ea4f593 | 1539 | av_free(sc); |
6cea494e ZK |
1540 | } |
1541 | } | |
1542 | ||
5ca1d879 | 1543 | static inline uint32_t mov_to_tag(uint8_t *buf) |
0e7eed09 | 1544 | { |
5ca1d879 | 1545 | return MKTAG(buf[0], buf[1], buf[2], buf[3]); |
0e7eed09 FB |
1546 | } |
1547 | ||
5cd62665 | 1548 | static inline uint32_t to_be32(uint8_t *buf) |
0e7eed09 FB |
1549 | { |
1550 | return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | |
1551 | } | |
1552 | ||
b6a17df4 | 1553 | /* XXX: is it sufficient ? */ |
c9a65ca8 FB |
1554 | static int mov_probe(AVProbeData *p) |
1555 | { | |
0e7eed09 FB |
1556 | unsigned int offset; |
1557 | uint32_t tag; | |
3ffe3793 | 1558 | |
c9a65ca8 FB |
1559 | /* check file header */ |
1560 | if (p->buf_size <= 12) | |
1561 | return 0; | |
0e7eed09 FB |
1562 | offset = 0; |
1563 | for(;;) { | |
1564 | /* ignore invalid offset */ | |
1565 | if ((offset + 8) > (unsigned int)p->buf_size) | |
3ffe3793 | 1566 | return 0; |
5ca1d879 | 1567 | tag = mov_to_tag(p->buf + offset + 4); |
0e7eed09 FB |
1568 | switch(tag) { |
1569 | case MKTAG( 'm', 'o', 'o', 'v' ): | |
1570 | case MKTAG( 'w', 'i', 'd', 'e' ): | |
1571 | case MKTAG( 'f', 'r', 'e', 'e' ): | |
8b879f18 FR |
1572 | case MKTAG( 'm', 'd', 'a', 't' ): |
1573 | case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */ | |
bc634f6f | 1574 | case MKTAG( 'u', 'd', 't', 'a' ): /* Packet Video PVAuthor adds this and a lot of more junk */ |
3ffe3793 | 1575 | return AVPROBE_SCORE_MAX; |
0e7eed09 | 1576 | case MKTAG( 'f', 't', 'y', 'p' ): |
5ca1d879 | 1577 | case MKTAG( 's', 'k', 'i', 'p' ): |
14342fd5 | 1578 | offset = to_be32(p->buf+offset) + offset; |
0e7eed09 FB |
1579 | break; |
1580 | default: | |
1581 | /* unrecognized tag */ | |
1582 | return 0; | |
1583 | } | |
3ffe3793 FR |
1584 | } |
1585 | return 0; | |
c9a65ca8 FB |
1586 | } |
1587 | ||
a266644f | 1588 | static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) |
6cea494e | 1589 | { |
b6a17df4 | 1590 | MOVContext *mov = (MOVContext *) s->priv_data; |
6cea494e | 1591 | ByteIOContext *pb = &s->pb; |
684f44d9 | 1592 | int i, j, nb, err; |
5ca1d879 | 1593 | MOV_atom_t atom = { 0, 0, 0 }; |
6cea494e | 1594 | |
6cea494e | 1595 | mov->fc = s; |
b6a17df4 | 1596 | mov->parse_table = mov_default_parse_table; |
c9a65ca8 FB |
1597 | #if 0 |
1598 | /* XXX: I think we should auto detect */ | |
1599 | if(s->iformat->name[1] == 'p') | |
6cea494e | 1600 | mov->mp4 = 1; |
c9a65ca8 | 1601 | #endif |
6cea494e | 1602 | if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ |
5ca1d879 | 1603 | atom.size = url_filesize(url_fileno(pb)); |
6cea494e | 1604 | else |
9ed83b0a | 1605 | atom.size = 0x7FFFFFFFFFFFFFFFLL; |
6cea494e ZK |
1606 | |
1607 | #ifdef DEBUG | |
baf25c9d | 1608 | av_log(NULL, AV_LOG_DEBUG, "filesz=%Ld\n", atom.size); |
6cea494e ZK |
1609 | #endif |
1610 | ||
1611 | /* check MOV header */ | |
5ca1d879 | 1612 | err = mov_read_default(mov, pb, atom); |
25fa62e1 | 1613 | if (err<0 || (!mov->found_moov && !mov->found_mdat)) { |
bc874dae | 1614 | av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%lld\n", |
25fa62e1 ZK |
1615 | err, mov->found_moov, mov->found_mdat, url_ftell(pb)); |
1616 | return -1; | |
6cea494e ZK |
1617 | } |
1618 | #ifdef DEBUG | |
baf25c9d | 1619 | av_log(NULL, AV_LOG_DEBUG, "on_parse_exit_offset=%d\n", (int) url_ftell(pb)); |
6cea494e ZK |
1620 | #endif |
1621 | /* some cleanup : make sure we are on the mdat atom */ | |
1622 | if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) | |
1623 | url_fseek(pb, mov->mdat_offset, SEEK_SET); | |
1624 | ||
1625 | mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */ | |
1626 | ||
1627 | #ifdef DEBUG | |
baf25c9d | 1628 | av_log(NULL, AV_LOG_DEBUG, "mdat_reset_offset=%d\n", (int) url_ftell(pb)); |
6cea494e ZK |
1629 | #endif |
1630 | ||
1631 | #ifdef DEBUG | |
baf25c9d | 1632 | av_log(NULL, AV_LOG_DEBUG, "streams= %d\n", s->nb_streams); |
6cea494e ZK |
1633 | #endif |
1634 | mov->total_streams = nb = s->nb_streams; | |
5ca1d879 | 1635 | |
6cea494e ZK |
1636 | #if 1 |
1637 | for(i=0; i<s->nb_streams;) { | |
1638 | if(s->streams[i]->codec.codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */ | |
1ea4f593 | 1639 | av_free(s->streams[i]); |
6cea494e ZK |
1640 | for(j=i+1; j<s->nb_streams; j++) |
1641 | s->streams[j-1] = s->streams[j]; | |
1642 | s->nb_streams--; | |
1643 | } else | |
1644 | i++; | |
1645 | } | |
1646 | for(i=0; i<s->nb_streams;i++) { | |
1647 | MOVStreamContext *sc; | |
1648 | sc = (MOVStreamContext *)s->streams[i]->priv_data; | |
1649 | sc->ffindex = i; | |
1650 | sc->is_ff_stream = 1; | |
1651 | } | |
1652 | #endif | |
1653 | #ifdef DEBUG | |
baf25c9d | 1654 | av_log(NULL, AV_LOG_DEBUG, "real streams= %d\n", s->nb_streams); |
6cea494e ZK |
1655 | #endif |
1656 | return 0; | |
1657 | } | |
1658 | ||
1659 | /* Yes, this is ugly... I didn't write the specs of QT :p */ | |
1660 | /* XXX:remove useless commented code sometime */ | |
a266644f | 1661 | static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) |
6cea494e | 1662 | { |
b6a17df4 | 1663 | MOVContext *mov = (MOVContext *) s->priv_data; |
0e7eed09 | 1664 | MOVStreamContext *sc; |
9ed83b0a | 1665 | int64_t offset = 0x0FFFFFFFFFFFFFFFLL; |
247d56f5 | 1666 | int i, a, b, m; |
5cd62665 | 1667 | int size; |
6cea494e | 1668 | size = 0x0FFFFFFF; |
5cd62665 | 1669 | |
3ffe3793 FR |
1670 | #ifdef MOV_SPLIT_CHUNKS |
1671 | if (mov->partial) { | |
5cd62665 | 1672 | |
3ffe3793 FR |
1673 | int idx; |
1674 | ||
5cd62665 ZK |
1675 | sc = mov->partial; |
1676 | idx = sc->sample_to_chunk_index; | |
1677 | ||
3ffe3793 | 1678 | if (idx < 0) return 0; |
5cd62665 | 1679 | size = sc->sample_sizes[sc->current_sample]; |
3ffe3793 | 1680 | |
5cd62665 ZK |
1681 | sc->current_sample++; |
1682 | sc->left_in_chunk--; | |
3ffe3793 | 1683 | |
5cd62665 | 1684 | if (sc->left_in_chunk <= 0) |
3ffe3793 FR |
1685 | mov->partial = 0; |
1686 | offset = mov->next_chunk_offset; | |
1687 | /* extract the sample */ | |
1688 | ||
1689 | goto readchunk; | |
1690 | } | |
1691 | #endif | |
1692 | ||
6cea494e | 1693 | again: |
5cd62665 | 1694 | sc = 0; |
6cea494e | 1695 | for(i=0; i<mov->total_streams; i++) { |
5cd62665 | 1696 | MOVStreamContext *msc = mov->streams[i]; |
baf25c9d | 1697 | //av_log(NULL, AV_LOG_DEBUG, "MOCHUNK %ld %d %p pos:%Ld\n", mov->streams[i]->next_chunk, mov->total_streams, mov->streams[i], url_ftell(&s->pb)); |
5cd62665 ZK |
1698 | if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0 |
1699 | && (msc->chunk_offsets[msc->next_chunk] < offset)) { | |
1700 | sc = msc; | |
1701 | offset = msc->chunk_offsets[msc->next_chunk]; | |
baf25c9d | 1702 | //av_log(NULL, AV_LOG_DEBUG, "SELETED %Ld i:%d\n", offset, i); |
6cea494e | 1703 | } |
6cea494e | 1704 | } |
9ed83b0a | 1705 | if (!sc || offset==0x0FFFFFFFFFFFFFFFLL) |
5cd62665 ZK |
1706 | return -1; |
1707 | ||
1708 | sc->next_chunk++; | |
1709 | ||
3ffe3793 | 1710 | if(mov->next_chunk_offset < offset) { /* some meta data */ |
6cea494e | 1711 | url_fskip(&s->pb, (offset - mov->next_chunk_offset)); |
3ffe3793 FR |
1712 | mov->next_chunk_offset = offset; |
1713 | } | |
1714 | ||
baf25c9d | 1715 | //av_log(NULL, AV_LOG_DEBUG, "chunk: [%i] %lli -> %lli\n", st_id, mov->next_chunk_offset, offset); |
5cd62665 | 1716 | if(!sc->is_ff_stream) { |
6cea494e | 1717 | url_fskip(&s->pb, (offset - mov->next_chunk_offset)); |
3ffe3793 | 1718 | mov->next_chunk_offset = offset; |
9ed83b0a | 1719 | offset = 0x0FFFFFFFFFFFFFFFLL; |
6cea494e ZK |
1720 | goto again; |
1721 | } | |
6cea494e ZK |
1722 | |
1723 | /* now get the chunk size... */ | |
1724 | ||
1725 | for(i=0; i<mov->total_streams; i++) { | |
5cd62665 ZK |
1726 | MOVStreamContext *msc = mov->streams[i]; |
1727 | if ((msc->next_chunk < msc->chunk_count) | |
1728 | && ((msc->chunk_offsets[msc->next_chunk] - offset) < size)) | |
1729 | size = msc->chunk_offsets[msc->next_chunk] - offset; | |
6cea494e | 1730 | } |
bc634f6f ZK |
1731 | |
1732 | #ifdef MOV_MINOLTA_FIX | |
1733 | //Make sure that size is according to sample_size (Needed by .mov files | |
1734 | //created on a Minolta Dimage Xi where audio chunks contains waste data in the end) | |
1735 | //Maybe we should really not only check sc->sample_size, but also sc->sample_sizes | |
1736 | //but I have no such movies | |
1737 | if (sc->sample_size > 0) { | |
1738 | int foundsize=0; | |
1739 | for(i=0; i<(sc->sample_to_chunk_sz); i++) { | |
1740 | if( (sc->sample_to_chunk[i].first)<=(sc->next_chunk) && (sc->sample_size>0) ) | |
1741 | { | |
cac0a56c RS |
1742 | // I can't figure out why for PCM audio sample_size is always 1 |
1743 | // (it should actually be channels*bits_per_second/8) but it is. | |
1744 | AVCodecContext* cod = &s->streams[sc->ffindex]->codec; | |
1745 | if (sc->sample_size == 1 && (cod->codec_id == CODEC_ID_PCM_S16BE || cod->codec_id == CODEC_ID_PCM_S16LE)) | |
1746 | foundsize=(sc->sample_to_chunk[i].count*cod->channels*cod->bits_per_sample)/8; | |
1747 | else | |
1748 | foundsize=sc->sample_to_chunk[i].count*sc->sample_size; | |
bc634f6f ZK |
1749 | } |
1750 | #ifdef DEBUG | |
baf25c9d | 1751 | /*av_log(NULL, AV_LOG_DEBUG, "sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id);*/ |
bc634f6f ZK |
1752 | #endif |
1753 | } | |
1754 | if( (foundsize>0) && (foundsize<size) ) | |
1755 | { | |
1756 | #ifdef DEBUG | |
baf25c9d | 1757 | /*av_log(NULL, AV_LOG_DEBUG, "this size should actually be %d\n",foundsize);*/ |
bc634f6f ZK |
1758 | #endif |
1759 | size=foundsize; | |
1760 | } | |
1761 | } | |
1762 | #endif //MOV_MINOLTA_FIX | |
1763 | ||
3ffe3793 FR |
1764 | #ifdef MOV_SPLIT_CHUNKS |
1765 | /* split chunks into samples */ | |
5cd62665 ZK |
1766 | if (sc->sample_size == 0) { |
1767 | int idx = sc->sample_to_chunk_index; | |
1768 | if ((idx + 1 < sc->sample_to_chunk_sz) | |
1769 | && (sc->next_chunk >= sc->sample_to_chunk[idx + 1].first)) | |
1770 | idx++; | |
1771 | sc->sample_to_chunk_index = idx; | |
1772 | if (idx >= 0 && sc->sample_to_chunk[idx].count != 1) { | |
1773 | mov->partial = sc; | |
3ffe3793 | 1774 | /* we'll have to get those samples before next chunk */ |
5cd62665 ZK |
1775 | sc->left_in_chunk = sc->sample_to_chunk[idx].count - 1; |
1776 | size = sc->sample_sizes[sc->current_sample]; | |
3ffe3793 FR |
1777 | } |
1778 | ||
5cd62665 | 1779 | sc->current_sample++; |
3ffe3793 FR |
1780 | } |
1781 | #endif | |
1782 | ||
1783 | readchunk: | |
baf25c9d | 1784 | //av_log(NULL, AV_LOG_DEBUG, "chunk: [%i] %lli -> %lli (%i)\n", st_id, offset, offset + size, size); |
6cea494e ZK |
1785 | if(size == 0x0FFFFFFF) |
1786 | size = mov->mdat_size + mov->mdat_offset - offset; | |
1787 | if(size < 0) | |
1788 | return -1; | |
1789 | if(size == 0) | |
1790 | return -1; | |
0e7eed09 | 1791 | url_fseek(&s->pb, offset, SEEK_SET); |
5cd62665 | 1792 | |
baf25c9d | 1793 | //av_log(NULL, AV_LOG_DEBUG, "READCHUNK hlen: %d %d off: %Ld pos:%Ld\n", size, sc->header_len, offset, url_ftell(&s->pb)); |
0e7eed09 FB |
1794 | if (sc->header_len > 0) { |
1795 | av_new_packet(pkt, size + sc->header_len); | |
1796 | memcpy(pkt->data, sc->header_data, sc->header_len); | |
1797 | get_buffer(&s->pb, pkt->data + sc->header_len, size); | |
1798 | /* free header */ | |
1799 | av_freep(&sc->header_data); | |
1800 | sc->header_len = 0; | |
1801 | } else { | |
1802 | av_new_packet(pkt, size); | |
1803 | get_buffer(&s->pb, pkt->data, pkt->size); | |
1804 | } | |
1805 | pkt->stream_index = sc->ffindex; | |
247d56f5 BB |
1806 | |
1807 | // If the keyframes table exists, mark any samples that are in the table as key frames. | |
1808 | // If no table exists, treat very sample as a key frame. | |
1809 | if (sc->keyframes) { | |
1810 | a = 0; | |
1811 | b = sc->keyframe_count - 1; | |
1812 | ||
1813 | while (a < b) { | |
1814 | m = (a + b + 1) >> 1; | |
1815 | if (sc->keyframes[m] > sc->current_sample) { | |
1816 | b = m - 1; | |
1817 | } else { | |
1818 | a = m; | |
1819 | } | |
1820 | } | |
1821 | ||
1822 | if (sc->keyframes[a] == sc->current_sample) | |
1823 | pkt->flags |= PKT_FLAG_KEY; | |
1824 | } | |
1825 | else | |
1826 | pkt->flags |= PKT_FLAG_KEY; | |
6cea494e ZK |
1827 | |
1828 | #ifdef DEBUG | |
1829 | /* | |
baf25c9d | 1830 | av_log(NULL, AV_LOG_DEBUG, "Packet (%d, %d, %ld) ", pkt->stream_index, st_id, pkt->size); |
6cea494e | 1831 | for(i=0; i<8; i++) |
baf25c9d | 1832 | av_log(NULL, AV_LOG_DEBUG, "%02x ", pkt->data[i]); |
6cea494e | 1833 | for(i=0; i<8; i++) |
baf25c9d | 1834 | av_log(NULL, AV_LOG_DEBUG, "%c ", (pkt->data[i]) & 0x7F); |
6cea494e ZK |
1835 | puts(""); |
1836 | */ | |
1837 | #endif | |
1838 | ||
1839 | mov->next_chunk_offset = offset + size; | |
1840 | ||
1841 | return 0; | |
1842 | } | |
1843 | ||
baf25c9d GC |
1844 | #if defined(MOV_SPLIT_CHUNKS) && defined(MOV_SEEK) |
1845 | /** | |
1846 | * Seek method based on the one described in the Appendix C of QTFileFormat.pdf | |
1847 | */ | |
1848 | static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp) | |
1849 | { | |
1850 | MOVContext* mov = (MOVContext *) s->priv_data; | |
1851 | MOVStreamContext* sc; | |
1852 | int32_t i, a, b, m; | |
1853 | int64_t sample_time; | |
1854 | int64_t start_time; | |
1855 | int32_t seek_sample, sample; | |
1856 | int32_t duration; | |
1857 | int32_t count; | |
1858 | int32_t chunk; | |
1859 | int32_t left_in_chunk; | |
1860 | int64_t chunk_file_offset; | |
1861 | int64_t sample_file_offset; | |
1862 | int32_t first_chunk_sample; | |
1863 | int32_t sample_to_chunk_idx; | |
1864 | int mov_idx; | |
1865 | ||
1866 | // Find the corresponding mov stream | |
1867 | for (mov_idx = 0; mov_idx < mov->total_streams; mov_idx++) | |
1868 | if (mov->streams[mov_idx]->ffindex == stream_index) | |
1869 | break; | |
1870 | if (mov_idx == mov->total_streams) { | |
1871 | av_log(s, AV_LOG_ERROR, "mov: requested stream was not found in mov streams (idx=%i)\n", stream_index); | |
1872 | return -1; | |
1873 | } | |
1874 | sc = mov->streams[mov_idx]; | |
1875 | ||
1876 | // Step 1. Find the edit that contains the requested time (elst) | |
1877 | if (sc->edit_count) { | |
1878 | // FIXME should handle edit list | |
1879 | av_log(s, AV_LOG_ERROR, "mov: does not handle seeking in files that contain edit list (c:%d)\n", sc->edit_count); | |
1880 | return -1; | |
1881 | } | |
1882 | ||
1883 | // Step 2. Find the corresponding sample using the Time-to-sample atom (stts) */ | |
1884 | #ifdef DEBUG | |
1885 | av_log(s, AV_LOG_DEBUG, "Searching for time %li in stream #%i (time_scale=%i)\n", (long)timestamp, mov_idx, sc->time_scale); | |
1886 | #endif | |
1887 | // convert timestamp from time_base unit to timescale unit | |
1888 | sample_time = av_rescale( timestamp, | |
1889 | (int64_t)sc->time_scale * s->streams[stream_index]->time_base.num, | |
1890 | (int64_t)s->streams[stream_index]->time_base.den); | |
1891 | start_time = 0; // FIXME use elst atom | |
1892 | sample = 1; // sample are 0 based in table | |
1893 | #ifdef DEBUG | |
1894 | av_log(s, AV_LOG_DEBUG, "Searching for sample_time %li \n", (long)sample_time); | |
1895 | #endif | |
1896 | for (i = 0; i < sc->stts_count; i++) { | |
1897 | count = (uint32_t)(sc->stts_data[i]>>32); | |
1898 | duration = (uint32_t)(sc->stts_data[i]&0xffff); | |
1899 | //av_log(s, AV_LOG_DEBUG, "> sample_time %lli \n", (long)sample_time); | |
1900 | //av_log(s, AV_LOG_DEBUG, "> count=%i duration=%i\n", count, duration); | |
1901 | if ((start_time + count*duration) > sample_time) { | |
1902 | sample += (sample_time - start_time) / duration; | |
1903 | break; | |
1904 | } | |
1905 | sample += count; | |
1906 | start_time += count * duration; | |
1907 | } | |
1908 | /* NOTE: despite what qt doc say, the dt value (Display Time in qt vocabulary) computed with the stts atom | |
1909 | is a decoding time stamp (dts) not a presentation time stamp. And as usual dts != pts for stream with b frames */ | |
1910 | ||
1911 | #ifdef DEBUG | |
1912 | av_log(s, AV_LOG_DEBUG, "Found time %li at sample #%u\n", (long)sample_time, sample); | |
1913 | #endif | |
1914 | if (sample > sc->sample_count) { | |
1915 | av_log(s, AV_LOG_ERROR, "mov: sample pos is too high, unable to seek (req. sample=%i, sample count=%ld)\n", sample, sc->sample_count); | |
1916 | return -1; | |
1917 | } | |
1918 | ||
1919 | // Step 3. Find the prior sync. sample using the Sync sample atom (stss) | |
1920 | if (sc->keyframes) { | |
1921 | a = 0; | |
1922 | b = sc->keyframe_count - 1; | |
1923 | while (a < b) { | |
1924 | m = (a + b + 1) >> 1; | |
1925 | if (sc->keyframes[m] > sample) { | |
1926 | b = m - 1; | |
1927 | } else { | |
1928 | a = m; | |
1929 | } | |
1930 | #ifdef DEBUG | |
1931 | // av_log(s, AV_LOG_DEBUG, "a=%i (%i) b=%i (%i) m=%i (%i) stream #%i\n", a, sc->keyframes[a], b, sc->keyframes[b], m, sc->keyframes[m], mov_idx); | |
1932 | #endif | |
1933 | } | |
1934 | seek_sample = sc->keyframes[a]; | |
1935 | } | |
1936 | else | |
1937 | seek_sample = sample; // else all samples are key frames | |
1938 | #ifdef DEBUG | |
1939 | av_log(s, AV_LOG_DEBUG, "Found nearest keyframe at sample #%i \n", seek_sample); | |
1940 | #endif | |
1941 | ||
1942 | // Step 4. Find the chunk of the sample using the Sample-to-chunk-atom (stsc) | |
1943 | for (first_chunk_sample = 1, i = 0; i < (sc->sample_to_chunk_sz - 1); i++) { | |
1944 | b = (sc->sample_to_chunk[i + 1].first - sc->sample_to_chunk[i].first) * sc->sample_to_chunk[i].count; | |
1945 | if (seek_sample >= first_chunk_sample && seek_sample < (first_chunk_sample + b)) | |
1946 | break; | |
1947 | first_chunk_sample += b; | |
1948 | } | |
1949 | chunk = sc->sample_to_chunk[i].first + (seek_sample - first_chunk_sample) / sc->sample_to_chunk[i].count; | |
1950 | left_in_chunk = sc->sample_to_chunk[i].count - (seek_sample - first_chunk_sample) % sc->sample_to_chunk[i].count; | |
1951 | first_chunk_sample += ((seek_sample - first_chunk_sample) / sc->sample_to_chunk[i].count) * sc->sample_to_chunk[i].count; | |
1952 | sample_to_chunk_idx = i; | |
1953 | #ifdef DEBUG | |
1954 | av_log(s, AV_LOG_DEBUG, "Sample was found in chunk #%i at sample offset %i (idx %i)\n", chunk, seek_sample - first_chunk_sample, sample_to_chunk_idx); | |
1955 | #endif | |
1956 | ||
1957 | // Step 5. Find the offset of the chunk using the chunk offset atom | |
1958 | if (!sc->chunk_offsets) { | |
1959 | av_log(s, AV_LOG_ERROR, "mov: no chunk offset atom, unable to seek\n"); | |
1960 | return -1; | |
1961 | } | |
1962 | if (chunk > sc->chunk_count) { | |
1963 | av_log(s, AV_LOG_ERROR, "mov: chunk offset atom too short, unable to seek (req. chunk=%i, chunk count=%li)\n", chunk, sc->chunk_count); | |
1964 | return -1; | |
1965 | } | |
1966 | chunk_file_offset = sc->chunk_offsets[chunk - 1]; | |
1967 | #ifdef DEBUG | |
1968 | av_log(s, AV_LOG_DEBUG, "Chunk file offset is #%llu \n", chunk_file_offset); | |
1969 | #endif | |
1970 | ||
1971 | // Step 6. Find the byte offset within the chunk using the sample size atom | |
1972 | sample_file_offset = chunk_file_offset; | |
1973 | if (sc->sample_size) | |
1974 | sample_file_offset += (seek_sample - first_chunk_sample) * sc->sample_size; | |
1975 | else { | |
1976 | for (i = 0; i < (seek_sample - first_chunk_sample); i++) { | |
1977 | sample_file_offset += sc->sample_sizes[first_chunk_sample + i - 1]; | |
1978 | } | |
1979 | } | |
1980 | #ifdef DEBUG | |
1981 | av_log(s, AV_LOG_DEBUG, "Sample file offset is #%llu \n", sample_file_offset); | |
1982 | #endif | |
1983 | ||
1984 | // Step 6. Update the parser | |
1985 | mov->partial = sc; | |
1986 | mov->next_chunk_offset = sample_file_offset; | |
1987 | // Update current stream state | |
1988 | sc->current_sample = seek_sample - 1; // zero based | |
1989 | sc->left_in_chunk = left_in_chunk; | |
1990 | sc->next_chunk = chunk; // +1 -1 (zero based) | |
1991 | sc->sample_to_chunk_index = sample_to_chunk_idx; | |
1992 | ||
1993 | // Update other streams | |
1994 | for (i = 0; i<mov->total_streams; i++) { | |
5c030d3e | 1995 | MOVStreamContext *msc; |
baf25c9d GC |
1996 | if (i == mov_idx) continue; |
1997 | // Find the nearest 'next' chunk | |
5c030d3e | 1998 | msc = mov->streams[i]; |
baf25c9d GC |
1999 | a = 0; |
2000 | b = msc->chunk_count - 1; | |
2001 | while (a < b) { | |
2002 | m = (a + b + 1) >> 1; | |
2003 | if (msc->chunk_offsets[m] > chunk_file_offset) { | |
2004 | b = m - 1; | |
2005 | } else { | |
2006 | a = m; | |
2007 | } | |
2008 | #ifdef DEBUG | |
2009 | /* av_log(s, AV_LOG_DEBUG, "a=%i (%li) b=%i (%li) m=%i (%li) stream #%i\n" | |
2010 | , a, (long)msc->chunk_offsets[a], b, (long)msc->chunk_offsets[b], m, (long)msc->chunk_offsets[m], i); */ | |
2011 | #endif | |
2012 | } | |
2013 | msc->next_chunk = a; | |
2014 | if (msc->chunk_offsets[a] < chunk_file_offset && a < (msc->chunk_count-1)) | |
2015 | msc->next_chunk ++; | |
2016 | #ifdef DEBUG | |
2017 | av_log(s, AV_LOG_DEBUG, "Nearest next chunk for stream #%i is #%i @%lli\n", i, msc->next_chunk+1, msc->chunk_offsets[msc->next_chunk]); | |
2018 | #endif | |
2019 | // Compute sample count and index in the sample_to_chunk table (what a pity) | |
2020 | msc->sample_to_chunk_index = 0; | |
2021 | msc->current_sample = 0; | |
2022 | for(; msc->sample_to_chunk_index < (msc->sample_to_chunk_sz - 1) | |
2023 | && msc->sample_to_chunk[msc->sample_to_chunk_index + 1].first <= (1 + msc->next_chunk); msc->sample_to_chunk_index++) { | |
2024 | msc->current_sample += (msc->sample_to_chunk[msc->sample_to_chunk_index + 1].first - msc->sample_to_chunk[msc->sample_to_chunk_index].first) \ | |
2025 | * msc->sample_to_chunk[msc->sample_to_chunk_index].count; | |
2026 | } | |
2027 | msc->current_sample += (msc->next_chunk - (msc->sample_to_chunk[msc->sample_to_chunk_index].first - 1)) * sc->sample_to_chunk[msc->sample_to_chunk_index].count; | |
2028 | msc->left_in_chunk = msc->sample_to_chunk[msc->sample_to_chunk_index].count - 1; | |
2029 | #ifdef DEBUG | |
2030 | av_log(s, AV_LOG_DEBUG, "Next Sample for stream #%i is #%i @%i\n", i, msc->current_sample + 1, msc->sample_to_chunk_index + 1); | |
2031 | #endif | |
2032 | } | |
2033 | return 0; | |
2034 | } | |
2035 | #endif | |
2036 | ||
a266644f | 2037 | static int mov_read_close(AVFormatContext *s) |
6cea494e ZK |
2038 | { |
2039 | int i; | |
b6a17df4 | 2040 | MOVContext *mov = (MOVContext *) s->priv_data; |
6cea494e ZK |
2041 | for(i=0; i<mov->total_streams; i++) |
2042 | mov_free_stream_context(mov->streams[i]); | |
5ca1d879 ZK |
2043 | /* free color tabs */ |
2044 | for(i=0; i<mov->ctab_size; i++) | |
2045 | av_freep(&mov->ctab[i]); | |
2046 | av_freep(&mov->ctab); | |
6cea494e ZK |
2047 | return 0; |
2048 | } | |
2049 | ||
c9a65ca8 | 2050 | static AVInputFormat mov_iformat = { |
4cb3f3b6 | 2051 | "mov,mp4,m4a,3gp", |
c9a65ca8 FB |
2052 | "QuickTime/MPEG4 format", |
2053 | sizeof(MOVContext), | |
2054 | mov_probe, | |
6cea494e ZK |
2055 | mov_read_header, |
2056 | mov_read_packet, | |
2057 | mov_read_close, | |
baf25c9d GC |
2058 | #if defined(MOV_SPLIT_CHUNKS) && defined(MOV_SEEK) |
2059 | mov_read_seek, | |
2060 | #endif | |
6cea494e ZK |
2061 | }; |
2062 | ||
c9a65ca8 FB |
2063 | int mov_init(void) |
2064 | { | |
2065 | av_register_input_format(&mov_iformat); | |
2066 | return 0; | |
2067 | } |