X-Git-Url: https://git.piment-noir.org/?p=deb_ffmpeg.git;a=blobdiff_plain;f=ffmpeg%2Ftools%2Fismindex.c;h=3e5304635f99e4ef68155b33e1602a92a964c0fe;hp=d66a389e0ec49d7fc726b141a24f0e0087a36cf4;hb=f6fa7814ccfe3e76514b36cf04f5cd3cb657c8cf;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00 diff --git a/ffmpeg/tools/ismindex.c b/ffmpeg/tools/ismindex.c index d66a389..3e53046 100644 --- a/ffmpeg/tools/ismindex.c +++ b/ffmpeg/tools/ismindex.c @@ -50,6 +50,7 @@ #include "cmdutils.h" #include "libavformat/avformat.h" +#include "libavformat/isom.h" #include "libavformat/os_support.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" @@ -226,6 +227,94 @@ fail: return ret; } +static int64_t read_trun_duration(AVIOContext *in, int default_duration, + int64_t end) +{ + int64_t ret = 0; + int64_t pos; + int flags, i; + int entries; + avio_r8(in); /* version */ + flags = avio_rb24(in); + if (default_duration <= 0 && !(flags & MOV_TRUN_SAMPLE_DURATION)) { + fprintf(stderr, "No sample duration in trun flags\n"); + return -1; + } + entries = avio_rb32(in); + + if (flags & MOV_TRUN_DATA_OFFSET) avio_rb32(in); + if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) avio_rb32(in); + + pos = avio_tell(in); + for (i = 0; i < entries && pos < end; i++) { + int sample_duration = default_duration; + if (flags & MOV_TRUN_SAMPLE_DURATION) sample_duration = avio_rb32(in); + if (flags & MOV_TRUN_SAMPLE_SIZE) avio_rb32(in); + if (flags & MOV_TRUN_SAMPLE_FLAGS) avio_rb32(in); + if (flags & MOV_TRUN_SAMPLE_CTS) avio_rb32(in); + if (sample_duration < 0) { + fprintf(stderr, "Negative sample duration %d\n", sample_duration); + return -1; + } + ret += sample_duration; + pos = avio_tell(in); + } + + return ret; +} + +static int64_t read_moof_duration(AVIOContext *in, int64_t offset) +{ + int64_t ret = -1; + int32_t moof_size, size, tag; + int64_t pos = 0; + int default_duration = 0; + + avio_seek(in, offset, SEEK_SET); + moof_size = avio_rb32(in); + tag = avio_rb32(in); + if (expect_tag(tag, MKBETAG('m', 'o', 'o', 'f')) != 0) + goto fail; + while (pos < offset + moof_size) { + pos = avio_tell(in); + size = avio_rb32(in); + tag = avio_rb32(in); + if (tag == MKBETAG('t', 'r', 'a', 'f')) { + int64_t traf_pos = pos; + int64_t traf_size = size; + while (pos < traf_pos + traf_size) { + pos = avio_tell(in); + size = avio_rb32(in); + tag = avio_rb32(in); + if (tag == MKBETAG('t', 'f', 'h', 'd')) { + int flags = 0; + avio_r8(in); /* version */ + flags = avio_rb24(in); + avio_rb32(in); /* track_id */ + if (flags & MOV_TFHD_BASE_DATA_OFFSET) + avio_rb64(in); + if (flags & MOV_TFHD_STSD_ID) + avio_rb32(in); + if (flags & MOV_TFHD_DEFAULT_DURATION) + default_duration = avio_rb32(in); + } + if (tag == MKBETAG('t', 'r', 'u', 'n')) { + return read_trun_duration(in, default_duration, + pos + size); + } + avio_seek(in, pos + size, SEEK_SET); + } + fprintf(stderr, "Couldn't find trun\n"); + goto fail; + } + avio_seek(in, pos + size, SEEK_SET); + } + fprintf(stderr, "Couldn't find traf\n"); + +fail: + return ret; +} + static int read_tfra(struct Tracks *tracks, int start_index, AVIOContext *f) { int ret = AVERROR_EOF, track_id; @@ -254,6 +343,8 @@ static int read_tfra(struct Tracks *tracks, int start_index, AVIOContext *f) ret = AVERROR(ENOMEM); goto fail; } + // The duration here is always the difference between consecutive + // start times. for (i = 0; i < track->chunks; i++) { if (version == 1) { track->offsets[i].time = avio_rb64(f); @@ -272,9 +363,41 @@ static int read_tfra(struct Tracks *tracks, int start_index, AVIOContext *f) track->offsets[i - 1].duration = track->offsets[i].time - track->offsets[i - 1].time; } - if (track->chunks > 0) - track->offsets[track->chunks - 1].duration = track->duration - + if (track->chunks > 0) { + track->offsets[track->chunks - 1].duration = track->offsets[0].time + + track->duration - track->offsets[track->chunks - 1].time; + } + // Now try and read the actual durations from the trun sample data. + for (i = 0; i < track->chunks; i++) { + int64_t duration = read_moof_duration(f, track->offsets[i].offset); + if (duration > 0 && abs(duration - track->offsets[i].duration) > 3) { + // 3 allows for integer duration to drift a few units, + // e.g., for 1/3 durations + track->offsets[i].duration = duration; + } + } + if (track->chunks > 0) { + if (track->offsets[track->chunks - 1].duration <= 0) { + fprintf(stderr, "Calculated last chunk duration for track %d " + "was non-positive (%"PRId64"), probably due to missing " + "fragments ", track->track_id, + track->offsets[track->chunks - 1].duration); + if (track->chunks > 1) { + track->offsets[track->chunks - 1].duration = + track->offsets[track->chunks - 2].duration; + } else { + track->offsets[track->chunks - 1].duration = 1; + } + fprintf(stderr, "corrected to %"PRId64"\n", + track->offsets[track->chunks - 1].duration); + track->duration = track->offsets[track->chunks - 1].time + + track->offsets[track->chunks - 1].duration - + track->offsets[0].time; + fprintf(stderr, "Track duration corrected to %"PRId64"\n", + track->duration); + } + } ret = 0; fail: @@ -526,6 +649,7 @@ static void print_track_chunks(FILE *out, struct Tracks *tracks, int main, const char *type) { int i, j; + int64_t pos = 0; struct Track *track = tracks->tracks[main]; int should_print_time_mismatch = 1; @@ -545,8 +669,14 @@ static void print_track_chunks(FILE *out, struct Tracks *tracks, int main, } } } - fprintf(out, "\t\t\n", + fprintf(out, "\t\toffsets[i].duration); + if (pos != track->offsets[i].time) { + fprintf(out, "t=\"%"PRId64"\" ", track->offsets[i].time); + pos = track->offsets[i].time; + } + pos += track->offsets[i].duration; + fprintf(out, "/>\n"); } }