comparison mov.c @ 3169:8ae50c221ae6 libavformat

mp4 fragments support
author bcoudurier
date Fri, 21 Mar 2008 13:40:23 +0000
parents 125b08d2ad59
children 3c56f53f437b
comparison
equal deleted inserted replaced
3168:103f156dd8cc 3169:8ae50c221ae6
79 int64_t offset; 79 int64_t offset;
80 int64_t size; /* total size (excluding the size and type fields) */ 80 int64_t size; /* total size (excluding the size and type fields) */
81 } MOV_atom_t; 81 } MOV_atom_t;
82 82
83 struct MOVParseTableEntry; 83 struct MOVParseTableEntry;
84
85 typedef struct {
86 unsigned track_id;
87 uint64_t base_data_offset;
88 uint64_t moof_offset;
89 unsigned stsd_id;
90 unsigned duration;
91 unsigned size;
92 unsigned flags;
93 } MOVFragment;
94
95 typedef struct {
96 unsigned track_id;
97 unsigned stsd_id;
98 unsigned duration;
99 unsigned size;
100 unsigned flags;
101 } MOVTrackExt;
84 102
85 typedef struct MOVStreamContext { 103 typedef struct MOVStreamContext {
86 ByteIOContext *pb; 104 ByteIOContext *pb;
87 int ffindex; /* the ffmpeg stream id */ 105 int ffindex; /* the ffmpeg stream id */
88 int next_chunk; 106 int next_chunk;
123 int found_mdat; /* we suppose we have enough data to read the file */ 141 int found_mdat; /* we suppose we have enough data to read the file */
124 AVPaletteControl palette_control; 142 AVPaletteControl palette_control;
125 DVDemuxContext *dv_demux; 143 DVDemuxContext *dv_demux;
126 AVFormatContext *dv_fctx; 144 AVFormatContext *dv_fctx;
127 int isom; /* 1 if file is ISO Media (mp4/3gp) */ 145 int isom; /* 1 if file is ISO Media (mp4/3gp) */
146 MOVFragment fragment; ///< current fragment in moof atom
147 MOVTrackExt *trex_data;
148 unsigned trex_count;
128 } MOVContext; 149 } MOVContext;
129 150
130 151
131 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */ 152 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */
132 153
414 /* so we don't parse the whole file if over a network */ 435 /* so we don't parse the whole file if over a network */
415 c->found_moov=1; 436 c->found_moov=1;
416 return 0; /* now go for mdat */ 437 return 0; /* now go for mdat */
417 } 438 }
418 439
440 static int mov_read_moof(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
441 {
442 c->fragment.moof_offset = url_ftell(pb) - 8;
443 dprintf(c->fc, "moof offset %llx\n", c->fragment.moof_offset);
444 return mov_read_default(c, pb, atom);
445 }
419 446
420 static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) 447 static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
421 { 448 {
422 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; 449 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
423 MOVStreamContext *sc = st->priv_data; 450 MOVStreamContext *sc = st->priv_data;
1357 get_be32(pb); /* track height */ 1384 get_be32(pb); /* track height */
1358 1385
1359 return 0; 1386 return 0;
1360 } 1387 }
1361 1388
1389 static int mov_read_tfhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1390 {
1391 MOVFragment *frag = &c->fragment;
1392 MOVTrackExt *trex = NULL;
1393 int flags, track_id, i;
1394
1395 get_byte(pb); /* version */
1396 flags = get_be24(pb);
1397
1398 track_id = get_be32(pb);
1399 if (!track_id || track_id > c->fc->nb_streams)
1400 return -1;
1401 frag->track_id = track_id;
1402 for (i = 0; i < c->trex_count; i++)
1403 if (c->trex_data[i].track_id == frag->track_id) {
1404 trex = &c->trex_data[i];
1405 break;
1406 }
1407 if (!trex) {
1408 av_log(c->fc, AV_LOG_ERROR, "could not find corresponding trex\n");
1409 return -1;
1410 }
1411
1412 if (flags & 0x01) frag->base_data_offset = get_be64(pb);
1413 else frag->base_data_offset = frag->moof_offset;
1414 if (flags & 0x02) frag->stsd_id = get_be32(pb);
1415 else frag->stsd_id = trex->stsd_id;
1416
1417 frag->duration = flags & 0x08 ? get_be32(pb) : trex->duration;
1418 frag->size = flags & 0x10 ? get_be32(pb) : trex->size;
1419 frag->flags = flags & 0x20 ? get_be32(pb) : trex->flags;
1420 dprintf(c->fc, "frag flags 0x%x\n", frag->flags);
1421 return 0;
1422 }
1423
1424 static int mov_read_trex(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1425 {
1426 MOVTrackExt *trex;
1427
1428 if ((uint64_t)c->trex_count+1 >= UINT_MAX / sizeof(*c->trex_data))
1429 return -1;
1430 c->trex_data = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data));
1431 if (!c->trex_data)
1432 return AVERROR(ENOMEM);
1433 trex = &c->trex_data[c->trex_count++];
1434 get_byte(pb); /* version */
1435 get_be24(pb); /* flags */
1436 trex->track_id = get_be32(pb);
1437 trex->stsd_id = get_be32(pb);
1438 trex->duration = get_be32(pb);
1439 trex->size = get_be32(pb);
1440 trex->flags = get_be32(pb);
1441 return 0;
1442 }
1443
1444 static int mov_read_trun(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1445 {
1446 MOVFragment *frag = &c->fragment;
1447 AVStream *st = c->fc->streams[frag->track_id-1];
1448 MOVStreamContext *sc = st->priv_data;
1449 uint64_t offset;
1450 int64_t dts;
1451 int data_offset = 0;
1452 unsigned entries, first_sample_flags = frag->flags;
1453 int flags, distance, i;
1454
1455 if (sc->pseudo_stream_id+1 != frag->stsd_id)
1456 return 0;
1457 if (!st->nb_index_entries)
1458 return -1;
1459 get_byte(pb); /* version */
1460 flags = get_be24(pb);
1461 entries = get_be32(pb);
1462 dprintf(c->fc, "flags 0x%x entries %d\n", flags, entries);
1463 if (flags & 0x001) data_offset = get_be32(pb);
1464 if (flags & 0x004) first_sample_flags = get_be32(pb);
1465 if (flags & 0x800) {
1466 if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data))
1467 return -1;
1468 sc->ctts_data = av_realloc(sc->ctts_data,
1469 (entries+sc->ctts_count)*sizeof(*sc->ctts_data));
1470 if (!sc->ctts_data)
1471 return AVERROR(ENOMEM);
1472 }
1473 dts = st->duration;
1474 offset = frag->base_data_offset + data_offset;
1475 distance = 0;
1476 dprintf(c->fc, "first sample flags 0x%x\n", first_sample_flags);
1477 for (i = 0; i < entries; i++) {
1478 unsigned sample_size = frag->size;
1479 int sample_flags = i ? frag->flags : first_sample_flags;
1480 unsigned sample_duration = frag->duration;
1481 int keyframe;
1482
1483 if (flags & 0x100) sample_duration = get_be32(pb);
1484 if (flags & 0x200) sample_size = get_be32(pb);
1485 if (flags & 0x400) sample_flags = get_be32(pb);
1486 if (flags & 0x800) {
1487 sc->ctts_data[sc->ctts_count].count = 1;
1488 sc->ctts_data[sc->ctts_count].duration = get_be32(pb);
1489 sc->ctts_count++;
1490 }
1491 if ((keyframe = st->codec->codec_type == CODEC_TYPE_AUDIO ||
1492 (flags & 0x004 && !i && !sample_flags) || sample_flags & 0x2000000))
1493 distance = 0;
1494 av_add_index_entry(st, offset, dts, sample_size, distance,
1495 keyframe ? AVINDEX_KEYFRAME : 0);
1496 dprintf(c->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
1497 "size %d, distance %d, keyframe %d\n", st->index, sc->sample_count+i,
1498 offset, dts, sample_size, distance, keyframe);
1499 distance++;
1500 assert(sample_duration % sc->time_rate == 0);
1501 dts += sample_duration / sc->time_rate;
1502 offset += sample_size;
1503 }
1504 frag->moof_offset = offset;
1505 sc->sample_count = st->nb_index_entries;
1506 st->duration = dts;
1507 return 0;
1508 }
1509
1362 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */ 1510 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
1363 /* like the files created with Adobe Premiere 5.0, for samples see */ 1511 /* like the files created with Adobe Premiere 5.0, for samples see */
1364 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */ 1512 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
1365 static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) 1513 static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1366 { 1514 {
1472 { MKTAG( 'j', 'p', '2', 'h' ), mov_read_extradata }, 1620 { MKTAG( 'j', 'p', '2', 'h' ), mov_read_extradata },
1473 { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat }, 1621 { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat },
1474 { MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd }, 1622 { MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd },
1475 { MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default }, 1623 { MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default },
1476 { MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default }, 1624 { MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default },
1625 { MKTAG( 'm', 'o', 'o', 'f' ), mov_read_moof },
1477 { MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov }, 1626 { MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov },
1627 { MKTAG( 'm', 'v', 'e', 'x' ), mov_read_default },
1478 { MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd }, 1628 { MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd },
1479 { MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */ 1629 { MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */
1480 { MKTAG( 'a', 'l', 'a', 'c' ), mov_read_extradata }, /* alac specific atom */ 1630 { MKTAG( 'a', 'l', 'a', 'c' ), mov_read_extradata }, /* alac specific atom */
1481 { MKTAG( 'a', 'v', 'c', 'C' ), mov_read_glbl }, 1631 { MKTAG( 'a', 'v', 'c', 'C' ), mov_read_glbl },
1482 { MKTAG( 's', 't', 'b', 'l' ), mov_read_default }, 1632 { MKTAG( 's', 't', 'b', 'l' ), mov_read_default },
1485 { MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */ 1635 { MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */
1486 { MKTAG( 's', 't', 's', 's' ), mov_read_stss }, /* sync sample */ 1636 { MKTAG( 's', 't', 's', 's' ), mov_read_stss }, /* sync sample */
1487 { MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */ 1637 { MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */
1488 { MKTAG( 's', 't', 't', 's' ), mov_read_stts }, 1638 { MKTAG( 's', 't', 't', 's' ), mov_read_stts },
1489 { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */ 1639 { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */
1640 { MKTAG( 't', 'f', 'h', 'd' ), mov_read_tfhd }, /* track fragment header */
1490 { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak }, 1641 { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak },
1642 { MKTAG( 't', 'r', 'a', 'f' ), mov_read_default },
1643 { MKTAG( 't', 'r', 'e', 'x' ), mov_read_trex },
1644 { MKTAG( 't', 'r', 'u', 'n' ), mov_read_trun },
1491 { MKTAG( 'u', 'd', 't', 'a' ), mov_read_udta }, 1645 { MKTAG( 'u', 'd', 't', 'a' ), mov_read_udta },
1492 { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave }, 1646 { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave },
1493 { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds }, 1647 { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds },
1494 { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */ 1648 { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */
1495 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov }, 1649 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov },
1710 av_freep(&mov->dv_fctx->streams[i]); 1864 av_freep(&mov->dv_fctx->streams[i]);
1711 } 1865 }
1712 av_freep(&mov->dv_fctx); 1866 av_freep(&mov->dv_fctx);
1713 av_freep(&mov->dv_demux); 1867 av_freep(&mov->dv_demux);
1714 } 1868 }
1869 av_freep(&mov->trex_data);
1715 return 0; 1870 return 0;
1716 } 1871 }
1717 1872
1718 AVInputFormat mov_demuxer = { 1873 AVInputFormat mov_demuxer = {
1719 "mov,mp4,m4a,3gp,3g2,mj2", 1874 "mov,mp4,m4a,3gp,3g2,mj2",