[FFmpeg-devel] [PATCH v3 04/25] avformat/mov, isom: read (multiple) track references (tag and multiple ids)
Erkki Seppälä
erkki.seppala.ext at nokia.com
Mon Sep 19 16:25:27 EEST 2016
This can be useful in particular with timed meta data tracks related
to multiple tracks.
Signed-off-by: Erkki Seppälä <erkki.seppala.ext at nokia.com>
Signed-off-by: OZOPlayer <OZOPL at 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
More information about the ffmpeg-devel
mailing list