On 8 October 2014 08:12, Mika Raento <mi...@iki.fi> wrote: > Reads the fragment duration from the trun sample data, rather than > assuming that there are no gaps. Creates much better playlists for our > inputs. > --- > tools/ismindex.c | 96 > +++++++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 85 insertions(+), 11 deletions(-) > > diff --git a/tools/ismindex.c b/tools/ismindex.c > index 734419b..dcbc115 100644 > --- a/tools/ismindex.c > +++ b/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,78 @@ fail: > return ret; > } > > +static int64_t read_trun_duration(AVIOContext *in, int64_t end) > +{ > + int64_t ret = 0; > + int64_t pos; > + int flags, i; > + int entries; > + avio_r8(in); /* version */ > + flags = avio_rb24(in); > + if (! (flags & MOV_TRUN_SAMPLE_DURATION)) { > + fprintf(stderr, "no sample duration in trun flags"); > + 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 = 0; > + 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; > + > + 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', 'r', 'u', 'n')) { > + return read_trun_duration(in, pos + size); > + } > + avio_seek(in, pos + size, SEEK_SET); > + } > + fprintf(stderr, "couldn't find trun"); > + goto fail; > + } > + avio_seek(in, pos + size, SEEK_SET); > + } > + fprintf(stderr, "couldn't find traf"); > + > +fail: > + return ret; > +} > + > static int read_tfra(struct Tracks *tracks, int start_index, AVIOContext *f) > { > int ret = AVERROR_EOF, track_id; > @@ -255,12 +328,7 @@ static int read_tfra(struct Tracks *tracks, int > start_index, AVIOContext *f) > goto fail; > } > // The duration here is always the difference between consecutive > - // start times and doesn't even try to read the actual duration of the > - // media fragments. This is what other smooth streaming tools tend to > - // do too, but cannot express missing fragments, and the start times > - // may not match the stream metadata we get from libavformat. Correct > - // calculation would require parsing the tfxd atom (if present, it's > - // not mandatory) or parsing the full moof atoms separately. > + // start times. > for (i = 0; i < track->chunks; i++) { > if (version == 1) { > track->offsets[i].time = avio_rb64(f); > @@ -283,6 +351,15 @@ static int read_tfra(struct Tracks *tracks, int > start_index, AVIOContext *f) > 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) { > + 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 " > @@ -576,11 +653,8 @@ static void print_track_chunks(FILE *out, struct Tracks > *tracks, int main, > } > fprintf(out, "\t\t<c n=\"%d\" d=\"%"PRId64"\" ", > i, track->offsets[i].duration); > - if (pos != track->offsets[i].time) { > - // With the current logic for calculation of durations from > - // chunk start times, this branch can only be hit on the first > - // chunk - but that's still useful and this will keep working > - // if the duration calculation is improved. > + if (abs(pos - track->offsets[i].time) > 3) { > + // 3 allows for t to drift a few units, e.g., for 1/3 durations > fprintf(out, "t=\"%"PRId64"\" ", track->offsets[i].time); > pos = track->offsets[i].time; > }
Martin rightly says that this is wrong: we must not fuzz the segment start times, as they must match between the playlist and the generated files. I'll change to fuzz the duration instead. BRB. > -- > 1.9.3 (Apple Git-50) > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel