3 * Copyright (c) 2001 Fabrice Bellard.
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.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 * First version by Francois Revol revol@free.fr
34 * Seek function by Gael Chardon gael.dev@4now.net
36 * Features and limitations:
37 * - reads most of the QT files I have (at least the structure),
38 * the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement.
39 * FIXED, Francois Revol, 07/17/2002
40 * - ffmpeg has nearly none of the usual QuickTime codecs,
41 * although I succesfully dumped raw and mp3 audio tracks off .mov files.
42 * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html
43 * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes
44 * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at
45 * http://mpeg.telecomitalialab.com/faq.htm
46 * - the code is quite ugly... maybe I won't do it recursive next time :-)
47 * - seek is not supported with files that contain edit list
49 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/
50 * when coding this :) (it's a writer anyway)
52 * Reference documents:
53 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
55 * http://developer.apple.com/documentation/QuickTime/QTFF/
56 * http://developer.apple.com/documentation/QuickTime/QTFF/qtff.pdf
57 * QuickTime is a trademark of Apple (AFAIK :))
60 #include "qtpalette.h"
69 /* Special handling for movies created with Minolta Dimaxe Xi*/
70 /* this fix should not interfere with other .mov files, but just in case*/
71 #define MOV_MINOLTA_FIX
73 /* some streams in QT (and in MP4 mostly) aren't either video nor audio */
74 /* so we first list them as this, then clean up the list of streams we give back, */
75 /* getting rid of these */
76 #define CODEC_TYPE_MOV_OTHER (enum CodecType) 2
78 /* http://gpac.sourceforge.net/tutorial/mediatypes.htm */
79 const CodecTag ff_mov_obj_type[] = {
80 { CODEC_ID_MPEG4 , 32 },
81 { CODEC_ID_H264 , 33 },
82 { CODEC_ID_AAC , 64 },
83 { CODEC_ID_MPEG2VIDEO, 96 }, /* MPEG2 Simple */
84 { CODEC_ID_MPEG2VIDEO, 97 }, /* MPEG2 Main */
85 { CODEC_ID_MPEG2VIDEO, 98 }, /* MPEG2 SNR */
86 { CODEC_ID_MPEG2VIDEO, 99 }, /* MPEG2 Spatial */
87 { CODEC_ID_MPEG2VIDEO, 100 }, /* MPEG2 High */
88 { CODEC_ID_MPEG2VIDEO, 101 }, /* MPEG2 422 */
89 { CODEC_ID_AAC , 102 }, /* MPEG2 AAC Main */
90 { CODEC_ID_AAC , 103 }, /* MPEG2 AAC Low */
91 { CODEC_ID_AAC , 104 }, /* MPEG2 AAC SSR */
92 { CODEC_ID_MP3 , 105 },
93 { CODEC_ID_MPEG1VIDEO, 106 },
94 { CODEC_ID_MP2 , 107 },
95 { CODEC_ID_MJPEG , 108 },
96 { CODEC_ID_PCM_S16LE , 224 },
97 { CODEC_ID_VORBIS , 225 },
98 { CODEC_ID_AC3 , 226 },
99 { CODEC_ID_PCM_ALAW , 227 },
100 { CODEC_ID_PCM_MULAW , 228 },
101 { CODEC_ID_PCM_S16BE , 230 },
102 { CODEC_ID_H263 , 242 },
103 { CODEC_ID_H261 , 243 },
107 static const CodecTag mov_video_tags[] = {
108 /* { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */
109 /* { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, *//* Uncompressed RGB */
110 /* { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, *//* Uncompressed YUV422 */
111 /* { CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'U', 'I') }, *//* YUV with alpha-channel (AVID Uncompressed) */
116 { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */
117 { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */
118 { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */
119 { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */
120 { CODEC_ID_MJPEG, MKTAG('A', 'V', 'D', 'J') }, /* MJPEG with alpha-channel (AVID JFIF meridien compressed) */
121 /* { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, *//* MJPEG with alpha-channel (AVID ABVB/Truevision NuVista) */
122 /* { CODEC_ID_GIF, MKTAG('g', 'i', 'f', ' ') }, *//* embedded gif files as frames (usually one "click to play movie" frame) */
124 { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') }, /* Sorenson Video v1 */
125 { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') }, /* Sorenson Video v1 */
126 { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', 'i') }, /* Sorenson Video v1 (from QT specs)*/
127 { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') }, /* Sorenson Video v3 */
128 { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
129 { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, /* OpenDiVX *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
130 { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
131 { CODEC_ID_MPEG4, MKTAG('3', 'I', 'V', '2') }, /* experimental: 3IVX files before ivx D4 4.5.1 */
132 /* { CODEC_ID_, MKTAG('I', 'V', '5', '0') }, *//* Indeo 5.0 */
133 { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, /* H263 */
134 { CODEC_ID_H263, MKTAG('s', '2', '6', '3') }, /* H263 ?? works */
135 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */
136 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */
137 /* { CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, *//* AVID dv */
138 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, /* On2 VP3 */
139 { CODEC_ID_RPZA, MKTAG('r', 'p', 'z', 'a') }, /* Apple Video (RPZA) */
140 { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') }, /* Cinepak */
141 { CODEC_ID_8BPS, MKTAG('8', 'B', 'P', 'S') }, /* Planar RGB (8BPS) */
142 { CODEC_ID_SMC, MKTAG('s', 'm', 'c', ' ') }, /* Apple Graphics (SMC) */
143 { CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') }, /* Apple Animation (RLE) */
144 { CODEC_ID_QDRAW, MKTAG('q', 'd', 'r', 'w') }, /* QuickDraw */
145 { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */
146 { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '2') }, /* MPEG2 produced by Sony HD camera */
147 { CODEC_ID_NONE, 0 },
150 static const CodecTag mov_audio_tags[] = {
151 /* { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, *//* uncompressed */
152 { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */
153 /* { CODEC_ID_PCM_S8, MKTAG('t', 'w', 'o', 's') },*/ /* 8 bits */
154 { CODEC_ID_PCM_U8, MKTAG('r', 'a', 'w', ' ') }, /* 8 bits unsigned */
155 { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /* */
156 { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /* */
157 { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /* */
158 { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, /* IMA-4 ADPCM */
159 { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, /* Macintosh Audio Compression and Expansion 3:1 */
160 { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, /* Macintosh Audio Compression and Expansion 6:1 */
162 { CODEC_ID_MP2, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */
163 { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */
164 { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */
165 /* { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
167 { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, /* MPEG-4 AAC */
168 /* The standard for mpeg4 audio is still not normalised AFAIK anyway */
169 { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') }, /* AMR-NB 3gp */
170 { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') }, /* AMR-WB 3gp */
171 { CODEC_ID_AC3, MKTAG('m', 's', 0x20, 0x00) }, /* Dolby AC-3 */
172 { CODEC_ID_ALAC,MKTAG('a', 'l', 'a', 'c') }, /* Apple Lossless */
173 { CODEC_ID_QDM2,MKTAG('Q', 'D', 'M', '2') }, /* QDM2 */
174 { CODEC_ID_NONE, 0 },
177 /* map numeric codes from mdhd atom to ISO 639 */
178 /* cf. QTFileFormat.pdf p253, qtff.pdf p205 */
179 /* http://developer.apple.com/documentation/mac/Text/Text-368.html */
180 /* deprecated by putting the code as 3*5bit ascii */
181 static const char *mov_mdhd_language_map[] = {
183 "eng", "fra", "ger", "ita", "dut", "sve", "spa", "dan", "por", "nor",
184 "heb", "jpn", "ara", "fin", "gre", "ice", "mlt", "tur", "hr "/*scr*/, "chi"/*ace?*/,
185 "urd", "hin", "tha", "kor", "lit", "pol", "hun", "est", "lav", NULL,
186 "fo ", NULL, "rus", "chi", NULL, "iri", "alb", "ron", "ces", "slk",
187 "slv", "yid", "sr ", "mac", "bul", "ukr", "bel", "uzb", "kaz", "aze",
189 "aze", "arm", "geo", "mol", "kir", "tgk", "tuk", "mon", NULL, "pus",
190 "kur", "kas", "snd", "tib", "nep", "san", "mar", "ben", "asm", "guj",
191 "pa ", "ori", "mal", "kan", "tam", "tel", NULL, "bur", "khm", "lao",
193 "vie", "ind", "tgl", "may", "may", "amh", "tir", "orm", "som", "swa",
195 NULL, "run", NULL, "mlg", "epo", NULL, NULL, NULL, NULL, NULL,
197 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
198 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "wel", "baq",
200 "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
203 /* the QuickTime file format is quite convoluted...
204 * it has lots of index tables, each indexing something in another one...
205 * Here we just use what is needed to read the chunks
208 typedef struct MOV_sample_to_chunk_tbl {
212 } MOV_sample_to_chunk_tbl;
217 int64_t size; /* total size (excluding the size and type fields) */
229 uint32_t flags; // 24bit
231 /* 0x03 ESDescrTag */
233 #define MP4ODescrTag 0x01
234 #define MP4IODescrTag 0x02
235 #define MP4ESDescrTag 0x03
236 #define MP4DecConfigDescrTag 0x04
237 #define MP4DecSpecificDescrTag 0x05
238 #define MP4SLConfigDescrTag 0x06
239 #define MP4ContentIdDescrTag 0x07
240 #define MP4SupplContentIdDescrTag 0x08
241 #define MP4IPIPtrDescrTag 0x09
242 #define MP4IPMPPtrDescrTag 0x0A
243 #define MP4IPMPDescrTag 0x0B
244 #define MP4RegistrationDescrTag 0x0D
245 #define MP4ESIDIncDescrTag 0x0E
246 #define MP4ESIDRefDescrTag 0x0F
247 #define MP4FileIODescrTag 0x10
248 #define MP4FileODescrTag 0x11
249 #define MP4ExtProfileLevelDescrTag 0x13
250 #define MP4ExtDescrTagsStart 0x80
251 #define MP4ExtDescrTagsEnd 0xFE
252 uint8_t stream_priority;
254 /* 0x04 DecConfigDescrTag */
255 uint8_t object_type_id;
257 /* XXX: really streamType is
258 * only 6bit, followed by:
262 uint32_t buffer_size_db; // 24
263 uint32_t max_bitrate;
264 uint32_t avg_bitrate;
266 /* 0x05 DecSpecificDescrTag */
267 uint8_t decoder_cfg_len;
268 uint8_t *decoder_cfg;
270 /* 0x06 SLConfigDescrTag */
271 uint8_t sl_config_len;
275 struct MOVParseTableEntry;
277 typedef struct Time2Sample{
282 typedef struct MOVStreamContext {
283 int ffindex; /* the ffmpeg stream id */
284 int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
287 int64_t *chunk_offsets;
289 Time2Sample *stts_data;
291 Time2Sample *ctts_data;
292 int edit_count; /* number of 'edit' (elst atom) */
293 long sample_to_chunk_sz;
294 MOV_sample_to_chunk_tbl *sample_to_chunk;
295 long sample_to_chunk_index;
296 int sample_to_time_index;
297 long sample_to_time_sample;
298 uint64_t sample_to_time_time;
299 int sample_to_ctime_index;
300 int sample_to_ctime_sample;
309 long left_in_chunk; /* how many samples before next chunk */
313 typedef struct MOVContext {
314 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) */
317 int duration; /* duration of the longest track */
318 int found_moov; /* when both 'moov' and 'mdat' sections has been found */
319 int found_mdat; /* we suppose we have enough data to read the file */
322 int ni; ///< non interleaved mode
324 /* some streams listed here aren't presented to the ffmpeg API, since they aren't either video nor audio
325 * but we need the info to be able to skip data from those streams in the 'mdat' section
327 MOVStreamContext *streams[MAX_STREAMS];
329 int64_t next_chunk_offset;
330 MOVStreamContext *partial; /* != 0 : there is still to read in the current chunk */
332 MOV_ctab_t **ctab; /* color tables */
333 const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */
334 /* NOTE: for recursion save to/ restore from local variable! */
336 AVPaletteControl palette_control;
340 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */
342 /* those functions parse an atom */
344 1: found what I wanted, exit
345 0: continue to parse next atom
346 -1: error occured, exit
348 typedef int (*mov_parse_function)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom);
350 /* links atom IDs to parse functions */
351 typedef struct MOVParseTableEntry {
353 mov_parse_function func;
354 } MOVParseTableEntry;
356 static int ff_mov_lang_to_iso639(int code, char *to)
359 /* is it the mangled iso code? */
360 /* see http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt */
362 for (i = 2; i >= 0; i--) {
363 to[i] = 0x60 + (code & 0x1f);
368 /* old fashion apple lang code */
369 if (code >= (sizeof(mov_mdhd_language_map)/sizeof(char *)))
371 if (!mov_mdhd_language_map[code])
373 strncpy(to, mov_mdhd_language_map[code], 4);
377 extern int ff_mov_iso639_to_lang(const char *lang, int mp4); /* for movenc.c */
378 int ff_mov_iso639_to_lang(const char *lang, int mp4)
382 /* old way, only for QT? */
383 for (i = 0; !mp4 && (i < (sizeof(mov_mdhd_language_map)/sizeof(char *))); i++) {
384 if (mov_mdhd_language_map[i] && !strcmp(lang, mov_mdhd_language_map[i]))
387 /* XXX:can we do that in mov too? */
390 /* handle undefined as such */
394 for (i = 0; i < 3; i++) {
395 unsigned char c = (unsigned char)lang[i];
406 static int mov_read_leaf(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
409 url_fskip(pb, atom.size);
410 /* url_seek(pb, atom_offset+atom.size, SEEK_SET); */
414 static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
416 int64_t total_size = 0;
421 a.offset = atom.offset;
424 atom.size = 0x7fffffffffffffffLL;
425 while(((total_size + 8) < atom.size) && !url_feof(pb) && !err) {
429 a.size = get_be32(pb);
430 a.type = get_le32(pb);
434 dprintf("type: %08x %.4s sz: %Lx %Lx %Lx\n", a.type, (char*)&a.type, a.size, atom.size, total_size);
435 if (a.size == 1) { /* 64 bit extended size */
436 a.size = get_be64(pb) - 8;
441 a.size = atom.size - total_size;
445 for (i = 0; c->parse_table[i].type != 0L
446 && c->parse_table[i].type != a.type; i++)
454 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */
455 url_fskip(pb, a.size);
457 err = (c->parse_table[i].func)(c, pb, a);
461 total_size += a.size;
464 if (!err && total_size < atom.size && atom.size < 0x7ffff) {
465 url_fskip(pb, atom.size - total_size);
471 static int mov_read_ctab(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
474 url_fskip(pb, atom.size); // for now
476 VERY VERY BROKEN, NEVER execute this, needs rewrite
479 c->ctab = av_realloc(c->ctab, ++c->ctab_size);
480 t = c->ctab[c->ctab_size];
481 t->seed = get_be32(pb);
482 t->flags = get_be16(pb);
483 t->size = get_be16(pb) + 1;
484 len = 2 * t->size * 4;
486 t->clrs = av_malloc(len); // 16bit A R G B
488 get_buffer(pb, t->clrs, len);
495 static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
497 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
502 get_byte(pb); /* version */
503 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
506 ctype = get_le32(pb);
507 type = get_le32(pb); /* component subtype */
509 dprintf("ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype);
510 dprintf("stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]);
511 if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */
512 /* helps parsing the string hereafter... */
514 if(type == MKTAG('v', 'i', 'd', 'e'))
515 st->codec->codec_type = CODEC_TYPE_VIDEO;
516 else if(type == MKTAG('s', 'o', 'u', 'n'))
517 st->codec->codec_type = CODEC_TYPE_AUDIO;
518 } else if(ctype == 0) { /* MP4 */
519 /* helps parsing the string hereafter... */
521 if(type == MKTAG('v', 'i', 'd', 'e'))
522 st->codec->codec_type = CODEC_TYPE_VIDEO;
523 else if(type == MKTAG('s', 'o', 'u', 'n'))
524 st->codec->codec_type = CODEC_TYPE_AUDIO;
526 get_be32(pb); /* component manufacture */
527 get_be32(pb); /* component flags */
528 get_be32(pb); /* component flags mask */
531 return 0; /* nothing left to read */
532 /* XXX: MP4 uses a C string, not a pascal one */
537 while(get_byte(pb) && (++len < (atom.size - 24)));
539 /* .mov: PASCAL string */
544 url_fskip(pb, atom.size - (url_ftell(pb) - atom.offset));
548 static int mov_mp4_read_descr_len(ByteIOContext *pb)
553 int c = get_byte(pb);
554 len = (len << 7) | (c & 0x7f);
561 static int mov_mp4_read_descr(ByteIOContext *pb, int *tag)
565 len = mov_mp4_read_descr_len(pb);
566 dprintf("MPEG4 description: tag=0x%02x len=%d\n", *tag, len);
570 static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
572 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
573 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
574 int64_t start_pos = url_ftell(pb);
577 /* Well, broken but suffisant for some MP4 streams */
578 get_be32(pb); /* version + flags */
579 len = mov_mp4_read_descr(pb, &tag);
580 if (tag == MP4ESDescrTag) {
581 get_be16(pb); /* ID */
582 get_byte(pb); /* priority */
584 get_be16(pb); /* ID */
586 len = mov_mp4_read_descr(pb, &tag);
587 if (tag == MP4DecConfigDescrTag) {
588 sc->esds.object_type_id = get_byte(pb);
589 sc->esds.stream_type = get_byte(pb);
590 sc->esds.buffer_size_db = get_be24(pb);
591 sc->esds.max_bitrate = get_be32(pb);
592 sc->esds.avg_bitrate = get_be32(pb);
594 st->codec->codec_id= codec_get_id(ff_mov_obj_type, sc->esds.object_type_id);
595 len = mov_mp4_read_descr(pb, &tag);
596 if (tag == MP4DecSpecificDescrTag) {
597 dprintf("Specific MPEG4 header len=%d\n", len);
598 st->codec->extradata = (uint8_t*) av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
599 if (st->codec->extradata) {
600 get_buffer(pb, st->codec->extradata, len);
601 st->codec->extradata_size = len;
605 /* in any case, skip garbage */
606 url_fskip(pb, atom.size - ((url_ftell(pb) - start_pos)));
610 /* this atom contains actual media data */
611 static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
613 if(atom.size == 0) /* wrong one (MP4) */
616 c->mdat_offset = atom.offset;
617 c->mdat_size = atom.size;
619 return 1; /* found both, just go */
620 url_fskip(pb, atom.size);
621 return 0; /* now go for moov */
624 /* this atom should contain all header atoms */
625 static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
629 err = mov_read_default(c, pb, atom);
630 /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
631 /* so we don't parse the whole file if over a network */
634 return 1; /* found both, just go */
635 return 0; /* now go for mdat */
639 static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
644 version = get_byte(pb); /* version */
646 return 1; /* unsupported */
648 get_byte(pb); get_byte(pb);
649 get_byte(pb); /* flags */
651 (version==1)?get_be64(pb):get_be32(pb); /* creation time */
652 (version==1)?get_be64(pb):get_be32(pb); /* modification time */
654 c->streams[c->fc->nb_streams-1]->time_scale = get_be32(pb);
655 c->fc->streams[c->fc->nb_streams-1]->duration = (version==1)?get_be64(pb):get_be32(pb); /* duration */
657 lang = get_be16(pb); /* language */
658 ff_mov_lang_to_iso639(lang, c->fc->streams[c->fc->nb_streams-1]->language);
659 get_be16(pb); /* quality */
664 static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
666 get_byte(pb); /* version */
667 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
669 get_be32(pb); /* creation time */
670 get_be32(pb); /* modification time */
671 c->time_scale = get_be32(pb); /* time scale */
673 av_log(NULL, AV_LOG_DEBUG, "time scale = %i\n", c->time_scale);
675 c->duration = get_be32(pb); /* duration */
676 get_be32(pb); /* preferred scale */
678 get_be16(pb); /* preferred volume */
680 url_fskip(pb, 10); /* reserved */
682 url_fskip(pb, 36); /* display matrix */
684 get_be32(pb); /* preview time */
685 get_be32(pb); /* preview duration */
686 get_be32(pb); /* poster time */
687 get_be32(pb); /* selection time */
688 get_be32(pb); /* selection duration */
689 get_be32(pb); /* current time */
690 get_be32(pb); /* next track ID */
695 static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
697 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
699 if((uint64_t)atom.size > (1<<30))
702 // currently SVQ3 decoder expect full STSD header - so let's fake it
703 // this should be fixed and just SMI header should be passed
704 av_free(st->codec->extradata);
705 st->codec->extradata_size = 0x5a + atom.size;
706 st->codec->extradata = (uint8_t*) av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
708 if (st->codec->extradata) {
709 strcpy(st->codec->extradata, "SVQ3"); // fake
710 get_buffer(pb, st->codec->extradata + 0x5a, atom.size);
711 dprintf("Reading SMI %Ld %s\n", atom.size, (char*)st->codec->extradata + 0x5a);
713 url_fskip(pb, atom.size);
718 static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
720 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
722 if((uint64_t)atom.size > (1<<30))
725 if (st->codec->codec_id == CODEC_ID_QDM2) {
726 // pass all frma atom to codec, needed at least for QDM2
727 av_free(st->codec->extradata);
728 st->codec->extradata_size = atom.size;
729 st->codec->extradata = (uint8_t*) av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
731 if (st->codec->extradata) {
732 get_buffer(pb, st->codec->extradata, atom.size);
734 url_fskip(pb, atom.size);
735 } else if (atom.size > 8) { /* to read frma, esds atoms */
736 mov_read_default(c, pb, atom);
737 } else if (atom.size > 0)
738 url_fskip(pb, atom.size);
742 static int mov_read_avcC(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
744 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
746 if((uint64_t)atom.size > (1<<30))
749 av_free(st->codec->extradata);
751 st->codec->extradata_size = atom.size;
752 st->codec->extradata = (uint8_t*) av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
754 if (st->codec->extradata) {
755 get_buffer(pb, st->codec->extradata, atom.size);
757 url_fskip(pb, atom.size);
762 static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
764 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
765 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
766 unsigned int i, entries;
768 get_byte(pb); /* version */
769 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
771 entries = get_be32(pb);
773 if(entries >= UINT_MAX/sizeof(int64_t))
776 sc->chunk_count = entries;
777 sc->chunk_offsets = (int64_t*) av_malloc(entries * sizeof(int64_t));
778 if (!sc->chunk_offsets)
780 if (atom.type == MKTAG('s', 't', 'c', 'o')) {
781 for(i=0; i<entries; i++) {
782 sc->chunk_offsets[i] = get_be32(pb);
784 } else if (atom.type == MKTAG('c', 'o', '6', '4')) {
785 for(i=0; i<entries; i++) {
786 sc->chunk_offsets[i] = get_be64(pb);
791 for(i=0; i<c->fc->nb_streams; i++){
792 MOVStreamContext *sc2 = (MOVStreamContext *)c->fc->streams[i]->priv_data;
793 if(sc2 && sc2->chunk_offsets){
794 int64_t first= sc2->chunk_offsets[0];
795 int64_t last= sc2->chunk_offsets[sc2->chunk_count-1];
796 if(first >= sc->chunk_offsets[entries-1] || last <= sc->chunk_offsets[0])
803 static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
805 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
806 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
807 int entries, frames_per_sample;
809 uint8_t codec_name[32];
811 /* for palette traversal */
819 unsigned char *color_table;
821 unsigned char r, g, b;
823 get_byte(pb); /* version */
824 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
826 entries = get_be32(pb);
828 while(entries--) { //Parsing Sample description table
830 offset_t start_pos = url_ftell(pb);
831 int size = get_be32(pb); /* size */
832 format = get_le32(pb); /* data format */
834 get_be32(pb); /* reserved */
835 get_be16(pb); /* reserved */
836 get_be16(pb); /* index */
838 /* for MPEG4: set codec type by looking for it */
839 id = codec_get_id(mov_video_tags, format);
841 id = codec_get_id(codec_bmp_tags, format);
844 codec = avcodec_find_decoder(id);
846 st->codec->codec_type = codec->type;
848 dprintf("size=%d 4CC= %c%c%c%c codec_type=%d\n",
850 (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, (format >> 24) & 0xff,
851 st->codec->codec_type);
852 st->codec->codec_tag = format;
853 if(st->codec->codec_type==CODEC_TYPE_VIDEO) {
854 MOV_atom_t a = { 0, 0, 0 };
855 st->codec->codec_id = id;
856 get_be16(pb); /* version */
857 get_be16(pb); /* revision level */
858 get_be32(pb); /* vendor */
859 get_be32(pb); /* temporal quality */
860 get_be32(pb); /* spacial quality */
861 if(st->codec->codec_id == CODEC_ID_MPEG4){ //FIXME this is silly
865 st->codec->width = get_be16(pb); /* width */
866 st->codec->height = get_be16(pb); /* height */
868 get_be32(pb); /* horiz resolution */
869 get_be32(pb); /* vert resolution */
870 get_be32(pb); /* data size, always 0 */
871 frames_per_sample = get_be16(pb); /* frames per samples */
873 av_log(NULL, AV_LOG_DEBUG, "frames/samples = %d\n", frames_per_sample);
875 get_buffer(pb, codec_name, 32); /* codec name, pascal string (FIXME: true for mp4?) */
876 if (codec_name[0] <= 31) {
877 memcpy(st->codec->codec_name, &codec_name[1],codec_name[0]);
878 st->codec->codec_name[codec_name[0]] = 0;
881 st->codec->bits_per_sample = get_be16(pb); /* depth */
882 st->codec->color_table_id = get_be16(pb); /* colortable id */
884 /* These are set in mov_read_stts and might already be set!
885 st->codec->time_base.den = 25;
886 st->codec->time_base.num = 1;
893 a.size = get_be32(pb);
894 a.type = get_le32(pb);
897 av_log(NULL, AV_LOG_DEBUG, "VIDEO: atom_type=%c%c%c%c atom.size=%Ld size_left=%d\n",
898 (a.type >> 0) & 0xff,
899 (a.type >> 8) & 0xff,
900 (a.type >> 16) & 0xff,
901 (a.type >> 24) & 0xff,
904 start_pos = url_ftell(pb);
907 case MKTAG('e', 's', 'd', 's'):
910 /* Well, broken but suffisant for some MP4 streams */
911 get_be32(pb); /* version + flags */
912 len = mov_mp4_read_descr(pb, &tag);
915 get_be16(pb); /* ID */
916 get_byte(pb); /* priority */
917 len = mov_mp4_read_descr(pb, &tag);
920 /* MP4DecConfigDescrTag */
921 get_byte(pb); /* objectTypeId */
922 get_be32(pb); /* streamType + buffer size */
923 get_be32(pb); /* max bit rate */
924 get_be32(pb); /* avg bit rate */
925 len = mov_mp4_read_descr(pb, &tag);
928 /* MP4DecSpecificDescrTag */
929 sc->header_data = av_mallocz(len);
930 if (sc->header_data) {
931 get_buffer(pb, sc->header_data, len);
932 sc->header_len = len;
935 /* in any case, skip garbage */
942 dprintf("ATOMENEWSIZE %Ld %d\n", atom.size, url_ftell(pb) - start_pos);
944 url_fskip(pb, (atom.size - 8) -
945 ((url_ftell(pb) - start_pos)));
946 size -= atom.size - 8;
950 /* unknown extension */
955 /* figure out the palette situation */
956 color_depth = st->codec->bits_per_sample & 0x1F;
957 color_greyscale = st->codec->bits_per_sample & 0x20;
959 /* if the depth is 2, 4, or 8 bpp, file is palettized */
960 if ((color_depth == 2) || (color_depth == 4) ||
961 (color_depth == 8)) {
963 if (color_greyscale) {
965 /* compute the greyscale palette */
966 color_count = 1 << color_depth;
968 color_dec = 256 / (color_count - 1);
969 for (j = 0; j < color_count; j++) {
970 r = g = b = color_index;
971 c->palette_control.palette[j] =
972 (r << 16) | (g << 8) | (b);
973 color_index -= color_dec;
978 } else if (st->codec->color_table_id & 0x08) {
980 /* if flag bit 3 is set, use the default palette */
981 color_count = 1 << color_depth;
982 if (color_depth == 2)
983 color_table = ff_qt_default_palette_4;
984 else if (color_depth == 4)
985 color_table = ff_qt_default_palette_16;
987 color_table = ff_qt_default_palette_256;
989 for (j = 0; j < color_count; j++) {
990 r = color_table[j * 4 + 0];
991 g = color_table[j * 4 + 1];
992 b = color_table[j * 4 + 2];
993 c->palette_control.palette[j] =
994 (r << 16) | (g << 8) | (b);
999 /* load the palette from the file */
1000 color_start = get_be32(pb);
1001 color_count = get_be16(pb);
1002 color_end = get_be16(pb);
1003 for (j = color_start; j <= color_end; j++) {
1004 /* each R, G, or B component is 16 bits;
1005 * only use the top 8 bits; skip alpha bytes
1015 c->palette_control.palette[j] =
1016 (r << 16) | (g << 8) | (b);
1020 st->codec->palctrl = &c->palette_control;
1021 st->codec->palctrl->palette_changed = 1;
1023 st->codec->palctrl = NULL;
1025 a.size = size - (url_ftell(pb) - start_pos);
1027 mov_read_default(c, pb, a);
1028 else if (a.size > 0)
1029 url_fskip(pb, a.size);
1032 st->codec->codec_id = codec_get_id(mov_audio_tags, format);
1033 if(st->codec->codec_id==CODEC_ID_AMR_NB || st->codec->codec_id==CODEC_ID_AMR_WB) //from TS26.244
1035 dprintf("AMR audio identified %d!!\n", st->codec->codec_id);
1036 get_be32(pb);get_be32(pb); //Reserved_8
1037 get_be16(pb);//Reserved_2
1038 get_be16(pb);//Reserved_2
1039 get_be32(pb);//Reserved_4
1040 get_be16(pb);//TimeScale
1041 get_be16(pb);//Reserved_2
1043 //AMRSpecificBox.(10 bytes)
1045 get_be32(pb); //size
1046 get_be32(pb); //type=='damr'
1047 get_be32(pb); //vendor
1048 get_byte(pb); //decoder version
1049 get_be16(pb); //mode_set
1050 get_byte(pb); //mode_change_period
1051 get_byte(pb); //frames_per_sample
1053 st->duration = AV_NOPTS_VALUE;//Not possible to get from this info, must count number of AMR frames
1054 if(st->codec->codec_id==CODEC_ID_AMR_NB)
1056 st->codec->sample_rate=8000;
1057 st->codec->channels=1;
1061 st->codec->sample_rate=16000;
1062 st->codec->channels=1;
1064 st->codec->bits_per_sample=16;
1065 st->codec->bit_rate=0; /*It is not possible to tell this before we have
1066 an audio frame and even then every frame can be different*/
1068 else if( st->codec->codec_tag == MKTAG( 'm', 'p', '4', 's' ))
1070 //This is some stuff for the hint track, lets ignore it!
1071 //Do some mp4 auto detect.
1074 url_fskip(pb, size); /* The mp4s atom also contians a esds atom that we can skip*/
1076 else if( st->codec->codec_tag == MKTAG( 'm', 'p', '4', 'a' ))
1081 /* Handle mp4 audio tag */
1082 mp4_version=get_be16(pb);/*version*/
1083 get_be16(pb); /*revesion*/
1085 st->codec->channels = get_be16(pb); /* channels */
1086 st->codec->bits_per_sample = get_be16(pb); /* bits per sample */
1088 st->codec->sample_rate = get_be16(pb); /* sample rate, not always correct */
1089 if(st->codec->sample_rate == 1) //nonsese rate? -> ignore
1090 st->codec->sample_rate= 0;
1098 a.size=size-(16+20+16);
1101 a.size=size-(16+20);
1103 a.offset=url_ftell(pb);
1105 mov_read_default(c, pb, a);
1107 /* Get correct sample rate from extradata */
1108 if(st->codec->extradata_size) {
1109 const int samplerate_table[] = {
1110 96000, 88200, 64000, 48000, 44100, 32000,
1111 24000, 22050, 16000, 12000, 11025, 8000,
1114 unsigned char *px = st->codec->extradata;
1115 // 5 bits objectTypeIndex, 4 bits sampleRateIndex, 4 bits channels
1116 int samplerate_index = ((px[0] & 7) << 1) + ((px[1] >> 7) & 1);
1117 st->codec->sample_rate = samplerate_table[samplerate_index];
1118 st->codec->channels = (px[1] >> 3) & 15;
1121 else if( st->codec->codec_tag == MKTAG( 'a', 'l', 'a', 'c' ))
1123 /* Handle alac audio tag + special extradata */
1124 get_be32(pb); /* version */
1126 st->codec->channels = get_be16(pb); /* channels */
1127 st->codec->bits_per_sample = get_be16(pb); /* bits per sample */
1129 st->codec->sample_rate = get_be16(pb);
1132 /* fetch the 36-byte extradata needed for alac decoding */
1133 st->codec->extradata_size = 36;
1134 st->codec->extradata = (uint8_t*)
1135 av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
1136 get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
1138 else if(size>=(16+20))
1139 {//16 bytes read, reading atleast 20 more
1141 version = get_be16(pb); /* version */
1142 get_be16(pb); /* revision level */
1143 get_be32(pb); /* vendor */
1145 st->codec->channels = get_be16(pb); /* channel count */
1146 st->codec->bits_per_sample = get_be16(pb); /* sample size */
1148 /* handle specific s8 codec */
1149 get_be16(pb); /* compression id = 0*/
1150 get_be16(pb); /* packet size = 0 */
1152 st->codec->sample_rate = ((get_be32(pb) >> 16));
1154 switch (st->codec->codec_id) {
1155 case CODEC_ID_PCM_S16BE:
1156 if (st->codec->bits_per_sample == 8)
1157 st->codec->codec_id = CODEC_ID_PCM_S8;
1159 case CODEC_ID_PCM_U8:
1160 st->codec->bit_rate = st->codec->sample_rate * 8;
1166 //Read QT version 1 fields. In version 0 theese dont exist
1167 dprintf("version =%d mp4=%d\n",version,c->mp4);
1168 if((version==1) && size>=(16+20+16))
1170 get_be32(pb); /* samples per packet */
1171 get_be32(pb); /* bytes per packet */
1172 get_be32(pb); /* bytes per frame */
1173 get_be32(pb); /* bytes per sample */
1176 //Optional, additional atom-based fields
1177 MOV_atom_t a = { format, url_ftell(pb), size - (16 + 20 + 16 + 8) };
1178 mov_read_default(c, pb, a);
1183 //We should be down to 0 bytes here, but lets make sure.
1186 dprintf("skipping 0x%X bytes\n",size-(16+20));
1187 url_fskip(pb, size);
1194 //Unknown size, but lets do our best and skip the rest.
1195 dprintf("Strange size, skipping 0x%X bytes\n",size);
1196 url_fskip(pb, size);
1201 if(st->codec->codec_type==CODEC_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) {
1202 st->codec->sample_rate= sc->time_scale;
1208 static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1210 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
1211 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
1212 unsigned int i, entries;
1214 get_byte(pb); /* version */
1215 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1217 entries = get_be32(pb);
1219 if(entries >= UINT_MAX / sizeof(MOV_sample_to_chunk_tbl))
1223 av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries);
1225 sc->sample_to_chunk_sz = entries;
1226 sc->sample_to_chunk = (MOV_sample_to_chunk_tbl*) av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl));
1227 if (!sc->sample_to_chunk)
1229 for(i=0; i<entries; i++) {
1230 sc->sample_to_chunk[i].first = get_be32(pb);
1231 sc->sample_to_chunk[i].count = get_be32(pb);
1232 sc->sample_to_chunk[i].id = get_be32(pb);
1237 static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1239 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
1240 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
1241 unsigned int i, entries;
1243 get_byte(pb); /* version */
1244 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1246 entries = get_be32(pb);
1248 if(entries >= UINT_MAX / sizeof(long))
1251 sc->keyframe_count = entries;
1253 av_log(NULL, AV_LOG_DEBUG, "keyframe_count = %ld\n", sc->keyframe_count);
1255 sc->keyframes = (long*) av_malloc(entries * sizeof(long));
1258 for(i=0; i<entries; i++) {
1259 sc->keyframes[i] = get_be32(pb);
1261 /* av_log(NULL, AV_LOG_DEBUG, "keyframes[]=%ld\n", sc->keyframes[i]); */
1267 static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1269 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
1270 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
1271 unsigned int i, entries;
1273 get_byte(pb); /* version */
1274 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1276 sc->sample_size = get_be32(pb);
1277 entries = get_be32(pb);
1278 if(entries >= UINT_MAX / sizeof(long))
1281 sc->sample_count = entries;
1283 av_log(NULL, AV_LOG_DEBUG, "sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count);
1286 return 0; /* there isn't any table following */
1287 sc->sample_sizes = (long*) av_malloc(entries * sizeof(long));
1288 if (!sc->sample_sizes)
1290 for(i=0; i<entries; i++) {
1291 sc->sample_sizes[i] = get_be32(pb);
1293 av_log(NULL, AV_LOG_DEBUG, "sample_sizes[]=%ld\n", sc->sample_sizes[i]);
1299 static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1301 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
1302 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
1303 unsigned int i, entries;
1305 int64_t total_sample_count=0;
1307 get_byte(pb); /* version */
1308 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1309 entries = get_be32(pb);
1310 if(entries >= UINT_MAX / sizeof(Time2Sample))
1313 sc->stts_count = entries;
1314 sc->stts_data = av_malloc(entries * sizeof(Time2Sample));
1317 av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries);
1322 for(i=0; i<entries; i++) {
1323 int sample_duration;
1326 sample_count=get_be32(pb);
1327 sample_duration = get_be32(pb);
1328 sc->stts_data[i].count= sample_count;
1329 sc->stts_data[i].duration= sample_duration;
1331 sc->time_rate= ff_gcd(sc->time_rate, sample_duration);
1333 dprintf("sample_count=%d, sample_duration=%d\n",sample_count,sample_duration);
1335 duration+=sample_duration*sample_count;
1336 total_sample_count+=sample_count;
1339 st->nb_frames= total_sample_count;
1341 st->duration= duration;
1345 static int mov_read_ctts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1347 unsigned int i, entries;
1349 get_byte(pb); /* version */
1350 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1351 entries = get_be32(pb);
1352 if(entries >= UINT_MAX / sizeof(Time2Sample))
1355 c->streams[c->fc->nb_streams-1]->ctts_count = entries;
1356 c->streams[c->fc->nb_streams-1]->ctts_data = av_malloc(entries * sizeof(Time2Sample));
1358 dprintf("track[%i].ctts.entries = %i\n", c->fc->nb_streams-1, entries);
1360 for(i=0; i<entries; i++) {
1361 c->streams[c->fc->nb_streams - 1]->ctts_data[i].count= get_be32(pb);
1362 c->streams[c->fc->nb_streams - 1]->ctts_data[i].duration= get_be32(pb);
1367 static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1370 MOVStreamContext *sc;
1372 st = av_new_stream(c->fc, c->fc->nb_streams);
1374 sc = (MOVStreamContext*) av_mallocz(sizeof(MOVStreamContext));
1380 sc->sample_to_chunk_index = -1;
1382 st->codec->codec_type = CODEC_TYPE_MOV_OTHER;
1383 st->start_time = 0; /* XXX: check */
1384 c->streams[c->fc->nb_streams-1] = sc;
1386 return mov_read_default(c, pb, atom);
1389 static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1393 st = c->fc->streams[c->fc->nb_streams-1];
1395 get_byte(pb); /* version */
1397 get_byte(pb); get_byte(pb);
1398 get_byte(pb); /* flags */
1400 MOV_TRACK_ENABLED 0x0001
1401 MOV_TRACK_IN_MOVIE 0x0002
1402 MOV_TRACK_IN_PREVIEW 0x0004
1403 MOV_TRACK_IN_POSTER 0x0008
1406 get_be32(pb); /* creation time */
1407 get_be32(pb); /* modification time */
1408 st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/
1409 get_be32(pb); /* reserved */
1410 st->start_time = 0; /* check */
1411 get_be32(pb); /* highlevel (considering edits) duration in movie timebase */
1412 get_be32(pb); /* reserved */
1413 get_be32(pb); /* reserved */
1415 get_be16(pb); /* layer */
1416 get_be16(pb); /* alternate group */
1417 get_be16(pb); /* volume */
1418 get_be16(pb); /* reserved */
1420 url_fskip(pb, 36); /* display matrix */
1422 /* those are fixed-point */
1423 /*st->codec->width =*/ get_be32(pb) >> 16; /* track width */
1424 /*st->codec->height =*/ get_be32(pb) >> 16; /* track height */
1429 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
1430 /* like the files created with Adobe Premiere 5.0, for samples see */
1431 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
1432 static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1437 return 0; /* continue */
1438 if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */
1439 url_fskip(pb, atom.size - 4);
1442 atom.type = get_le32(pb);
1445 if (atom.type != MKTAG('m', 'd', 'a', 't')) {
1446 url_fskip(pb, atom.size);
1449 err = mov_read_mdat(c, pb, atom);
1455 static int null_read_packet(void *opaque, uint8_t *buf, int buf_size)
1460 static int mov_read_cmov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1464 uint8_t *moov_data; /* uncompressed data */
1465 long cmov_len, moov_len;
1468 get_be32(pb); /* dcom atom */
1469 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' ))
1471 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) {
1472 av_log(NULL, AV_LOG_ERROR, "unknown compression for cmov atom !");
1475 get_be32(pb); /* cmvd atom */
1476 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' ))
1478 moov_len = get_be32(pb); /* uncompressed size */
1479 cmov_len = atom.size - 6 * 4;
1481 cmov_data = (uint8_t *) av_malloc(cmov_len);
1484 moov_data = (uint8_t *) av_malloc(moov_len);
1489 get_buffer(pb, cmov_data, cmov_len);
1490 if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK)
1492 if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0)
1494 ctx.buf_end = ctx.buffer + moov_len;
1495 atom.type = MKTAG( 'm', 'o', 'o', 'v' );
1497 atom.size = moov_len;
1499 // { int fd = open("/tmp/uncompheader.mov", O_WRONLY | O_CREAT); write(fd, moov_data, moov_len); close(fd); }
1501 ret = mov_read_default(c, &ctx, atom);
1509 /* edit list atom */
1510 static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1514 get_byte(pb); /* version */
1515 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1516 edit_count= c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */
1518 for(i=0; i<edit_count; i++){
1519 get_be32(pb); /* Track duration */
1520 get_be32(pb); /* Media time */
1521 get_be32(pb); /* Media rate */
1523 dprintf("track[%i].edit_count = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count);
1527 static const MOVParseTableEntry mov_default_parse_table[] = {
1529 { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco },
1530 { MKTAG( 'c', 'p', 'r', 't' ), mov_read_default },
1531 { MKTAG( 'c', 'r', 'h', 'd' ), mov_read_default },
1532 { MKTAG( 'c', 't', 't', 's' ), mov_read_ctts }, /* composition time to sample */
1533 { MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */
1534 { MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf },
1535 { MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf },
1536 { MKTAG( 'e', 'd', 't', 's' ), mov_read_default },
1537 { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst },
1538 { MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf },
1539 { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr },
1540 { MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf },
1541 { MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf },
1542 { MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf },
1543 { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat },
1544 { MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd },
1545 { MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default },
1546 { MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default },
1547 { MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov },
1548 { MKTAG( 'm', 'p', '4', 'a' ), mov_read_default },
1549 { MKTAG( 'm', 'p', '4', 's' ), mov_read_default },
1550 { MKTAG( 'm', 'p', '4', 'v' ), mov_read_default },
1551 { MKTAG( 'm', 'p', 'o', 'd' ), mov_read_leaf },
1552 { MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd },
1553 { MKTAG( 'n', 'm', 'h', 'd' ), mov_read_leaf },
1554 { MKTAG( 'o', 'd', 'h', 'd' ), mov_read_default },
1555 { MKTAG( 's', 'd', 'h', 'd' ), mov_read_default },
1556 { MKTAG( 's', 'k', 'i', 'p' ), mov_read_leaf },
1557 { MKTAG( 's', 'm', 'h', 'd' ), mov_read_leaf }, /* sound media info header */
1558 { MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */
1559 { MKTAG( 'a', 'v', 'c', 'C' ), mov_read_avcC },
1560 { MKTAG( 's', 't', 'b', 'l' ), mov_read_default },
1561 { MKTAG( 's', 't', 'c', 'o' ), mov_read_stco },
1562 { MKTAG( 's', 't', 'd', 'p' ), mov_read_default },
1563 { MKTAG( 's', 't', 's', 'c' ), mov_read_stsc },
1564 { MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */
1565 { MKTAG( 's', 't', 's', 'h' ), mov_read_default },
1566 { MKTAG( 's', 't', 's', 's' ), mov_read_stss }, /* sync sample */
1567 { MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */
1568 { MKTAG( 's', 't', 't', 's' ), mov_read_stts },
1569 { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */
1570 { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak },
1571 { MKTAG( 't', 'r', 'e', 'f' ), mov_read_default }, /* not really */
1572 { MKTAG( 'u', 'd', 't', 'a' ), mov_read_leaf },
1573 { MKTAG( 'u', 'r', 'l', ' ' ), mov_read_leaf },
1574 { MKTAG( 'u', 'r', 'n', ' ' ), mov_read_leaf },
1575 { MKTAG( 'u', 'u', 'i', 'd' ), mov_read_leaf },
1576 { MKTAG( 'v', 'm', 'h', 'd' ), mov_read_leaf }, /* video media info header */
1577 { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave },
1579 { MKTAG( 'M', 'D', 'E', 'S' ), mov_read_leaf },
1581 { MKTAG( 'c', 'h', 'a', 'p' ), mov_read_leaf },
1582 { MKTAG( 'c', 'l', 'i', 'p' ), mov_read_default },
1583 { MKTAG( 'c', 'r', 'g', 'n' ), mov_read_leaf },
1584 { MKTAG( 'c', 't', 'a', 'b' ), mov_read_ctab },
1585 { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds },
1586 { MKTAG( 'k', 'm', 'a', 't' ), mov_read_leaf },
1587 { MKTAG( 'm', 'a', 't', 't' ), mov_read_default },
1588 { MKTAG( 'r', 'd', 'r', 'f' ), mov_read_leaf },
1589 { MKTAG( 'r', 'm', 'd', 'a' ), mov_read_default },
1590 { MKTAG( 'r', 'm', 'd', 'r' ), mov_read_leaf },
1591 { MKTAG( 'r', 'm', 'r', 'a' ), mov_read_default },
1592 { MKTAG( 's', 'c', 'p', 't' ), mov_read_leaf },
1593 { MKTAG( 's', 's', 'r', 'c' ), mov_read_leaf },
1594 { MKTAG( 's', 'y', 'n', 'c' ), mov_read_leaf },
1595 { MKTAG( 't', 'c', 'm', 'd' ), mov_read_leaf },
1596 { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */
1597 //{ MKTAG( 'r', 'm', 'q', 'u' ), mov_read_leaf },
1599 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov },
1601 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_leaf },
1603 { 0L, mov_read_leaf }
1606 static void mov_free_stream_context(MOVStreamContext *sc)
1609 av_freep(&sc->chunk_offsets);
1610 av_freep(&sc->sample_to_chunk);
1611 av_freep(&sc->sample_sizes);
1612 av_freep(&sc->keyframes);
1613 av_freep(&sc->stts_data);
1614 av_freep(&sc->ctts_data);
1619 static inline uint32_t mov_to_tag(uint8_t *buf)
1621 return MKTAG(buf[0], buf[1], buf[2], buf[3]);
1624 static inline uint32_t to_be32(uint8_t *buf)
1626 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1629 /* XXX: is it sufficient ? */
1630 static int mov_probe(AVProbeData *p)
1632 unsigned int offset;
1636 /* check file header */
1637 if (p->buf_size <= 12)
1641 /* ignore invalid offset */
1642 if ((offset + 8) > (unsigned int)p->buf_size)
1644 tag = mov_to_tag(p->buf + offset + 4);
1646 /* check for obvious tags */
1647 case MKTAG( 'm', 'o', 'o', 'v' ):
1648 case MKTAG( 'm', 'd', 'a', 't' ):
1649 case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */
1650 case MKTAG( 'u', 'd', 't', 'a' ): /* Packet Video PVAuthor adds this and a lot of more junk */
1651 return AVPROBE_SCORE_MAX;
1652 /* those are more common words, so rate then a bit less */
1653 case MKTAG( 'w', 'i', 'd', 'e' ):
1654 case MKTAG( 'f', 'r', 'e', 'e' ):
1655 case MKTAG( 'j', 'u', 'n', 'k' ):
1656 case MKTAG( 'p', 'i', 'c', 't' ):
1657 return AVPROBE_SCORE_MAX - 5;
1658 case MKTAG( 'f', 't', 'y', 'p' ):
1659 case MKTAG( 's', 'k', 'i', 'p' ):
1660 case MKTAG( 'u', 'u', 'i', 'd' ):
1661 offset = to_be32(p->buf+offset) + offset;
1662 /* if we only find those cause probedata is too small at least rate them */
1663 score = AVPROBE_SCORE_MAX - 50;
1666 /* unrecognized tag */
1673 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap)
1675 MOVContext *mov = (MOVContext *) s->priv_data;
1676 ByteIOContext *pb = &s->pb;
1678 MOV_atom_t atom = { 0, 0, 0 };
1681 mov->parse_table = mov_default_parse_table;
1683 /* XXX: I think we should auto detect */
1684 if(s->iformat->name[1] == 'p')
1687 if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
1688 atom.size = url_fsize(pb);
1690 atom.size = 0x7FFFFFFFFFFFFFFFLL;
1692 /* check MOV header */
1693 err = mov_read_default(mov, pb, atom);
1694 if (err<0 || (!mov->found_moov && !mov->found_mdat)) {
1695 av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%"PRId64"\n",
1696 err, mov->found_moov, mov->found_mdat, url_ftell(pb));
1699 dprintf("on_parse_exit_offset=%d\n", (int) url_ftell(pb));
1701 /* some cleanup : make sure we are on the mdat atom */
1702 if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset))
1703 url_fseek(pb, mov->mdat_offset, SEEK_SET);
1705 mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */
1706 mov->total_streams = nb = s->nb_streams;
1709 for(i=0; i<s->nb_streams;) {
1710 if(s->streams[i]->codec->codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */
1711 av_free(s->streams[i]);
1712 for(j=i+1; j<s->nb_streams; j++)
1713 s->streams[j-1] = s->streams[j];
1718 for(i=0; i<s->nb_streams;i++) {
1719 MOVStreamContext *sc = (MOVStreamContext *)s->streams[i]->priv_data;
1723 av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale);
1725 assert(s->streams[i]->duration % sc->time_rate == 0);
1726 s->streams[i]->duration /= sc->time_rate;
1729 sc->is_ff_stream = 1;
1735 /* Yes, this is ugly... I didn't write the specs of QT :p */
1736 /* XXX:remove useless commented code sometime */
1737 static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
1739 MOVContext *mov = (MOVContext *) s->priv_data;
1740 MOVStreamContext *sc;
1742 int64_t offset = INT64_MAX;
1743 int64_t best_dts = INT64_MAX;
1751 idx = sc->sample_to_chunk_index;
1753 if (idx < 0) return 0;
1754 dprintf("sc[ffid %d]->sample_size = %ld\n", sc->ffindex, sc->sample_size);
1755 //size = sc->sample_sizes[sc->current_sample];
1756 // that ain't working...
1757 //size = (sc->sample_size)?sc->sample_size:sc->sample_sizes[sc->current_sample];
1758 size = (sc->sample_size > 1)?sc->sample_size:sc->sample_sizes[sc->current_sample];
1760 sc->current_sample++;
1761 sc->left_in_chunk--;
1763 if (sc->left_in_chunk <= 0)
1765 offset = mov->next_chunk_offset;
1766 /* extract the sample */
1773 if(offset == INT64_MAX)
1774 best_dts= INT64_MAX;
1775 for(i=0; i<mov->total_streams; i++) {
1776 MOVStreamContext *msc = mov->streams[i];
1778 if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0){
1779 if (msc->sample_to_time_index < msc->stts_count && mov->ni) {
1781 int index= msc->sample_to_time_index;
1782 int sample= msc->sample_to_time_sample;
1783 int time= msc->sample_to_time_time;
1784 int duration = msc->stts_data[index].duration;
1785 int count = msc->stts_data[index].count;
1786 if (sample + count < msc->current_sample) {
1788 time += count*duration;
1790 duration = msc->stts_data[index].duration;
1792 dts = time + (msc->current_sample-1 - sample) * (int64_t)duration;
1793 dts = av_rescale(dts, AV_TIME_BASE, msc->time_scale);
1794 dprintf("stream: %d dts: %Ld best_dts: %Ld offset: %Ld \n", i, dts, best_dts, offset);
1798 offset = msc->chunk_offsets[msc->next_chunk];
1801 if ((msc->chunk_offsets[msc->next_chunk] < offset)) {
1803 offset = msc->chunk_offsets[msc->next_chunk];
1808 if (!sc || offset==INT64_MAX)
1813 if(mov->next_chunk_offset < offset) { /* some meta data */
1814 url_fskip(&s->pb, (offset - mov->next_chunk_offset));
1815 mov->next_chunk_offset = offset;
1818 if(!sc->is_ff_stream || (s->streams[sc->ffindex]->discard >= AVDISCARD_ALL)) {
1819 url_fskip(&s->pb, (offset - mov->next_chunk_offset));
1820 mov->next_chunk_offset = offset;
1825 /* now get the chunk size... */
1827 for(i=0; i<mov->total_streams; i++) {
1828 MOVStreamContext *msc = mov->streams[i];
1829 if ((msc->next_chunk < msc->chunk_count)
1830 && msc->chunk_offsets[msc->next_chunk] - offset < size
1831 && msc->chunk_offsets[msc->next_chunk] > offset)
1832 size = msc->chunk_offsets[msc->next_chunk] - offset;
1835 #ifdef MOV_MINOLTA_FIX
1836 //Make sure that size is according to sample_size (Needed by .mov files
1837 //created on a Minolta Dimage Xi where audio chunks contains waste data in the end)
1838 //Maybe we should really not only check sc->sample_size, but also sc->sample_sizes
1839 //but I have no such movies
1840 if (sc->sample_size > 0) {
1842 for(i=0; i<(sc->sample_to_chunk_sz); i++) {
1843 if( (sc->sample_to_chunk[i].first)<=(sc->next_chunk) )
1845 // I can't figure out why for PCM audio sample_size is always 1
1846 // (it should actually be channels*bits_per_second/8) but it is.
1847 AVCodecContext* cod = s->streams[sc->ffindex]->codec;
1848 if (sc->sample_size == 1 && (cod->codec_id == CODEC_ID_PCM_S16BE || cod->codec_id == CODEC_ID_PCM_S16LE))
1849 foundsize=(sc->sample_to_chunk[i].count*cod->channels*cod->bits_per_sample)/8;
1851 foundsize=sc->sample_to_chunk[i].count*sc->sample_size;
1853 dprintf("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);
1855 if( (foundsize>0) && (foundsize<size) )
1860 #endif //MOV_MINOLTA_FIX
1862 idx = sc->sample_to_chunk_index;
1863 if (idx + 1 < sc->sample_to_chunk_sz && sc->next_chunk >= sc->sample_to_chunk[idx + 1].first)
1865 sc->sample_to_chunk_index = idx;
1866 /* split chunks into samples */
1867 if (sc->sample_size == 0 || sc->sample_size > 100) {
1868 if (idx >= 0 && sc->sample_to_chunk[idx].count != 1) {
1870 /* we'll have to get those samples before next chunk */
1871 sc->left_in_chunk = sc->sample_to_chunk[idx].count - 1;
1872 size = (sc->sample_size > 1)?sc->sample_size:sc->sample_sizes[sc->current_sample];
1875 sc->current_sample++;
1876 }else if(idx + 1 < sc->sample_to_chunk_sz){
1877 sc->current_sample += sc->sample_size * sc->sample_to_chunk[idx].count;
1881 dprintf("chunk: %lli -> %lli (%i)\n", offset, offset + size, size);
1882 if(size == 0x0FFFFFFF)
1883 size = mov->mdat_size + mov->mdat_offset - offset;
1888 url_fseek(&s->pb, offset, SEEK_SET);
1890 av_get_packet(&s->pb, pkt, size);
1891 pkt->stream_index = sc->ffindex;
1893 // If the keyframes table exists, mark any samples that are in the table as key frames.
1894 // If no table exists, treat very sample as a key frame.
1895 if (sc->keyframes) {
1897 b = sc->keyframe_count - 1;
1900 m = (a + b + 1) >> 1;
1901 if (sc->keyframes[m] > sc->current_sample) {
1908 if (sc->keyframes[a] == sc->current_sample)
1909 pkt->flags |= PKT_FLAG_KEY;
1912 pkt->flags |= PKT_FLAG_KEY;
1914 mov->next_chunk_offset = offset + size;
1916 /* find the corresponding dts */
1917 if (sc && sc->sample_to_time_index < sc->stts_count && pkt) {
1920 unsigned int duration = sc->stts_data[sc->sample_to_time_index].duration;
1921 count = sc->stts_data[sc->sample_to_time_index].count;
1922 if ((sc->sample_to_time_sample + count) < sc->current_sample) {
1923 sc->sample_to_time_sample += count;
1924 sc->sample_to_time_time += count*duration;
1925 sc->sample_to_time_index ++;
1926 duration = sc->stts_data[sc->sample_to_time_index].duration;
1928 dts = sc->sample_to_time_time + (sc->current_sample-1 - sc->sample_to_time_sample) * (int64_t)duration;
1929 /* find the corresponding pts */
1930 if (sc->sample_to_ctime_index < sc->ctts_count) {
1931 int duration = sc->ctts_data[sc->sample_to_ctime_index].duration;
1932 int count = sc->ctts_data[sc->sample_to_ctime_index].count;
1934 if ((sc->sample_to_ctime_sample + count) < sc->current_sample) {
1935 sc->sample_to_ctime_sample += count;
1936 sc->sample_to_ctime_index ++;
1937 duration = sc->ctts_data[sc->sample_to_ctime_index].duration;
1939 pts = dts + duration;
1943 st= s->streams[ sc->ffindex ];
1944 assert(pts % st->time_base.num == 0);
1945 assert(dts % st->time_base.num == 0);
1947 pkt->pts = pts / st->time_base.num;
1948 pkt->dts = dts / st->time_base.num;
1949 dprintf("stream #%d smp #%ld dts = %lld pts = %lld (smp:%ld time:%lld idx:%d ent:%d count:%d dur:%d)\n"
1950 , pkt->stream_index, sc->current_sample-1, pkt->dts, pkt->pts
1951 , sc->sample_to_time_sample
1952 , sc->sample_to_time_time
1953 , sc->sample_to_time_index
1962 #if defined(MOV_SEEK)
1964 * Seek method based on the one described in the Appendix C of QTFileFormat.pdf
1966 static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
1968 MOVContext* mov = (MOVContext *) s->priv_data;
1969 MOVStreamContext* sc;
1972 int32_t seek_sample, sample;
1976 int32_t left_in_chunk;
1977 int64_t chunk_file_offset;
1978 int64_t sample_file_offset;
1979 int32_t first_chunk_sample;
1980 int32_t sample_to_chunk_idx;
1981 int sample_to_time_index;
1982 long sample_to_time_sample = 0;
1983 uint64_t sample_to_time_time = 0;
1986 // Find the corresponding mov stream
1987 for (mov_idx = 0; mov_idx < mov->total_streams; mov_idx++)
1988 if (mov->streams[mov_idx]->ffindex == stream_index)
1990 if (mov_idx == mov->total_streams) {
1991 av_log(s, AV_LOG_ERROR, "mov: requested stream was not found in mov streams (idx=%i)\n", stream_index);
1994 sc = mov->streams[mov_idx];
1996 sample_time *= s->streams[stream_index]->time_base.num;
1998 // Step 1. Find the edit that contains the requested time (elst)
1999 if (sc->edit_count && 0) {
2000 // FIXME should handle edit list
2001 av_log(s, AV_LOG_ERROR, "mov: does not handle seeking in files that contain edit list (c:%d)\n", sc->edit_count);
2005 // Step 2. Find the corresponding sample using the Time-to-sample atom (stts) */
2006 dprintf("Searching for time %li in stream #%i (time_scale=%i)\n", (long)sample_time, mov_idx, sc->time_scale);
2007 start_time = 0; // FIXME use elst atom
2008 sample = 1; // sample are 0 based in table
2010 for (i = 0; i < sc->stts_count; i++) {
2011 count = sc->stts_data[i].count;
2012 duration = sc->stts_data[i].duration;
2013 if ((start_time + count*duration) > sample_time) {
2014 sample_to_time_time = start_time;
2015 sample_to_time_index = i;
2016 sample_to_time_sample = sample;
2017 sample += (sample_time - start_time) / duration;
2021 start_time += count * duration;
2023 sample_to_time_time = start_time;
2024 sample_to_time_index = i;
2025 /* NOTE: despite what qt doc say, the dt value (Display Time in qt vocabulary) computed with the stts atom
2026 is a decoding time stamp (dts) not a presentation time stamp. And as usual dts != pts for stream with b frames */
2028 dprintf("Found time %li at sample #%u\n", (long)sample_time, sample);
2029 if (sample > sc->sample_count) {
2030 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);
2034 // Step 3. Find the prior sync. sample using the Sync sample atom (stss)
2035 if (sc->keyframes) {
2037 b = sc->keyframe_count - 1;
2039 m = (a + b + 1) >> 1;
2040 if (sc->keyframes[m] > sample) {
2046 // for low latency prob: always use the previous keyframe, just uncomment the next line
2048 seek_sample = sc->keyframes[a];
2051 seek_sample = sample; // else all samples are key frames
2052 dprintf("Found nearest keyframe at sample #%i \n", seek_sample);
2054 // Step 4. Find the chunk of the sample using the Sample-to-chunk-atom (stsc)
2055 for (first_chunk_sample = 1, i = 0; i < (sc->sample_to_chunk_sz - 1); i++) {
2056 b = (sc->sample_to_chunk[i + 1].first - sc->sample_to_chunk[i].first) * sc->sample_to_chunk[i].count;
2057 if (seek_sample >= first_chunk_sample && seek_sample < (first_chunk_sample + b))
2059 first_chunk_sample += b;
2061 chunk = sc->sample_to_chunk[i].first + (seek_sample - first_chunk_sample) / sc->sample_to_chunk[i].count;
2062 left_in_chunk = sc->sample_to_chunk[i].count - (seek_sample - first_chunk_sample) % sc->sample_to_chunk[i].count;
2063 first_chunk_sample += ((seek_sample - first_chunk_sample) / sc->sample_to_chunk[i].count) * sc->sample_to_chunk[i].count;
2064 sample_to_chunk_idx = i;
2065 dprintf("Sample was found in chunk #%i at sample offset %i (idx %i)\n", chunk, seek_sample - first_chunk_sample, sample_to_chunk_idx);
2067 // Step 5. Find the offset of the chunk using the chunk offset atom
2068 if (!sc->chunk_offsets) {
2069 av_log(s, AV_LOG_ERROR, "mov: no chunk offset atom, unable to seek\n");
2072 if (chunk > sc->chunk_count) {
2073 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);
2076 chunk_file_offset = sc->chunk_offsets[chunk - 1];
2077 dprintf("Chunk file offset is #%llu \n", chunk_file_offset);
2079 // Step 6. Find the byte offset within the chunk using the sample size atom
2080 sample_file_offset = chunk_file_offset;
2081 if (sc->sample_size)
2082 sample_file_offset += (seek_sample - first_chunk_sample) * sc->sample_size;
2084 for (i = 0; i < (seek_sample - first_chunk_sample); i++) {
2085 sample_file_offset += sc->sample_sizes[first_chunk_sample + i - 1];
2088 dprintf("Sample file offset is #%llu \n", sample_file_offset);
2090 // Step 6. Update the parser
2092 mov->next_chunk_offset = sample_file_offset;
2093 // Update current stream state
2094 sc->current_sample = seek_sample - 1; // zero based
2095 sc->left_in_chunk = left_in_chunk;
2096 sc->next_chunk = chunk; // +1 -1 (zero based)
2097 sc->sample_to_chunk_index = sample_to_chunk_idx;
2099 // Update other streams
2100 for (i = 0; i<mov->total_streams; i++) {
2101 MOVStreamContext *msc;
2102 if (i == mov_idx) continue;
2103 // Find the nearest 'next' chunk
2104 msc = mov->streams[i];
2106 b = msc->chunk_count - 1;
2108 m = (a + b + 1) >> 1;
2109 if (msc->chunk_offsets[m] > chunk_file_offset) {
2115 msc->next_chunk = a;
2116 if (msc->chunk_offsets[a] < chunk_file_offset && a < (msc->chunk_count-1))
2118 dprintf("Nearest next chunk for stream #%i is #%li @%lli\n", i, msc->next_chunk+1, msc->chunk_offsets[msc->next_chunk]);
2120 // Compute sample count and index in the sample_to_chunk table (what a pity)
2121 msc->sample_to_chunk_index = 0;
2122 msc->current_sample = 0;
2123 for(; msc->sample_to_chunk_index < (msc->sample_to_chunk_sz - 1)
2124 && msc->sample_to_chunk[msc->sample_to_chunk_index + 1].first <= (1 + msc->next_chunk); msc->sample_to_chunk_index++) {
2125 msc->current_sample += (msc->sample_to_chunk[msc->sample_to_chunk_index + 1].first - msc->sample_to_chunk[msc->sample_to_chunk_index].first) \
2126 * msc->sample_to_chunk[msc->sample_to_chunk_index].count;
2128 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;
2129 msc->left_in_chunk = msc->sample_to_chunk[msc->sample_to_chunk_index].count - 1;
2130 // Find corresponding position in stts (used later to compute dts)
2133 for (msc->sample_to_time_index = 0; msc->sample_to_time_index < msc->stts_count; msc->sample_to_time_index++) {
2134 count = msc->stts_data[msc->sample_to_time_index].count;
2135 duration = msc->stts_data[msc->sample_to_time_index].duration;
2136 if ((sample + count - 1) > msc->current_sample) {
2137 msc->sample_to_time_time = start_time;
2138 msc->sample_to_time_sample = sample;
2142 start_time += count * duration;
2145 for (msc->sample_to_ctime_index = 0; msc->sample_to_ctime_index < msc->ctts_count; msc->sample_to_ctime_index++) {
2146 count = msc->ctts_data[msc->sample_to_ctime_index].count;
2147 duration = msc->ctts_data[msc->sample_to_ctime_index].duration;
2148 if ((sample + count - 1) > msc->current_sample) {
2149 msc->sample_to_ctime_sample = sample;
2154 dprintf("Next Sample for stream #%i is #%li @%li\n", i, msc->current_sample + 1, msc->sample_to_chunk_index + 1);
2160 static int mov_read_close(AVFormatContext *s)
2163 MOVContext *mov = (MOVContext *) s->priv_data;
2164 for(i=0; i<mov->total_streams; i++)
2165 mov_free_stream_context(mov->streams[i]);
2166 /* free color tabs */
2167 for(i=0; i<mov->ctab_size; i++)
2168 av_freep(&mov->ctab[i]);
2169 av_freep(&mov->ctab);
2173 static AVInputFormat mov_iformat = {
2174 "mov,mp4,m4a,3gp,3g2",
2175 "QuickTime/MPEG4 format",
2181 #if defined(MOV_SEEK)
2188 av_register_input_format(&mov_iformat);