This can be useful in particular with timed meta data tracks related to multiple tracks.
Signed-off-by: Erkki Seppälä <erkki.seppala....@nokia.com> Signed-off-by: OZOPlayer <oz...@nokia.com> --- libavformat/isom.h | 3 ++ libavformat/mov.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index df6c15a..609b7b7 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -27,6 +27,8 @@ #include "avio.h" #include "internal.h" #include "dv.h" +#include "movmeta.h" +#include "movtref.h" /* isom.c */ extern const AVCodecTag ff_mp4_obj_type[]; @@ -167,6 +169,7 @@ typedef struct MOVStreamContext { int start_pad; ///< amount of samples to skip due to enc-dec delay unsigned int rap_group_count; MOVSbgp *rap_group; + MOVTRefs trefs; int nb_frames_for_fps; int64_t duration_for_fps; diff --git a/libavformat/mov.c b/libavformat/mov.c index 1bc3800..ff4c91c 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -3157,6 +3157,121 @@ static void fix_timescale(MOVContext *c, MOVStreamContext *sc) } } +static int mov_read_tref_subatom(MOVContext *c, AVIOContext *pb, MOVTRefs *trefs) +{ + uint32_t tref_tag; + MOVTRef *tref; + int tref_ids_size; + int *tref_ids; + int ret; + + tref_ids_size = avio_rb32(pb); + if (tref_ids_size % 4 != 0) + return AVERROR_INVALIDDATA; + tref_ids_size -= 4; + + tref_tag = avio_rl32(pb); + tref_ids_size -= 4; + if (tref_ids_size < 4) + return AVERROR_INVALIDDATA; + + ret = ff_mov_tref_find_or_add(trefs, tref_tag, &tref); + if (ret != 0) + return ret; + + ff_mov_tref_alloc(tref, tref_ids_size / 4, &tref_ids); + if (ret != 0) + return ret; + + while (tref_ids_size) { + *tref_ids = avio_rb32(pb); + ++tref_ids; + tref_ids_size -= 4; + } + + return ret; +} + +static int mov_tref_copy_to_side_data(AVStream *st, MOVTRefs *trefs) +{ + if (trefs->nb_trefs) { + int i; + char *trefs_side_ptr; + int end_offset = 0; + int offset = 0; + AVTrackReferences *trefs_side_prev = NULL; + + for (i = 0; i < trefs->nb_trefs; ++i) { + MOVTRef *tref = &trefs->trefs[i]; + if (tref->nb_track_ids > 0) + // Ensure the returned data is easy to access without + // worrying about alignment, even if it wastes some memory + end_offset = FFALIGN(end_offset + sizeof(AVTrackReferences) + + sizeof(int) * (tref->nb_track_ids - 1), + sizeof(AVTrackReferences)); + } + + trefs_side_ptr = (void*) av_stream_new_side_data(st, + AV_PKT_DATA_TRACK_REFERENCES, + end_offset); + if (!trefs_side_ptr) + return AVERROR(ENOMEM); + + for (i = 0; i < trefs->nb_trefs; ++i) { + MOVTRef *tref = &trefs->trefs[i]; + if (tref->nb_track_ids > 0) { + AVTrackReferences *trefs_side = (AVTrackReferences*) (trefs_side_ptr + offset); + int *trefs_tracks; + + trefs_side->nb_tracks = tref->nb_track_ids; + trefs_side->tag[0] = (tref->tag >> 0) & 0xff; + trefs_side->tag[1] = (tref->tag >> 8) & 0xff; + trefs_side->tag[2] = (tref->tag >> 16) & 0xff; + trefs_side->tag[3] = (tref->tag >> 24) & 0xff; + trefs_tracks = trefs_side->tracks; + for (i = 0; i < tref->nb_track_ids; ++i) { + trefs_tracks[i] = tref->track_ids[i]; + } + + if (trefs_side_prev) + trefs_side_prev->next_tref_ofs = (char*) trefs_side - (char*) trefs_side_prev; + trefs_side_prev = trefs_side; + offset = FFALIGN(end_offset + sizeof(AVTrackReferences) + + sizeof(int) * (tref->nb_track_ids - 1), + sizeof(AVTrackReferences)); + } + } + } + + return 0; +} + +static int mov_read_tref(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + int64_t end = avio_tell(pb) + atom.size; + + if (c->fc->nb_streams < 1) + return 0; + + st = c->fc->streams[c->fc->nb_streams-1]; + sc = st->priv_data; + + if (atom.size < 12) { + return mov_read_default(c, pb, atom); + } else { + int ret = 0; + while (end - avio_tell(pb) > 0 && ret == 0) { + ret = mov_read_tref_subatom(c, pb, &sc->trefs); + } + mov_tref_copy_to_side_data(st, &sc->trefs); + avio_seek(pb, end, SEEK_SET); + } + + return 0; +} + static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -4414,7 +4529,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('t','f','h','d'), mov_read_tfhd }, /* track fragment header */ { MKTAG('t','r','a','k'), mov_read_trak }, { MKTAG('t','r','a','f'), mov_read_default }, -{ MKTAG('t','r','e','f'), mov_read_default }, +{ MKTAG('t','r','e','f'), mov_read_tref }, { MKTAG('t','m','c','d'), mov_read_tmcd }, { MKTAG('c','h','a','p'), mov_read_chap }, { MKTAG('t','r','e','x'), mov_read_trex }, @@ -4832,6 +4947,8 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->cenc.auxiliary_info); av_freep(&sc->cenc.auxiliary_info_sizes); av_aes_ctr_free(sc->cenc.aes_ctr); + + ff_mov_tref_free(&sc->trefs); } if (mov->dv_demux) { -- 2.7.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel