# HG changeset patch # User bcoudurier # Date 1204050118 0 # Node ID bae59276377fb02d69e5dbc15e6f81aa431fc1e4 # Parent 1fd2a702fe4900bf8cdcf8ad14e1155c65028f1c support mov reference files, ref.mov/ref.m2v/ref.wav and detect BrianCox.mov diff -r 1fd2a702fe49 -r bae59276377f mov.c --- a/mov.c Tue Feb 26 14:42:07 2008 +0000 +++ b/mov.c Tue Feb 26 18:21:58 2008 +0000 @@ -71,6 +71,11 @@ typedef struct { uint32_t type; + char *path; +} MOV_dref_t; + +typedef struct { + uint32_t type; int64_t offset; int64_t size; /* total size (excluding the size and type fields) */ } MOV_atom_t; @@ -78,6 +83,7 @@ struct MOVParseTableEntry; typedef struct MOVStreamContext { + ByteIOContext *pb; int ffindex; /* the ffmpeg stream id */ int next_chunk; unsigned int chunk_count; @@ -104,6 +110,9 @@ int dv_audio_container; int pseudo_stream_id; int16_t audio_cid; ///< stsd audio compression id + unsigned drefs_count; + MOV_dref_t *drefs; + int dref_id; } MOVStreamContext; typedef struct MOVContext { @@ -200,6 +209,71 @@ return err; } +static int mov_read_dref(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) +{ + AVStream *st = c->fc->streams[c->fc->nb_streams-1]; + MOVStreamContext *sc = st->priv_data; + int entries, i, j; + + get_be32(pb); // version + flags + entries = get_be32(pb); + if (entries >= UINT_MAX / sizeof(*sc->drefs)) + return -1; + sc->drefs_count = entries; + sc->drefs = av_mallocz(entries * sizeof(*sc->drefs)); + + for (i = 0; i < sc->drefs_count; i++) { + MOV_dref_t *dref = &sc->drefs[i]; + uint32_t size = get_be32(pb); + offset_t next = url_ftell(pb) + size - 4; + + dref->type = get_le32(pb); + get_be32(pb); // version + flags + dprintf(c->fc, "type %.4s size %d\n", (char*)&dref->type, size); + + if (dref->type == MKTAG('a','l','i','s') && size > 150) { + /* macintosh alias record */ + uint16_t volume_len, len; + char volume[28]; + int16_t type; + + url_fskip(pb, 10); + + volume_len = get_byte(pb); + volume_len = FFMIN(volume_len, 27); + get_buffer(pb, volume, 27); + volume[volume_len] = 0; + av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", volume, volume_len); + + url_fskip(pb, 112); + + for (type = 0; type != -1 && url_ftell(pb) < next; ) { + type = get_be16(pb); + len = get_be16(pb); + av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len); + if (len&1) + len += 1; + if (type == 2) { // absolute path + dref->path = av_mallocz(len+1); + get_buffer(pb, dref->path, len); + if (!strncmp(dref->path, volume, volume_len)) { + len -= volume_len; + memmove(dref->path, dref->path+volume_len, len); + dref->path[len] = 0; + } + for (j = 0; j < len; j++) + if (dref->path[j] == ':') + dref->path[j] = '/'; + av_log(c->fc, AV_LOG_DEBUG, "path %s\n", dref->path); + } else + url_fskip(pb, len); + } + } + url_fseek(pb, next, SEEK_SET); + } + return 0; +} + static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; @@ -574,6 +648,7 @@ for(pseudo_stream_id=0; pseudo_stream_idcodec->codec_tag && (c->fc->video_codec_id ? codec_get_id(codec_movvideo_tags, format) != c->fc->video_codec_id @@ -594,6 +669,7 @@ continue; } sc->pseudo_stream_id= pseudo_stream_id; + sc->dref_id= dref_id; st->codec->codec_tag = format; id = codec_get_id(codec_movaudio_tags, format); @@ -1217,6 +1293,8 @@ /* mp4 atoms */ { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, { MKTAG( 'c', 't', 't', 's' ), mov_read_ctts }, /* composition time to sample */ +{ MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, +{ MKTAG( 'd', 'r', 'e', 'f' ), mov_read_dref }, { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, { MKTAG( 'e', 'n', 'd', 'a' ), mov_read_enda }, @@ -1451,6 +1529,13 @@ sc->ffindex = i; mov_build_index(mov, st); + if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { + if (url_fopen(&sc->pb, sc->drefs[sc->dref_id-1].path, URL_RDONLY) < 0) + av_log(s, AV_LOG_ERROR, "stream %d, error opening external essence: %s\n", + st->index, strerror(errno)); + } else + sc->pb = s->pb; + switch (st->codec->codec_id) { #ifdef CONFIG_H261_DECODER case CODEC_ID_H261: @@ -1499,15 +1584,16 @@ for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; MOVStreamContext *msc = st->priv_data; - if (st->discard != AVDISCARD_ALL && msc->current_sample < msc->sample_count) { + if (st->discard != AVDISCARD_ALL && msc->pb && msc->current_sample < msc->sample_count) { AVIndexEntry *current_sample = &st->index_entries[msc->current_sample]; int64_t dts = av_rescale(current_sample->timestamp * (int64_t)msc->time_rate, AV_TIME_BASE, msc->time_scale); dprintf(s, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts); if (!sample || (url_is_streamed(s->pb) && current_sample->pos < sample->pos) || (!url_is_streamed(s->pb) && + ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb && ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) || - (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))) { + (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) { sample = current_sample; best_dts = dts; sc = msc; @@ -1518,12 +1604,12 @@ return -1; /* must be done just before reading, to avoid infinite loop on sample */ sc->current_sample++; - if (url_fseek(s->pb, sample->pos, SEEK_SET) != sample->pos) { + if (url_fseek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n", sc->ffindex, sample->pos); return -1; } - av_get_packet(s->pb, pkt, sample->size); + av_get_packet(sc->pb, pkt, sample->size); #ifdef CONFIG_DV_DEMUXER if (mov->dv_demux && sc->dv_audio_container) { dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); @@ -1614,11 +1700,16 @@ static int mov_read_close(AVFormatContext *s) { - int i; + int i, j; MOVContext *mov = s->priv_data; for(i=0; inb_streams; i++) { MOVStreamContext *sc = s->streams[i]->priv_data; av_freep(&sc->ctts_data); + for (j=0; jdrefs_count; j++) + av_freep(&sc->drefs[j].path); + av_freep(&sc->drefs); + if (sc->pb && sc->pb != s->pb) + url_fclose(sc->pb); } if(mov->dv_demux){ for(i=0; idv_fctx->nb_streams; i++){