Mercurial > libavformat.hg
annotate mov.c @ 2660:022174d849d5 libavformat
fix issue 225, instead of stoping when wrong atom size is found,
limit atom size to what is left, assuming container atom has correct size..
cricket4.3g2 has incorrect moov atom size which indicates that file size should be
2 bytes bigger than it is and quicktime reads it correctly though.
author | bcoudurier |
---|---|
date | Mon, 22 Oct 2007 14:36:14 +0000 |
parents | 960795567b33 |
children | 9645f395842d |
rev | line source |
---|---|
1845 | 1 /* |
2 * MOV demuxer | |
3 * Copyright (c) 2001 Fabrice Bellard. | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 #include <limits.h> | |
23 | |
24 //#define DEBUG | |
25 | |
26 #include "avformat.h" | |
27 #include "riff.h" | |
28 #include "isom.h" | |
29 #include "dv.h" | |
30 | |
31 #ifdef CONFIG_ZLIB | |
32 #include <zlib.h> | |
33 #endif | |
34 | |
35 /* | |
36 * First version by Francois Revol revol@free.fr | |
37 * Seek function by Gael Chardon gael.dev@4now.net | |
38 * | |
39 * Features and limitations: | |
40 * - reads most of the QT files I have (at least the structure), | |
41 * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html | |
42 * - the code is quite ugly... maybe I won't do it recursive next time :-) | |
43 * | |
44 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ | |
45 * when coding this :) (it's a writer anyway) | |
46 * | |
47 * Reference documents: | |
48 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt | |
49 * Apple: | |
50 * http://developer.apple.com/documentation/QuickTime/QTFF/ | |
51 * http://developer.apple.com/documentation/QuickTime/QTFF/qtff.pdf | |
52 * QuickTime is a trademark of Apple (AFAIK :)) | |
53 */ | |
54 | |
55 #include "qtpalette.h" | |
56 | |
57 | |
58 #undef NDEBUG | |
59 #include <assert.h> | |
60 | |
61 /* the QuickTime file format is quite convoluted... | |
62 * it has lots of index tables, each indexing something in another one... | |
63 * Here we just use what is needed to read the chunks | |
64 */ | |
65 | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
66 typedef struct { |
2030 | 67 int first; |
68 int count; | |
69 int id; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
70 } MOV_stsc_t; |
1845 | 71 |
72 typedef struct { | |
73 uint32_t type; | |
74 int64_t offset; | |
75 int64_t size; /* total size (excluding the size and type fields) */ | |
76 } MOV_atom_t; | |
77 | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
78 typedef struct { |
1845 | 79 offset_t offset; |
80 int64_t size; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
81 } MOV_mdat_t; |
1845 | 82 |
83 struct MOVParseTableEntry; | |
84 | |
85 typedef struct MOVStreamContext { | |
86 int ffindex; /* the ffmpeg stream id */ | |
2030 | 87 int next_chunk; |
1845 | 88 unsigned int chunk_count; |
89 int64_t *chunk_offsets; | |
90 unsigned int stts_count; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
91 MOV_stts_t *stts_data; |
1845 | 92 unsigned int ctts_count; |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
93 MOV_stts_t *ctts_data; |
1845 | 94 unsigned int edit_count; /* number of 'edit' (elst atom) */ |
95 unsigned int sample_to_chunk_sz; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
96 MOV_stsc_t *sample_to_chunk; |
1845 | 97 int sample_to_ctime_index; |
98 int sample_to_ctime_sample; | |
99 unsigned int sample_size; | |
100 unsigned int sample_count; | |
2030 | 101 int *sample_sizes; |
1845 | 102 unsigned int keyframe_count; |
2030 | 103 int *keyframes; |
1845 | 104 int time_scale; |
105 int time_rate; | |
2030 | 106 int current_sample; |
1940
1a7f66384792
cosmetics, sample_size_v1 -> bytes_per_frame / samples_per_frame
bcoudurier
parents:
1939
diff
changeset
|
107 unsigned int bytes_per_frame; |
1a7f66384792
cosmetics, sample_size_v1 -> bytes_per_frame / samples_per_frame
bcoudurier
parents:
1939
diff
changeset
|
108 unsigned int samples_per_frame; |
1845 | 109 int dv_audio_container; |
110 } MOVStreamContext; | |
111 | |
112 typedef struct MOVContext { | |
113 AVFormatContext *fc; | |
114 int time_scale; | |
115 int64_t duration; /* duration of the longest track */ | |
116 int found_moov; /* when both 'moov' and 'mdat' sections has been found */ | |
117 int found_mdat; /* we suppose we have enough data to read the file */ | |
118 int64_t mdat_offset; | |
119 int total_streams; | |
120 MOVStreamContext *streams[MAX_STREAMS]; | |
121 | |
122 const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */ | |
123 /* NOTE: for recursion save to/ restore from local variable! */ | |
124 | |
125 AVPaletteControl palette_control; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
126 MOV_mdat_t *mdat_list; |
1845 | 127 int mdat_count; |
128 DVDemuxContext *dv_demux; | |
129 AVFormatContext *dv_fctx; | |
130 int isom; /* 1 if file is ISO Media (mp4/3gp) */ | |
131 } MOVContext; | |
132 | |
133 | |
134 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */ | |
135 | |
136 /* those functions parse an atom */ | |
137 /* return code: | |
138 1: found what I wanted, exit | |
139 0: continue to parse next atom | |
140 -1: error occured, exit | |
141 */ | |
142 typedef int (*mov_parse_function)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom); | |
143 | |
144 /* links atom IDs to parse functions */ | |
145 typedef struct MOVParseTableEntry { | |
146 uint32_t type; | |
147 mov_parse_function func; | |
148 } MOVParseTableEntry; | |
149 | |
150 static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
151 { | |
152 int64_t total_size = 0; | |
153 MOV_atom_t a; | |
154 int i; | |
155 int err = 0; | |
156 | |
157 a.offset = atom.offset; | |
158 | |
159 if (atom.size < 0) | |
2026 | 160 atom.size = INT64_MAX; |
1845 | 161 while(((total_size + 8) < atom.size) && !url_feof(pb) && !err) { |
162 a.size = atom.size; | |
163 a.type=0L; | |
164 if(atom.size >= 8) { | |
165 a.size = get_be32(pb); | |
166 a.type = get_le32(pb); | |
167 } | |
168 total_size += 8; | |
169 a.offset += 8; | |
1907 | 170 dprintf(c->fc, "type: %08x %.4s sz: %"PRIx64" %"PRIx64" %"PRIx64"\n", a.type, (char*)&a.type, a.size, atom.size, total_size); |
1845 | 171 if (a.size == 1) { /* 64 bit extended size */ |
172 a.size = get_be64(pb) - 8; | |
173 a.offset += 8; | |
174 total_size += 8; | |
175 } | |
176 if (a.size == 0) { | |
177 a.size = atom.size - total_size; | |
178 if (a.size <= 8) | |
179 break; | |
180 } | |
1964
4571a481081d
move atom size check before parsing function search
bcoudurier
parents:
1963
diff
changeset
|
181 a.size -= 8; |
2660
022174d849d5
fix issue 225, instead of stoping when wrong atom size is found,
bcoudurier
parents:
2589
diff
changeset
|
182 if(a.size < 0) |
1964
4571a481081d
move atom size check before parsing function search
bcoudurier
parents:
1963
diff
changeset
|
183 break; |
2660
022174d849d5
fix issue 225, instead of stoping when wrong atom size is found,
bcoudurier
parents:
2589
diff
changeset
|
184 if (a.size > atom.size - total_size) |
022174d849d5
fix issue 225, instead of stoping when wrong atom size is found,
bcoudurier
parents:
2589
diff
changeset
|
185 a.size = atom.size - total_size; |
1964
4571a481081d
move atom size check before parsing function search
bcoudurier
parents:
1963
diff
changeset
|
186 |
1845 | 187 for (i = 0; c->parse_table[i].type != 0L |
188 && c->parse_table[i].type != a.type; i++) | |
189 /* empty */; | |
190 | |
191 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ | |
192 url_fskip(pb, a.size); | |
193 } else { | |
194 offset_t start_pos = url_ftell(pb); | |
195 int64_t left; | |
196 err = (c->parse_table[i].func)(c, pb, a); | |
197 left = a.size - url_ftell(pb) + start_pos; | |
198 if (left > 0) /* skip garbage at atom end */ | |
199 url_fskip(pb, left); | |
200 } | |
201 | |
202 a.offset += a.size; | |
203 total_size += a.size; | |
204 } | |
205 | |
206 if (!err && total_size < atom.size && atom.size < 0x7ffff) { | |
207 url_fskip(pb, atom.size - total_size); | |
208 } | |
209 | |
210 return err; | |
211 } | |
212 | |
213 static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
214 { | |
215 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
216 uint32_t type; | |
217 uint32_t ctype; | |
218 | |
219 get_byte(pb); /* version */ | |
220 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
221 | |
222 /* component type */ | |
223 ctype = get_le32(pb); | |
224 type = get_le32(pb); /* component subtype */ | |
225 | |
2030 | 226 dprintf(c->fc, "ctype= %c%c%c%c (0x%08x)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (int) ctype); |
1907 | 227 dprintf(c->fc, "stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); |
1845 | 228 if(!ctype) |
229 c->isom = 1; | |
230 if(type == MKTAG('v', 'i', 'd', 'e')) | |
231 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
232 else if(type == MKTAG('s', 'o', 'u', 'n')) | |
233 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
234 else if(type == MKTAG('m', '1', 'a', ' ')) | |
235 st->codec->codec_id = CODEC_ID_MP2; | |
236 else if(type == MKTAG('s', 'u', 'b', 'p')) { | |
237 st->codec->codec_type = CODEC_TYPE_SUBTITLE; | |
238 st->codec->codec_id = CODEC_ID_DVD_SUBTITLE; | |
239 } | |
240 get_be32(pb); /* component manufacture */ | |
241 get_be32(pb); /* component flags */ | |
242 get_be32(pb); /* component flags mask */ | |
243 | |
244 if(atom.size <= 24) | |
245 return 0; /* nothing left to read */ | |
246 | |
247 url_fskip(pb, atom.size - (url_ftell(pb) - atom.offset)); | |
248 return 0; | |
249 } | |
250 | |
2029 | 251 static int mp4_read_descr_len(ByteIOContext *pb) |
1845 | 252 { |
253 int len = 0; | |
254 int count = 4; | |
255 while (count--) { | |
256 int c = get_byte(pb); | |
257 len = (len << 7) | (c & 0x7f); | |
258 if (!(c & 0x80)) | |
259 break; | |
260 } | |
261 return len; | |
262 } | |
263 | |
2029 | 264 static int mp4_read_descr(MOVContext *c, ByteIOContext *pb, int *tag) |
1845 | 265 { |
266 int len; | |
267 *tag = get_byte(pb); | |
2029 | 268 len = mp4_read_descr_len(pb); |
1907 | 269 dprintf(c->fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); |
1845 | 270 return len; |
271 } | |
272 | |
2028 | 273 #define MP4ESDescrTag 0x03 |
274 #define MP4DecConfigDescrTag 0x04 | |
275 #define MP4DecSpecificDescrTag 0x05 | |
276 | |
1845 | 277 static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
278 { | |
279 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
280 int tag, len; | |
281 | |
282 get_be32(pb); /* version + flags */ | |
2029 | 283 len = mp4_read_descr(c, pb, &tag); |
1845 | 284 if (tag == MP4ESDescrTag) { |
285 get_be16(pb); /* ID */ | |
286 get_byte(pb); /* priority */ | |
287 } else | |
288 get_be16(pb); /* ID */ | |
289 | |
2029 | 290 len = mp4_read_descr(c, pb, &tag); |
1845 | 291 if (tag == MP4DecConfigDescrTag) { |
2028 | 292 int object_type_id = get_byte(pb); |
293 get_byte(pb); /* stream type */ | |
294 get_be24(pb); /* buffer size db */ | |
295 get_be32(pb); /* max bitrate */ | |
296 get_be32(pb); /* avg bitrate */ | |
1845 | 297 |
2028 | 298 st->codec->codec_id= codec_get_id(ff_mp4_obj_type, object_type_id); |
299 dprintf(c->fc, "esds object type id %d\n", object_type_id); | |
2029 | 300 len = mp4_read_descr(c, pb, &tag); |
1845 | 301 if (tag == MP4DecSpecificDescrTag) { |
1907 | 302 dprintf(c->fc, "Specific MPEG4 header len=%d\n", len); |
1845 | 303 st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); |
304 if (st->codec->extradata) { | |
305 get_buffer(pb, st->codec->extradata, len); | |
306 st->codec->extradata_size = len; | |
307 /* from mplayer */ | |
308 if ((*st->codec->extradata >> 3) == 29) { | |
309 st->codec->codec_id = CODEC_ID_MP3ON4; | |
310 } | |
311 } | |
312 } | |
313 } | |
314 return 0; | |
315 } | |
316 | |
317 /* this atom contains actual media data */ | |
318 static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
319 { | |
320 if(atom.size == 0) /* wrong one (MP4) */ | |
321 return 0; | |
322 c->mdat_list = av_realloc(c->mdat_list, (c->mdat_count + 1) * sizeof(*c->mdat_list)); | |
323 c->mdat_list[c->mdat_count].offset = atom.offset; | |
324 c->mdat_list[c->mdat_count].size = atom.size; | |
325 c->mdat_count++; | |
326 c->found_mdat=1; | |
327 c->mdat_offset = atom.offset; | |
328 if(c->found_moov) | |
329 return 1; /* found both, just go */ | |
330 url_fskip(pb, atom.size); | |
331 return 0; /* now go for moov */ | |
332 } | |
333 | |
334 static int mov_read_ftyp(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
335 { | |
336 uint32_t type = get_le32(pb); | |
337 | |
338 if (type != MKTAG('q','t',' ',' ')) | |
339 c->isom = 1; | |
340 av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type); | |
341 get_be32(pb); /* minor version */ | |
342 url_fskip(pb, atom.size - 8); | |
343 return 0; | |
344 } | |
345 | |
346 /* this atom should contain all header atoms */ | |
347 static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
348 { | |
349 int err; | |
350 | |
351 err = mov_read_default(c, pb, atom); | |
352 /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */ | |
353 /* so we don't parse the whole file if over a network */ | |
354 c->found_moov=1; | |
355 if(c->found_mdat) | |
356 return 1; /* found both, just go */ | |
357 return 0; /* now go for mdat */ | |
358 } | |
359 | |
360 | |
361 static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
362 { | |
363 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 364 MOVStreamContext *sc = st->priv_data; |
1845 | 365 int version = get_byte(pb); |
366 int lang; | |
367 | |
368 if (version > 1) | |
369 return 1; /* unsupported */ | |
370 | |
371 get_byte(pb); get_byte(pb); | |
372 get_byte(pb); /* flags */ | |
373 | |
374 if (version == 1) { | |
375 get_be64(pb); | |
376 get_be64(pb); | |
377 } else { | |
378 get_be32(pb); /* creation time */ | |
379 get_be32(pb); /* modification time */ | |
380 } | |
381 | |
382 sc->time_scale = get_be32(pb); | |
383 st->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */ | |
384 | |
385 lang = get_be16(pb); /* language */ | |
386 ff_mov_lang_to_iso639(lang, st->language); | |
387 get_be16(pb); /* quality */ | |
388 | |
389 return 0; | |
390 } | |
391 | |
392 static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
393 { | |
394 int version = get_byte(pb); /* version */ | |
395 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
396 | |
397 if (version == 1) { | |
398 get_be64(pb); | |
399 get_be64(pb); | |
400 } else { | |
401 get_be32(pb); /* creation time */ | |
402 get_be32(pb); /* modification time */ | |
403 } | |
404 c->time_scale = get_be32(pb); /* time scale */ | |
2044 | 405 |
406 dprintf(c->fc, "time scale = %i\n", c->time_scale); | |
407 | |
1845 | 408 c->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */ |
409 get_be32(pb); /* preferred scale */ | |
410 | |
411 get_be16(pb); /* preferred volume */ | |
412 | |
413 url_fskip(pb, 10); /* reserved */ | |
414 | |
415 url_fskip(pb, 36); /* display matrix */ | |
416 | |
417 get_be32(pb); /* preview time */ | |
418 get_be32(pb); /* preview duration */ | |
419 get_be32(pb); /* poster time */ | |
420 get_be32(pb); /* selection time */ | |
421 get_be32(pb); /* selection duration */ | |
422 get_be32(pb); /* current time */ | |
423 get_be32(pb); /* next track ID */ | |
424 | |
425 return 0; | |
426 } | |
427 | |
428 static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
429 { | |
430 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
431 | |
432 if((uint64_t)atom.size > (1<<30)) | |
433 return -1; | |
434 | |
435 // currently SVQ3 decoder expect full STSD header - so let's fake it | |
436 // this should be fixed and just SMI header should be passed | |
437 av_free(st->codec->extradata); | |
438 st->codec->extradata_size = 0x5a + atom.size; | |
439 st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
440 | |
441 if (st->codec->extradata) { | |
442 memcpy(st->codec->extradata, "SVQ3", 4); // fake | |
443 get_buffer(pb, st->codec->extradata + 0x5a, atom.size); | |
1907 | 444 dprintf(c->fc, "Reading SMI %"PRId64" %s\n", atom.size, st->codec->extradata + 0x5a); |
1845 | 445 } else |
446 url_fskip(pb, atom.size); | |
447 | |
448 return 0; | |
449 } | |
450 | |
451 static int mov_read_enda(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
452 { | |
453 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
454 int little_endian = get_be16(pb); | |
455 | |
456 if (little_endian) { | |
457 switch (st->codec->codec_id) { | |
458 case CODEC_ID_PCM_S24BE: | |
459 st->codec->codec_id = CODEC_ID_PCM_S24LE; | |
460 break; | |
461 case CODEC_ID_PCM_S32BE: | |
462 st->codec->codec_id = CODEC_ID_PCM_S32LE; | |
463 break; | |
464 default: | |
465 break; | |
466 } | |
467 } | |
468 return 0; | |
469 } | |
470 | |
471 /* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */ | |
472 static int mov_read_extradata(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
473 { | |
474 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2589
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
475 uint64_t size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE; |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
476 uint8_t *buf; |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
477 if(size > INT_MAX || (uint64_t)atom.size > INT_MAX) |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
478 return -1; |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
479 buf= av_realloc(st->codec->extradata, size); |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
480 if(!buf) |
1845 | 481 return -1; |
2589
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
482 st->codec->extradata= buf; |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
483 buf+= st->codec->extradata_size; |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
484 st->codec->extradata_size= size - FF_INPUT_BUFFER_PADDING_SIZE; |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
485 AV_WB32( buf , atom.size + 8); |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
486 AV_WL32( buf + 4, atom.type); |
960795567b33
append extradata atoms when parsing, fix OLOCOONS_O3.mov
bcoudurier
parents:
2547
diff
changeset
|
487 get_buffer(pb, buf + 8, atom.size); |
1845 | 488 return 0; |
489 } | |
490 | |
491 static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
492 { | |
493 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
494 | |
495 if((uint64_t)atom.size > (1<<30)) | |
496 return -1; | |
497 | |
498 if (st->codec->codec_id == CODEC_ID_QDM2) { | |
499 // pass all frma atom to codec, needed at least for QDM2 | |
500 av_free(st->codec->extradata); | |
501 st->codec->extradata_size = atom.size; | |
502 st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
503 | |
504 if (st->codec->extradata) { | |
505 get_buffer(pb, st->codec->extradata, atom.size); | |
506 } else | |
507 url_fskip(pb, atom.size); | |
508 } else if (atom.size > 8) { /* to read frma, esds atoms */ | |
509 mov_read_default(c, pb, atom); | |
510 } else | |
511 url_fskip(pb, atom.size); | |
512 return 0; | |
513 } | |
514 | |
515 static int mov_read_avcC(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
516 { | |
517 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
518 | |
519 if((uint64_t)atom.size > (1<<30)) | |
520 return -1; | |
521 | |
522 av_free(st->codec->extradata); | |
523 | |
524 st->codec->extradata_size = atom.size; | |
525 st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
526 | |
527 if (st->codec->extradata) { | |
528 get_buffer(pb, st->codec->extradata, atom.size); | |
529 } else | |
530 url_fskip(pb, atom.size); | |
531 | |
532 return 0; | |
533 } | |
534 | |
535 static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
536 { | |
537 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 538 MOVStreamContext *sc = st->priv_data; |
1845 | 539 unsigned int i, entries; |
540 | |
541 get_byte(pb); /* version */ | |
542 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
543 | |
544 entries = get_be32(pb); | |
545 | |
546 if(entries >= UINT_MAX/sizeof(int64_t)) | |
547 return -1; | |
548 | |
549 sc->chunk_count = entries; | |
550 sc->chunk_offsets = av_malloc(entries * sizeof(int64_t)); | |
551 if (!sc->chunk_offsets) | |
552 return -1; | |
553 if (atom.type == MKTAG('s', 't', 'c', 'o')) { | |
554 for(i=0; i<entries; i++) { | |
555 sc->chunk_offsets[i] = get_be32(pb); | |
556 } | |
557 } else if (atom.type == MKTAG('c', 'o', '6', '4')) { | |
558 for(i=0; i<entries; i++) { | |
559 sc->chunk_offsets[i] = get_be64(pb); | |
560 } | |
561 } else | |
562 return -1; | |
563 | |
564 return 0; | |
565 } | |
566 | |
567 static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
568 { | |
569 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 570 MOVStreamContext *sc = st->priv_data; |
1845 | 571 int entries, frames_per_sample; |
572 uint32_t format; | |
573 uint8_t codec_name[32]; | |
574 | |
575 /* for palette traversal */ | |
576 int color_depth; | |
577 int color_start; | |
578 int color_count; | |
579 int color_end; | |
580 int color_index; | |
581 int color_dec; | |
582 int color_greyscale; | |
583 unsigned char *color_table; | |
584 int j; | |
585 unsigned char r, g, b; | |
586 | |
587 get_byte(pb); /* version */ | |
588 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
589 | |
590 entries = get_be32(pb); | |
591 | |
592 while(entries--) { //Parsing Sample description table | |
593 enum CodecID id; | |
594 MOV_atom_t a = { 0, 0, 0 }; | |
595 offset_t start_pos = url_ftell(pb); | |
596 int size = get_be32(pb); /* size */ | |
597 format = get_le32(pb); /* data format */ | |
598 | |
599 get_be32(pb); /* reserved */ | |
600 get_be16(pb); /* reserved */ | |
601 get_be16(pb); /* index */ | |
602 | |
603 if (st->codec->codec_tag) { | |
604 /* multiple fourcc, just skip for now */ | |
605 url_fskip(pb, size - (url_ftell(pb) - start_pos)); | |
606 continue; | |
607 } | |
608 | |
609 st->codec->codec_tag = format; | |
1847
922180a45610
recommit of the change below after reverting earlier cosmetic-functional mix
michael
parents:
1846
diff
changeset
|
610 id = codec_get_id(codec_movaudio_tags, format); |
2298 | 611 if (id<=0 && (format&0xFFFF) == 'm' + ('s'<<8)) |
612 id = codec_get_id(codec_wav_tags, bswap_32(format)&0xFFFF); | |
613 | |
1845 | 614 if (st->codec->codec_type != CODEC_TYPE_VIDEO && id > 0) { |
615 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
616 } else if (st->codec->codec_type != CODEC_TYPE_AUDIO && /* do not overwrite codec type */ | |
617 format && format != MKTAG('m', 'p', '4', 's')) { /* skip old asf mpeg4 tag */ | |
1847
922180a45610
recommit of the change below after reverting earlier cosmetic-functional mix
michael
parents:
1846
diff
changeset
|
618 id = codec_get_id(codec_movvideo_tags, format); |
1845 | 619 if (id <= 0) |
620 id = codec_get_id(codec_bmp_tags, format); | |
621 if (id > 0) | |
622 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
623 } | |
624 | |
1907 | 625 dprintf(c->fc, "size=%d 4CC= %c%c%c%c codec_type=%d\n", |
1845 | 626 size, |
627 (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, (format >> 24) & 0xff, | |
628 st->codec->codec_type); | |
629 | |
630 if(st->codec->codec_type==CODEC_TYPE_VIDEO) { | |
631 st->codec->codec_id = id; | |
632 get_be16(pb); /* version */ | |
633 get_be16(pb); /* revision level */ | |
634 get_be32(pb); /* vendor */ | |
635 get_be32(pb); /* temporal quality */ | |
636 get_be32(pb); /* spacial quality */ | |
637 | |
638 st->codec->width = get_be16(pb); /* width */ | |
639 st->codec->height = get_be16(pb); /* height */ | |
640 | |
641 get_be32(pb); /* horiz resolution */ | |
642 get_be32(pb); /* vert resolution */ | |
643 get_be32(pb); /* data size, always 0 */ | |
644 frames_per_sample = get_be16(pb); /* frames per samples */ | |
2044 | 645 |
646 dprintf(c->fc, "frames/samples = %d\n", frames_per_sample); | |
647 | |
1845 | 648 get_buffer(pb, codec_name, 32); /* codec name, pascal string (FIXME: true for mp4?) */ |
649 if (codec_name[0] <= 31) { | |
650 memcpy(st->codec->codec_name, &codec_name[1],codec_name[0]); | |
651 st->codec->codec_name[codec_name[0]] = 0; | |
652 } | |
653 | |
654 st->codec->bits_per_sample = get_be16(pb); /* depth */ | |
655 st->codec->color_table_id = get_be16(pb); /* colortable id */ | |
656 | |
657 /* figure out the palette situation */ | |
658 color_depth = st->codec->bits_per_sample & 0x1F; | |
659 color_greyscale = st->codec->bits_per_sample & 0x20; | |
660 | |
661 /* if the depth is 2, 4, or 8 bpp, file is palettized */ | |
662 if ((color_depth == 2) || (color_depth == 4) || | |
663 (color_depth == 8)) { | |
664 | |
665 if (color_greyscale) { | |
666 | |
667 /* compute the greyscale palette */ | |
668 color_count = 1 << color_depth; | |
669 color_index = 255; | |
670 color_dec = 256 / (color_count - 1); | |
671 for (j = 0; j < color_count; j++) { | |
672 r = g = b = color_index; | |
673 c->palette_control.palette[j] = | |
674 (r << 16) | (g << 8) | (b); | |
675 color_index -= color_dec; | |
676 if (color_index < 0) | |
677 color_index = 0; | |
678 } | |
679 | |
680 } else if (st->codec->color_table_id & 0x08) { | |
681 | |
682 /* if flag bit 3 is set, use the default palette */ | |
683 color_count = 1 << color_depth; | |
684 if (color_depth == 2) | |
685 color_table = ff_qt_default_palette_4; | |
686 else if (color_depth == 4) | |
687 color_table = ff_qt_default_palette_16; | |
688 else | |
689 color_table = ff_qt_default_palette_256; | |
690 | |
691 for (j = 0; j < color_count; j++) { | |
692 r = color_table[j * 4 + 0]; | |
693 g = color_table[j * 4 + 1]; | |
694 b = color_table[j * 4 + 2]; | |
695 c->palette_control.palette[j] = | |
696 (r << 16) | (g << 8) | (b); | |
697 } | |
698 | |
699 } else { | |
700 | |
701 /* load the palette from the file */ | |
702 color_start = get_be32(pb); | |
703 color_count = get_be16(pb); | |
704 color_end = get_be16(pb); | |
705 for (j = color_start; j <= color_end; j++) { | |
706 /* each R, G, or B component is 16 bits; | |
707 * only use the top 8 bits; skip alpha bytes | |
708 * up front */ | |
709 get_byte(pb); | |
710 get_byte(pb); | |
711 r = get_byte(pb); | |
712 get_byte(pb); | |
713 g = get_byte(pb); | |
714 get_byte(pb); | |
715 b = get_byte(pb); | |
716 get_byte(pb); | |
717 c->palette_control.palette[j] = | |
718 (r << 16) | (g << 8) | (b); | |
719 } | |
720 } | |
721 | |
722 st->codec->palctrl = &c->palette_control; | |
723 st->codec->palctrl->palette_changed = 1; | |
724 } else | |
725 st->codec->palctrl = NULL; | |
726 } else if(st->codec->codec_type==CODEC_TYPE_AUDIO) { | |
727 int bits_per_sample; | |
728 uint16_t version = get_be16(pb); | |
729 | |
730 st->codec->codec_id = id; | |
731 get_be16(pb); /* revision level */ | |
732 get_be32(pb); /* vendor */ | |
733 | |
734 st->codec->channels = get_be16(pb); /* channel count */ | |
1907 | 735 dprintf(c->fc, "audio channels %d\n", st->codec->channels); |
1845 | 736 st->codec->bits_per_sample = get_be16(pb); /* sample size */ |
737 /* do we need to force to 16 for AMR ? */ | |
738 | |
739 /* handle specific s8 codec */ | |
740 get_be16(pb); /* compression id = 0*/ | |
741 get_be16(pb); /* packet size = 0 */ | |
742 | |
743 st->codec->sample_rate = ((get_be32(pb) >> 16)); | |
744 | |
745 switch (st->codec->codec_id) { | |
746 case CODEC_ID_PCM_S8: | |
747 case CODEC_ID_PCM_U8: | |
748 if (st->codec->bits_per_sample == 16) | |
749 st->codec->codec_id = CODEC_ID_PCM_S16BE; | |
750 break; | |
751 case CODEC_ID_PCM_S16LE: | |
752 case CODEC_ID_PCM_S16BE: | |
753 if (st->codec->bits_per_sample == 8) | |
754 st->codec->codec_id = CODEC_ID_PCM_S8; | |
755 else if (st->codec->bits_per_sample == 24) | |
756 st->codec->codec_id = CODEC_ID_PCM_S24BE; | |
757 break; | |
758 default: | |
759 break; | |
760 } | |
761 | |
2164 | 762 //Read QT version 1 fields. In version 0 these do not exist. |
1907 | 763 dprintf(c->fc, "version =%d, isom =%d\n",version,c->isom); |
1845 | 764 if(!c->isom) { |
765 if(version==1) { | |
1940
1a7f66384792
cosmetics, sample_size_v1 -> bytes_per_frame / samples_per_frame
bcoudurier
parents:
1939
diff
changeset
|
766 sc->samples_per_frame = get_be32(pb); |
1845 | 767 get_be32(pb); /* bytes per packet */ |
1940
1a7f66384792
cosmetics, sample_size_v1 -> bytes_per_frame / samples_per_frame
bcoudurier
parents:
1939
diff
changeset
|
768 sc->bytes_per_frame = get_be32(pb); |
1845 | 769 get_be32(pb); /* bytes per sample */ |
770 } else if(version==2) { | |
771 get_be32(pb); /* sizeof struct only */ | |
772 st->codec->sample_rate = av_int2dbl(get_be64(pb)); /* float 64 */ | |
773 st->codec->channels = get_be32(pb); | |
774 get_be32(pb); /* always 0x7F000000 */ | |
775 get_be32(pb); /* bits per channel if sound is uncompressed */ | |
776 get_be32(pb); /* lcpm format specific flag */ | |
777 get_be32(pb); /* bytes per audio packet if constant */ | |
778 get_be32(pb); /* lpcm frames per audio packet if constant */ | |
779 } | |
780 } | |
781 | |
782 bits_per_sample = av_get_bits_per_sample(st->codec->codec_id); | |
783 if (bits_per_sample) { | |
784 st->codec->bits_per_sample = bits_per_sample; | |
785 sc->sample_size = (bits_per_sample >> 3) * st->codec->channels; | |
786 } | |
787 } else { | |
788 /* other codec type, just skip (rtp, mp4s, tmcd ...) */ | |
789 url_fskip(pb, size - (url_ftell(pb) - start_pos)); | |
790 } | |
791 /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ | |
792 a.size = size - (url_ftell(pb) - start_pos); | |
793 if (a.size > 8) | |
794 mov_read_default(c, pb, a); | |
795 else if (a.size > 0) | |
796 url_fskip(pb, a.size); | |
797 } | |
798 | |
799 if(st->codec->codec_type==CODEC_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) { | |
800 st->codec->sample_rate= sc->time_scale; | |
801 } | |
802 | |
803 /* special codec parameters handling */ | |
804 switch (st->codec->codec_id) { | |
805 #ifdef CONFIG_H261_DECODER | |
806 case CODEC_ID_H261: | |
807 #endif | |
808 #ifdef CONFIG_H263_DECODER | |
809 case CODEC_ID_H263: | |
810 #endif | |
811 #ifdef CONFIG_MPEG4_DECODER | |
812 case CODEC_ID_MPEG4: | |
813 #endif | |
814 st->codec->width= 0; /* let decoder init width/height */ | |
815 st->codec->height= 0; | |
816 break; | |
817 #ifdef CONFIG_LIBFAAD | |
818 case CODEC_ID_AAC: | |
819 #endif | |
820 #ifdef CONFIG_VORBIS_DECODER | |
821 case CODEC_ID_VORBIS: | |
822 #endif | |
823 case CODEC_ID_MP3ON4: | |
824 st->codec->sample_rate= 0; /* let decoder init parameters properly */ | |
825 break; | |
826 #ifdef CONFIG_DV_DEMUXER | |
827 case CODEC_ID_DVAUDIO: | |
828 c->dv_fctx = av_alloc_format_context(); | |
829 c->dv_demux = dv_init_demux(c->dv_fctx); | |
830 if (!c->dv_demux) { | |
831 av_log(c->fc, AV_LOG_ERROR, "dv demux context init error\n"); | |
832 return -1; | |
833 } | |
834 sc->dv_audio_container = 1; | |
835 st->codec->codec_id = CODEC_ID_PCM_S16LE; | |
836 break; | |
837 #endif | |
838 /* no ifdef since parameters are always those */ | |
839 case CODEC_ID_AMR_WB: | |
840 st->codec->sample_rate= 16000; | |
841 st->codec->channels= 1; /* really needed */ | |
842 break; | |
843 case CODEC_ID_AMR_NB: | |
844 st->codec->sample_rate= 8000; | |
845 st->codec->channels= 1; /* really needed */ | |
846 break; | |
847 case CODEC_ID_MP2: | |
1953
edfd6b33d1f6
activate parser on MP3 id, fix [A-Destiny]_Konjiki_no_Gash_Bell_-_65_[71EE362C].mp4
bcoudurier
parents:
1950
diff
changeset
|
848 case CODEC_ID_MP3: |
1845 | 849 st->codec->codec_type = CODEC_TYPE_AUDIO; /* force type after stsd for m1a hdlr */ |
2023 | 850 st->need_parsing = AVSTREAM_PARSE_FULL; |
1845 | 851 break; |
2299
fe59c768ecf7
set block align to stsd audio v2 bytes per frame for adpcm ms and ima wav, fix surge-2-16-L-ms11.mov and surge-2-16-L-ms02.mov
bcoudurier
parents:
2298
diff
changeset
|
852 case CODEC_ID_ADPCM_MS: |
fe59c768ecf7
set block align to stsd audio v2 bytes per frame for adpcm ms and ima wav, fix surge-2-16-L-ms11.mov and surge-2-16-L-ms02.mov
bcoudurier
parents:
2298
diff
changeset
|
853 case CODEC_ID_ADPCM_IMA_WAV: |
fe59c768ecf7
set block align to stsd audio v2 bytes per frame for adpcm ms and ima wav, fix surge-2-16-L-ms11.mov and surge-2-16-L-ms02.mov
bcoudurier
parents:
2298
diff
changeset
|
854 st->codec->block_align = sc->bytes_per_frame; |
fe59c768ecf7
set block align to stsd audio v2 bytes per frame for adpcm ms and ima wav, fix surge-2-16-L-ms11.mov and surge-2-16-L-ms02.mov
bcoudurier
parents:
2298
diff
changeset
|
855 break; |
1845 | 856 default: |
857 break; | |
858 } | |
859 | |
860 return 0; | |
861 } | |
862 | |
863 static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
864 { | |
865 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 866 MOVStreamContext *sc = st->priv_data; |
1845 | 867 unsigned int i, entries; |
868 | |
869 get_byte(pb); /* version */ | |
870 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
871 | |
872 entries = get_be32(pb); | |
873 | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
874 if(entries >= UINT_MAX / sizeof(MOV_stsc_t)) |
1845 | 875 return -1; |
876 | |
2044 | 877 dprintf(c->fc, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); |
878 | |
1845 | 879 sc->sample_to_chunk_sz = entries; |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
880 sc->sample_to_chunk = av_malloc(entries * sizeof(MOV_stsc_t)); |
1845 | 881 if (!sc->sample_to_chunk) |
882 return -1; | |
883 for(i=0; i<entries; i++) { | |
884 sc->sample_to_chunk[i].first = get_be32(pb); | |
885 sc->sample_to_chunk[i].count = get_be32(pb); | |
886 sc->sample_to_chunk[i].id = get_be32(pb); | |
887 } | |
888 return 0; | |
889 } | |
890 | |
891 static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
892 { | |
893 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 894 MOVStreamContext *sc = st->priv_data; |
1845 | 895 unsigned int i, entries; |
896 | |
897 get_byte(pb); /* version */ | |
898 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
899 | |
900 entries = get_be32(pb); | |
901 | |
2030 | 902 if(entries >= UINT_MAX / sizeof(int)) |
1845 | 903 return -1; |
904 | |
905 sc->keyframe_count = entries; | |
2044 | 906 |
907 dprintf(c->fc, "keyframe_count = %d\n", sc->keyframe_count); | |
908 | |
2030 | 909 sc->keyframes = av_malloc(entries * sizeof(int)); |
1845 | 910 if (!sc->keyframes) |
911 return -1; | |
912 for(i=0; i<entries; i++) { | |
913 sc->keyframes[i] = get_be32(pb); | |
2044 | 914 //dprintf(c->fc, "keyframes[]=%d\n", sc->keyframes[i]); |
1845 | 915 } |
916 return 0; | |
917 } | |
918 | |
919 static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
920 { | |
921 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 922 MOVStreamContext *sc = st->priv_data; |
1845 | 923 unsigned int i, entries, sample_size; |
924 | |
925 get_byte(pb); /* version */ | |
926 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
927 | |
928 sample_size = get_be32(pb); | |
929 if (!sc->sample_size) /* do not overwrite value computed in stsd */ | |
930 sc->sample_size = sample_size; | |
931 entries = get_be32(pb); | |
2030 | 932 if(entries >= UINT_MAX / sizeof(int)) |
1845 | 933 return -1; |
934 | |
935 sc->sample_count = entries; | |
936 if (sample_size) | |
937 return 0; | |
938 | |
2044 | 939 dprintf(c->fc, "sample_size = %d sample_count = %d\n", sc->sample_size, sc->sample_count); |
940 | |
2030 | 941 sc->sample_sizes = av_malloc(entries * sizeof(int)); |
1845 | 942 if (!sc->sample_sizes) |
943 return -1; | |
944 for(i=0; i<entries; i++) { | |
945 sc->sample_sizes[i] = get_be32(pb); | |
2044 | 946 dprintf(c->fc, "sample_sizes[]=%d\n", sc->sample_sizes[i]); |
1845 | 947 } |
948 return 0; | |
949 } | |
950 | |
951 static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
952 { | |
953 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 954 MOVStreamContext *sc = st->priv_data; |
1845 | 955 unsigned int i, entries; |
956 int64_t duration=0; | |
957 int64_t total_sample_count=0; | |
958 | |
959 get_byte(pb); /* version */ | |
960 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
961 entries = get_be32(pb); | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
962 if(entries >= UINT_MAX / sizeof(MOV_stts_t)) |
1845 | 963 return -1; |
964 | |
965 sc->stts_count = entries; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
966 sc->stts_data = av_malloc(entries * sizeof(MOV_stts_t)); |
1845 | 967 |
2044 | 968 dprintf(c->fc, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); |
1845 | 969 |
970 sc->time_rate=0; | |
971 | |
972 for(i=0; i<entries; i++) { | |
973 int sample_duration; | |
974 int sample_count; | |
975 | |
976 sample_count=get_be32(pb); | |
977 sample_duration = get_be32(pb); | |
978 sc->stts_data[i].count= sample_count; | |
979 sc->stts_data[i].duration= sample_duration; | |
980 | |
981 sc->time_rate= ff_gcd(sc->time_rate, sample_duration); | |
982 | |
1907 | 983 dprintf(c->fc, "sample_count=%d, sample_duration=%d\n",sample_count,sample_duration); |
1845 | 984 |
985 duration+=(int64_t)sample_duration*sample_count; | |
986 total_sample_count+=sample_count; | |
987 } | |
988 | |
989 st->nb_frames= total_sample_count; | |
990 if(duration) | |
991 st->duration= duration; | |
992 return 0; | |
993 } | |
994 | |
995 static int mov_read_ctts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
996 { | |
997 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
2006 | 998 MOVStreamContext *sc = st->priv_data; |
1845 | 999 unsigned int i, entries; |
1000 | |
1001 get_byte(pb); /* version */ | |
1002 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
1003 entries = get_be32(pb); | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
1004 if(entries >= UINT_MAX / sizeof(MOV_stts_t)) |
1845 | 1005 return -1; |
1006 | |
1007 sc->ctts_count = entries; | |
2045
aa5e56700fdf
cosmectics, use consistant and homogeneous type names for atoms
bcoudurier
parents:
2044
diff
changeset
|
1008 sc->ctts_data = av_malloc(entries * sizeof(MOV_stts_t)); |
1845 | 1009 |
1907 | 1010 dprintf(c->fc, "track[%i].ctts.entries = %i\n", c->fc->nb_streams-1, entries); |
1845 | 1011 |
1012 for(i=0; i<entries; i++) { | |
1013 int count =get_be32(pb); | |
1014 int duration =get_be32(pb); | |
1015 | |
1016 if (duration < 0) { | |
1017 av_log(c->fc, AV_LOG_ERROR, "negative ctts, ignoring\n"); | |
1018 sc->ctts_count = 0; | |
1019 url_fskip(pb, 8 * (entries - i - 1)); | |
1020 break; | |
1021 } | |
1022 sc->ctts_data[i].count = count; | |
1023 sc->ctts_data[i].duration= duration; | |
1024 | |
1025 sc->time_rate= ff_gcd(sc->time_rate, duration); | |
1026 } | |
1027 return 0; | |
1028 } | |
1029 | |
1030 static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1031 { | |
1032 AVStream *st; | |
1033 MOVStreamContext *sc; | |
1034 | |
1035 st = av_new_stream(c->fc, c->fc->nb_streams); | |
1036 if (!st) return -2; | |
1037 sc = av_mallocz(sizeof(MOVStreamContext)); | |
1038 if (!sc) { | |
1039 av_free(st); | |
1040 return -1; | |
1041 } | |
1042 | |
1043 st->priv_data = sc; | |
1044 st->codec->codec_type = CODEC_TYPE_DATA; | |
1045 st->start_time = 0; /* XXX: check */ | |
1046 c->streams[c->fc->nb_streams-1] = sc; | |
1047 | |
1048 return mov_read_default(c, pb, atom); | |
1049 } | |
1050 | |
2296
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1051 static void mov_parse_udta_string(ByteIOContext *pb, char *str, int size) |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1052 { |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1053 uint16_t str_size = get_be16(pb); /* string length */; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1054 |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1055 get_be16(pb); /* skip language */ |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1056 get_buffer(pb, str, FFMIN(size, str_size)); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1057 } |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1058 |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1059 static int mov_read_udta(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1060 { |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1061 uint64_t end = url_ftell(pb) + atom.size; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1062 |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1063 while (url_ftell(pb) + 8 < end) { |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1064 uint32_t tag_size = get_be32(pb); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1065 uint32_t tag = get_le32(pb); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1066 uint64_t next = url_ftell(pb) + tag_size - 8; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1067 |
2547
92bf4673d050
stop parsing udta if size is wrong/garbage, fix issue 154, fix RQ004F14.MOV
bcoudurier
parents:
2299
diff
changeset
|
1068 if (next > end) // stop if tag_size is wrong |
92bf4673d050
stop parsing udta if size is wrong/garbage, fix issue 154, fix RQ004F14.MOV
bcoudurier
parents:
2299
diff
changeset
|
1069 break; |
92bf4673d050
stop parsing udta if size is wrong/garbage, fix issue 154, fix RQ004F14.MOV
bcoudurier
parents:
2299
diff
changeset
|
1070 |
2296
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1071 switch (tag) { |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1072 case MKTAG(0xa9,'n','a','m'): |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1073 mov_parse_udta_string(pb, c->fc->title, sizeof(c->fc->title)); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1074 break; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1075 case MKTAG(0xa9,'w','r','t'): |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1076 mov_parse_udta_string(pb, c->fc->author, sizeof(c->fc->author)); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1077 break; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1078 case MKTAG(0xa9,'c','p','y'): |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1079 mov_parse_udta_string(pb, c->fc->copyright, sizeof(c->fc->copyright)); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1080 break; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1081 case MKTAG(0xa9,'i','n','f'): |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1082 mov_parse_udta_string(pb, c->fc->comment, sizeof(c->fc->comment)); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1083 break; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1084 default: |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1085 break; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1086 } |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1087 |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1088 url_fseek(pb, next, SEEK_SET); |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1089 } |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1090 |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1091 return 0; |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1092 } |
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1093 |
1845 | 1094 static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) |
1095 { | |
1096 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; | |
1097 int version = get_byte(pb); | |
1098 | |
1099 get_byte(pb); get_byte(pb); | |
1100 get_byte(pb); /* flags */ | |
1101 /* | |
1102 MOV_TRACK_ENABLED 0x0001 | |
1103 MOV_TRACK_IN_MOVIE 0x0002 | |
1104 MOV_TRACK_IN_PREVIEW 0x0004 | |
1105 MOV_TRACK_IN_POSTER 0x0008 | |
1106 */ | |
1107 | |
1108 if (version == 1) { | |
1109 get_be64(pb); | |
1110 get_be64(pb); | |
1111 } else { | |
1112 get_be32(pb); /* creation time */ | |
1113 get_be32(pb); /* modification time */ | |
1114 } | |
1115 st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/ | |
1116 get_be32(pb); /* reserved */ | |
1117 st->start_time = 0; /* check */ | |
1118 (version == 1) ? get_be64(pb) : get_be32(pb); /* highlevel (considering edits) duration in movie timebase */ | |
1119 get_be32(pb); /* reserved */ | |
1120 get_be32(pb); /* reserved */ | |
1121 | |
1122 get_be16(pb); /* layer */ | |
1123 get_be16(pb); /* alternate group */ | |
1124 get_be16(pb); /* volume */ | |
1125 get_be16(pb); /* reserved */ | |
1126 | |
1127 url_fskip(pb, 36); /* display matrix */ | |
1128 | |
1129 /* those are fixed-point */ | |
1130 get_be32(pb); /* track width */ | |
1131 get_be32(pb); /* track height */ | |
1132 | |
1133 return 0; | |
1134 } | |
1135 | |
1136 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */ | |
1137 /* like the files created with Adobe Premiere 5.0, for samples see */ | |
1138 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */ | |
1139 static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1140 { | |
1141 int err; | |
1142 | |
1143 if (atom.size < 8) | |
1144 return 0; /* continue */ | |
1145 if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */ | |
1146 url_fskip(pb, atom.size - 4); | |
1147 return 0; | |
1148 } | |
1149 atom.type = get_le32(pb); | |
1150 atom.offset += 8; | |
1151 atom.size -= 8; | |
1152 if (atom.type != MKTAG('m', 'd', 'a', 't')) { | |
1153 url_fskip(pb, atom.size); | |
1154 return 0; | |
1155 } | |
1156 err = mov_read_mdat(c, pb, atom); | |
1157 return err; | |
1158 } | |
1159 | |
1160 static int mov_read_cmov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1161 { | |
1162 #ifdef CONFIG_ZLIB | |
1163 ByteIOContext ctx; | |
1164 uint8_t *cmov_data; | |
1165 uint8_t *moov_data; /* uncompressed data */ | |
1166 long cmov_len, moov_len; | |
1167 int ret; | |
1168 | |
1169 get_be32(pb); /* dcom atom */ | |
1170 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) | |
1171 return -1; | |
1172 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { | |
1173 av_log(NULL, AV_LOG_ERROR, "unknown compression for cmov atom !"); | |
1174 return -1; | |
1175 } | |
1176 get_be32(pb); /* cmvd atom */ | |
1177 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) | |
1178 return -1; | |
1179 moov_len = get_be32(pb); /* uncompressed size */ | |
1180 cmov_len = atom.size - 6 * 4; | |
1181 | |
1182 cmov_data = av_malloc(cmov_len); | |
1183 if (!cmov_data) | |
1184 return -1; | |
1185 moov_data = av_malloc(moov_len); | |
1186 if (!moov_data) { | |
1187 av_free(cmov_data); | |
1188 return -1; | |
1189 } | |
1190 get_buffer(pb, cmov_data, cmov_len); | |
1191 if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) | |
1192 return -1; | |
1193 if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL) != 0) | |
1194 return -1; | |
1195 atom.type = MKTAG( 'm', 'o', 'o', 'v' ); | |
1196 atom.offset = 0; | |
1197 atom.size = moov_len; | |
1198 #ifdef DEBUG | |
1199 // { int fd = open("/tmp/uncompheader.mov", O_WRONLY | O_CREAT); write(fd, moov_data, moov_len); close(fd); } | |
1200 #endif | |
1201 ret = mov_read_default(c, &ctx, atom); | |
1202 av_free(moov_data); | |
1203 av_free(cmov_data); | |
1204 return ret; | |
1205 #else | |
1206 av_log(c->fc, AV_LOG_ERROR, "this file requires zlib support compiled in\n"); | |
1207 return -1; | |
1208 #endif | |
1209 } | |
1210 | |
1211 /* edit list atom */ | |
1212 static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) | |
1213 { | |
1214 int i, edit_count; | |
1215 | |
1216 get_byte(pb); /* version */ | |
1217 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ | |
1218 edit_count= c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */ | |
1219 | |
1220 for(i=0; i<edit_count; i++){ | |
1221 get_be32(pb); /* Track duration */ | |
1222 get_be32(pb); /* Media time */ | |
1223 get_be32(pb); /* Media rate */ | |
1224 } | |
1907 | 1225 dprintf(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count); |
1845 | 1226 return 0; |
1227 } | |
1228 | |
1229 static const MOVParseTableEntry mov_default_parse_table[] = { | |
1230 /* mp4 atoms */ | |
1231 { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, | |
1232 { MKTAG( 'c', 't', 't', 's' ), mov_read_ctts }, /* composition time to sample */ | |
1233 { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, | |
1234 { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, | |
1235 { MKTAG( 'e', 'n', 'd', 'a' ), mov_read_enda }, | |
1236 { MKTAG( 'f', 'i', 'e', 'l' ), mov_read_extradata }, | |
1237 { MKTAG( 'f', 't', 'y', 'p' ), mov_read_ftyp }, | |
1238 { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, | |
1239 { MKTAG( 'j', 'p', '2', 'h' ), mov_read_extradata }, | |
1240 { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat }, | |
1241 { MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd }, | |
1242 { MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default }, | |
1243 { MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default }, | |
1244 { MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov }, | |
1245 { MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd }, | |
1246 { MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */ | |
1247 { MKTAG( 'a', 'l', 'a', 'c' ), mov_read_extradata }, /* alac specific atom */ | |
1248 { MKTAG( 'a', 'v', 'c', 'C' ), mov_read_avcC }, | |
1249 { MKTAG( 's', 't', 'b', 'l' ), mov_read_default }, | |
1250 { MKTAG( 's', 't', 'c', 'o' ), mov_read_stco }, | |
1251 { MKTAG( 's', 't', 's', 'c' ), mov_read_stsc }, | |
1252 { MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */ | |
1253 { MKTAG( 's', 't', 's', 's' ), mov_read_stss }, /* sync sample */ | |
1254 { MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */ | |
1255 { MKTAG( 's', 't', 't', 's' ), mov_read_stts }, | |
1256 { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */ | |
1257 { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak }, | |
2296
0cfc556604e3
fill title, author, copyright and comment fields by parsing udta atom
benoit
parents:
2164
diff
changeset
|
1258 { MKTAG( 'u', 'd', 't', 'a' ), mov_read_udta }, |
1845 | 1259 { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave }, |
1260 { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds }, | |
1261 { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */ | |
1262 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov }, | |
1263 { 0L, NULL } | |
1264 }; | |
1265 | |
1266 /* XXX: is it sufficient ? */ | |
1267 static int mov_probe(AVProbeData *p) | |
1268 { | |
1269 unsigned int offset; | |
1270 uint32_t tag; | |
1271 int score = 0; | |
1272 | |
1273 /* check file header */ | |
1274 offset = 0; | |
1275 for(;;) { | |
1276 /* ignore invalid offset */ | |
1277 if ((offset + 8) > (unsigned int)p->buf_size) | |
1278 return score; | |
1279 tag = AV_RL32(p->buf + offset + 4); | |
1280 switch(tag) { | |
1281 /* check for obvious tags */ | |
1282 case MKTAG( 'j', 'P', ' ', ' ' ): /* jpeg 2000 signature */ | |
1283 case MKTAG( 'm', 'o', 'o', 'v' ): | |
1284 case MKTAG( 'm', 'd', 'a', 't' ): | |
1285 case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */ | |
1286 case MKTAG( 'u', 'd', 't', 'a' ): /* Packet Video PVAuthor adds this and a lot of more junk */ | |
1287 return AVPROBE_SCORE_MAX; | |
1288 /* those are more common words, so rate then a bit less */ | |
2039
5dd45d0a5340
add 'wide' reversed tag in probe, detect broken xdcam files xdcam_hd_1080i60.mov
bcoudurier
parents:
2030
diff
changeset
|
1289 case MKTAG( 'e', 'd', 'i', 'w' ): /* xdcam files have reverted first tags */ |
1845 | 1290 case MKTAG( 'w', 'i', 'd', 'e' ): |
1291 case MKTAG( 'f', 'r', 'e', 'e' ): | |
1292 case MKTAG( 'j', 'u', 'n', 'k' ): | |
1293 case MKTAG( 'p', 'i', 'c', 't' ): | |
1294 return AVPROBE_SCORE_MAX - 5; | |
1295 case MKTAG( 'f', 't', 'y', 'p' ): | |
1296 case MKTAG( 's', 'k', 'i', 'p' ): | |
1297 case MKTAG( 'u', 'u', 'i', 'd' ): | |
1298 offset = AV_RB32(p->buf+offset) + offset; | |
1299 /* if we only find those cause probedata is too small at least rate them */ | |
1300 score = AVPROBE_SCORE_MAX - 50; | |
1301 break; | |
1302 default: | |
1303 /* unrecognized tag */ | |
1304 return score; | |
1305 } | |
1306 } | |
1307 return score; | |
1308 } | |
1309 | |
1310 static void mov_build_index(MOVContext *mov, AVStream *st) | |
1311 { | |
1312 MOVStreamContext *sc = st->priv_data; | |
1313 offset_t current_offset; | |
1314 int64_t current_dts = 0; | |
1315 unsigned int stts_index = 0; | |
1316 unsigned int stsc_index = 0; | |
1317 unsigned int stss_index = 0; | |
1318 unsigned int i, j, k; | |
1319 | |
1320 if (sc->sample_sizes || st->codec->codec_type == CODEC_TYPE_VIDEO || sc->dv_audio_container) { | |
1321 unsigned int current_sample = 0; | |
1322 unsigned int stts_sample = 0; | |
1323 unsigned int keyframe, sample_size; | |
1324 unsigned int distance = 0; | |
1325 | |
1326 st->nb_frames = sc->sample_count; | |
1327 for (i = 0; i < sc->chunk_count; i++) { | |
1328 current_offset = sc->chunk_offsets[i]; | |
1329 if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) | |
1330 stsc_index++; | |
1331 for (j = 0; j < sc->sample_to_chunk[stsc_index].count; j++) { | |
1332 if (current_sample >= sc->sample_count) { | |
1333 av_log(mov->fc, AV_LOG_ERROR, "wrong sample count\n"); | |
1334 goto out; | |
1335 } | |
1336 keyframe = !sc->keyframe_count || current_sample + 1 == sc->keyframes[stss_index]; | |
1337 if (keyframe) { | |
1338 distance = 0; | |
1339 if (stss_index + 1 < sc->keyframe_count) | |
1340 stss_index++; | |
1341 } | |
1342 sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample]; | |
1907 | 1343 dprintf(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", size %d, distance %d, keyframe %d\n", |
1845 | 1344 st->index, current_sample, current_offset, current_dts, sample_size, distance, keyframe); |
1345 av_add_index_entry(st, current_offset, current_dts, sample_size, distance, keyframe ? AVINDEX_KEYFRAME : 0); | |
1346 current_offset += sample_size; | |
1347 assert(sc->stts_data[stts_index].duration % sc->time_rate == 0); | |
1348 current_dts += sc->stts_data[stts_index].duration / sc->time_rate; | |
1349 distance++; | |
1350 stts_sample++; | |
1351 current_sample++; | |
1352 if (stts_index + 1 < sc->stts_count && stts_sample == sc->stts_data[stts_index].count) { | |
1353 stts_sample = 0; | |
1354 stts_index++; | |
1355 } | |
1356 } | |
1357 } | |
1358 } else { /* read whole chunk */ | |
1359 unsigned int chunk_samples, chunk_size, chunk_duration; | |
1360 | |
1361 for (i = 0; i < sc->chunk_count; i++) { | |
1362 current_offset = sc->chunk_offsets[i]; | |
1363 if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) | |
1364 stsc_index++; | |
1365 chunk_samples = sc->sample_to_chunk[stsc_index].count; | |
1366 /* get chunk size */ | |
1367 if (sc->sample_size > 1 || st->codec->codec_id == CODEC_ID_PCM_U8 || st->codec->codec_id == CODEC_ID_PCM_S8) | |
1368 chunk_size = chunk_samples * sc->sample_size; | |
1940
1a7f66384792
cosmetics, sample_size_v1 -> bytes_per_frame / samples_per_frame
bcoudurier
parents:
1939
diff
changeset
|
1369 else if (sc->samples_per_frame > 0 && (chunk_samples * sc->bytes_per_frame % sc->samples_per_frame == 0)) |
1a7f66384792
cosmetics, sample_size_v1 -> bytes_per_frame / samples_per_frame
bcoudurier
parents:
1939
diff
changeset
|
1370 chunk_size = chunk_samples * sc->bytes_per_frame / sc->samples_per_frame; |
1845 | 1371 else { /* workaround to find nearest next chunk offset */ |
1372 chunk_size = INT_MAX; | |
1373 for (j = 0; j < mov->total_streams; j++) { | |
1374 MOVStreamContext *msc = mov->streams[j]; | |
1375 | |
1376 for (k = msc->next_chunk; k < msc->chunk_count; k++) { | |
1377 if (msc->chunk_offsets[k] > current_offset && msc->chunk_offsets[k] - current_offset < chunk_size) { | |
1378 chunk_size = msc->chunk_offsets[k] - current_offset; | |
1379 msc->next_chunk = k; | |
1380 break; | |
1381 } | |
1382 } | |
1383 } | |
1384 /* check for last chunk */ | |
1385 if (chunk_size == INT_MAX) | |
1386 for (j = 0; j < mov->mdat_count; j++) { | |
1907 | 1387 dprintf(mov->fc, "mdat %d, offset %"PRIx64", size %"PRId64", current offset %"PRIx64"\n", |
1845 | 1388 j, mov->mdat_list[j].offset, mov->mdat_list[j].size, current_offset); |
1389 if (mov->mdat_list[j].offset <= current_offset && mov->mdat_list[j].offset + mov->mdat_list[j].size > current_offset) | |
1390 chunk_size = mov->mdat_list[j].offset + mov->mdat_list[j].size - current_offset; | |
1391 } | |
1392 assert(chunk_size != INT_MAX); | |
1393 for (j = 0; j < mov->total_streams; j++) { | |
1394 mov->streams[j]->next_chunk = 0; | |
1395 } | |
1396 } | |
1397 av_add_index_entry(st, current_offset, current_dts, chunk_size, 0, AVINDEX_KEYFRAME); | |
1398 /* get chunk duration */ | |
1399 chunk_duration = 0; | |
1400 while (chunk_samples > 0) { | |
1401 if (chunk_samples < sc->stts_data[stts_index].count) { | |
1402 chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; | |
1403 sc->stts_data[stts_index].count -= chunk_samples; | |
1404 break; | |
1405 } else { | |
1406 chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; | |
1407 chunk_samples -= sc->stts_data[stts_index].count; | |
1408 if (stts_index + 1 < sc->stts_count) { | |
1409 stts_index++; | |
1410 } | |
1411 } | |
1412 } | |
1907 | 1413 dprintf(mov->fc, "AVIndex stream %d, chunk %d, offset %"PRIx64", dts %"PRId64", size %d, duration %d\n", |
1845 | 1414 st->index, i, current_offset, current_dts, chunk_size, chunk_duration); |
1415 assert(chunk_duration % sc->time_rate == 0); | |
1416 current_dts += chunk_duration / sc->time_rate; | |
1417 } | |
1418 } | |
1419 out: | |
1420 /* adjust sample count to avindex entries */ | |
1421 sc->sample_count = st->nb_index_entries; | |
1422 } | |
1423 | |
1424 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
1425 { | |
2006 | 1426 MOVContext *mov = s->priv_data; |
1845 | 1427 ByteIOContext *pb = &s->pb; |
1428 int i, err; | |
1429 MOV_atom_t atom = { 0, 0, 0 }; | |
1430 | |
1431 mov->fc = s; | |
1432 mov->parse_table = mov_default_parse_table; | |
1433 | |
1434 if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ | |
1435 atom.size = url_fsize(pb); | |
1436 else | |
2026 | 1437 atom.size = INT64_MAX; |
1845 | 1438 |
1439 /* check MOV header */ | |
1440 err = mov_read_default(mov, pb, atom); | |
1441 if (err<0 || (!mov->found_moov && !mov->found_mdat)) { | |
1442 av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%"PRId64"\n", | |
1443 err, mov->found_moov, mov->found_mdat, url_ftell(pb)); | |
1444 return -1; | |
1445 } | |
1907 | 1446 dprintf(mov->fc, "on_parse_exit_offset=%d\n", (int) url_ftell(pb)); |
1845 | 1447 |
1448 /* some cleanup : make sure we are on the mdat atom */ | |
1449 if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) | |
1450 url_fseek(pb, mov->mdat_offset, SEEK_SET); | |
1451 | |
1452 mov->total_streams = s->nb_streams; | |
1453 | |
1454 for(i=0; i<mov->total_streams; i++) { | |
1455 MOVStreamContext *sc = mov->streams[i]; | |
1938 | 1456 AVStream *st = s->streams[i]; |
1845 | 1457 /* sanity checks */ |
1458 if(!sc->stts_count || !sc->chunk_count || !sc->sample_to_chunk_sz || | |
1459 (!sc->sample_size && !sc->sample_count)){ | |
1460 av_log(s, AV_LOG_ERROR, "missing mandatory atoms, broken header\n"); | |
1963
81268e2bd9aa
unset sample count to disable track when is broken
bcoudurier
parents:
1962
diff
changeset
|
1461 sc->sample_count = 0; //ignore track |
1950
4ef37f929c21
dont fail immediately when a somehow broken track is detected, some tracks might be good, fix mi2_vorbis51.mp4
bcoudurier
parents:
1948
diff
changeset
|
1462 continue; |
1845 | 1463 } |
1464 if(!sc->time_rate) | |
1465 sc->time_rate=1; | |
1466 if(!sc->time_scale) | |
1467 sc->time_scale= mov->time_scale; | |
1939 | 1468 av_set_pts_info(st, 64, sc->time_rate, sc->time_scale); |
1845 | 1469 |
1938 | 1470 if (st->codec->codec_type == CODEC_TYPE_AUDIO && sc->stts_count == 1) |
1471 st->codec->frame_size = sc->stts_data[0].duration; | |
1472 | |
1939 | 1473 if(st->duration != AV_NOPTS_VALUE){ |
1474 assert(st->duration % sc->time_rate == 0); | |
1475 st->duration /= sc->time_rate; | |
1845 | 1476 } |
1477 sc->ffindex = i; | |
1939 | 1478 mov_build_index(mov, st); |
1845 | 1479 } |
1480 | |
1481 for(i=0; i<mov->total_streams; i++) { | |
2164 | 1482 /* Do not need those anymore. */ |
1845 | 1483 av_freep(&mov->streams[i]->chunk_offsets); |
1484 av_freep(&mov->streams[i]->sample_to_chunk); | |
1485 av_freep(&mov->streams[i]->sample_sizes); | |
1486 av_freep(&mov->streams[i]->keyframes); | |
1487 av_freep(&mov->streams[i]->stts_data); | |
1488 } | |
1489 av_freep(&mov->mdat_list); | |
1490 return 0; | |
1491 } | |
1492 | |
1493 static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) | |
1494 { | |
1495 MOVContext *mov = s->priv_data; | |
1496 MOVStreamContext *sc = 0; | |
1497 AVIndexEntry *sample = 0; | |
1498 int64_t best_dts = INT64_MAX; | |
1499 int i; | |
1500 | |
1501 for (i = 0; i < mov->total_streams; i++) { | |
1502 MOVStreamContext *msc = mov->streams[i]; | |
1503 | |
1504 if (s->streams[i]->discard != AVDISCARD_ALL && msc->current_sample < msc->sample_count) { | |
1505 AVIndexEntry *current_sample = &s->streams[i]->index_entries[msc->current_sample]; | |
1506 int64_t dts = av_rescale(current_sample->timestamp * (int64_t)msc->time_rate, AV_TIME_BASE, msc->time_scale); | |
1507 | |
2030 | 1508 dprintf(s, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts); |
1845 | 1509 if (dts < best_dts) { |
1510 sample = current_sample; | |
1511 best_dts = dts; | |
1512 sc = msc; | |
1513 } | |
1514 } | |
1515 } | |
1516 if (!sample) | |
1517 return -1; | |
1518 /* must be done just before reading, to avoid infinite loop on sample */ | |
1519 sc->current_sample++; | |
1520 if (sample->pos >= url_fsize(&s->pb)) { | |
1521 av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n", sc->ffindex, sample->pos); | |
1522 return -1; | |
1523 } | |
1524 #ifdef CONFIG_DV_DEMUXER | |
1525 if (sc->dv_audio_container) { | |
1526 dv_get_packet(mov->dv_demux, pkt); | |
1907 | 1527 dprintf(s, "dv audio pkt size %d\n", pkt->size); |
1845 | 1528 } else { |
1529 #endif | |
1530 url_fseek(&s->pb, sample->pos, SEEK_SET); | |
1531 av_get_packet(&s->pb, pkt, sample->size); | |
1532 #ifdef CONFIG_DV_DEMUXER | |
1533 if (mov->dv_demux) { | |
1534 void *pkt_destruct_func = pkt->destruct; | |
1535 dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); | |
1536 pkt->destruct = pkt_destruct_func; | |
1537 } | |
1538 } | |
1539 #endif | |
1540 pkt->stream_index = sc->ffindex; | |
1541 pkt->dts = sample->timestamp; | |
1542 if (sc->ctts_data) { | |
1543 assert(sc->ctts_data[sc->sample_to_ctime_index].duration % sc->time_rate == 0); | |
1544 pkt->pts = pkt->dts + sc->ctts_data[sc->sample_to_ctime_index].duration / sc->time_rate; | |
1545 /* update ctts context */ | |
1546 sc->sample_to_ctime_sample++; | |
1547 if (sc->sample_to_ctime_index < sc->ctts_count && sc->ctts_data[sc->sample_to_ctime_index].count == sc->sample_to_ctime_sample) { | |
1548 sc->sample_to_ctime_index++; | |
1549 sc->sample_to_ctime_sample = 0; | |
1550 } | |
1551 } else { | |
1552 pkt->pts = pkt->dts; | |
1553 } | |
1554 pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? PKT_FLAG_KEY : 0; | |
1555 pkt->pos = sample->pos; | |
1907 | 1556 dprintf(s, "stream %d, pts %"PRId64", dts %"PRId64", pos 0x%"PRIx64", duration %d\n", pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration); |
1845 | 1557 return 0; |
1558 } | |
1559 | |
1560 static int mov_seek_stream(AVStream *st, int64_t timestamp, int flags) | |
1561 { | |
1562 MOVStreamContext *sc = st->priv_data; | |
1563 int sample, time_sample; | |
1564 int i; | |
1565 | |
1566 sample = av_index_search_timestamp(st, timestamp, flags); | |
1907 | 1567 dprintf(st->codec, "stream %d, timestamp %"PRId64", sample %d\n", st->index, timestamp, sample); |
1845 | 1568 if (sample < 0) /* not sure what to do */ |
1569 return -1; | |
1570 sc->current_sample = sample; | |
2030 | 1571 dprintf(st->codec, "stream %d, found sample %d\n", st->index, sc->current_sample); |
1845 | 1572 /* adjust ctts index */ |
1573 if (sc->ctts_data) { | |
1574 time_sample = 0; | |
1575 for (i = 0; i < sc->ctts_count; i++) { | |
2083
2c3887f02739
fix ctts index computation when seeking, check must be done against next ctts sample, thanks to Uoti
bcoudurier
parents:
2046
diff
changeset
|
1576 int next = time_sample + sc->ctts_data[i].count; |
2c3887f02739
fix ctts index computation when seeking, check must be done against next ctts sample, thanks to Uoti
bcoudurier
parents:
2046
diff
changeset
|
1577 if (next > sc->current_sample) { |
1845 | 1578 sc->sample_to_ctime_index = i; |
2083
2c3887f02739
fix ctts index computation when seeking, check must be done against next ctts sample, thanks to Uoti
bcoudurier
parents:
2046
diff
changeset
|
1579 sc->sample_to_ctime_sample = sc->current_sample - time_sample; |
1845 | 1580 break; |
1581 } | |
2083
2c3887f02739
fix ctts index computation when seeking, check must be done against next ctts sample, thanks to Uoti
bcoudurier
parents:
2046
diff
changeset
|
1582 time_sample = next; |
1845 | 1583 } |
1584 } | |
1585 return sample; | |
1586 } | |
1587 | |
1588 static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) | |
1589 { | |
1590 AVStream *st; | |
1591 int64_t seek_timestamp, timestamp; | |
1592 int sample; | |
1593 int i; | |
1594 | |
1595 if (stream_index >= s->nb_streams) | |
1596 return -1; | |
1597 | |
1598 st = s->streams[stream_index]; | |
1599 sample = mov_seek_stream(st, sample_time, flags); | |
1600 if (sample < 0) | |
1601 return -1; | |
1602 | |
1603 /* adjust seek timestamp to found sample timestamp */ | |
1604 seek_timestamp = st->index_entries[sample].timestamp; | |
1605 | |
1606 for (i = 0; i < s->nb_streams; i++) { | |
1607 st = s->streams[i]; | |
1608 if (stream_index == i || st->discard == AVDISCARD_ALL) | |
1609 continue; | |
1610 | |
1611 timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base); | |
1612 mov_seek_stream(st, timestamp, flags); | |
1613 } | |
1614 return 0; | |
1615 } | |
1616 | |
1617 static int mov_read_close(AVFormatContext *s) | |
1618 { | |
1619 int i; | |
2006 | 1620 MOVContext *mov = s->priv_data; |
2084 | 1621 for(i=0; i<mov->total_streams; i++) { |
1622 av_freep(&mov->streams[i]->ctts_data); | |
1623 av_freep(&mov->streams[i]); | |
1624 } | |
1845 | 1625 if(mov->dv_demux){ |
1626 for(i=0; i<mov->dv_fctx->nb_streams; i++){ | |
1627 av_freep(&mov->dv_fctx->streams[i]->codec); | |
1628 av_freep(&mov->dv_fctx->streams[i]); | |
1629 } | |
1630 av_freep(&mov->dv_fctx); | |
1631 av_freep(&mov->dv_demux); | |
1632 } | |
1633 return 0; | |
1634 } | |
1635 | |
1636 AVInputFormat mov_demuxer = { | |
1637 "mov,mp4,m4a,3gp,3g2,mj2", | |
1638 "QuickTime/MPEG4/Motion JPEG 2000 format", | |
1639 sizeof(MOVContext), | |
1640 mov_probe, | |
1641 mov_read_header, | |
1642 mov_read_packet, | |
1643 mov_read_close, | |
1644 mov_read_seek, | |
1645 }; |