The input file may not be contiguous in time, this produces the right
manifest to keep video and audio in sync.
---
 tools/ismindex.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 1 deletion(-)

diff --git a/tools/ismindex.c b/tools/ismindex.c
index bc98226..b605c9f 100644
--- a/tools/ismindex.c
+++ b/tools/ismindex.c
@@ -252,6 +252,11 @@ 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 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 libavcodec.
     for (i = 0; i < track->chunks; i++) {
         if (version == 1) {
             track->offsets[i].time   = avio_rb64(f);
@@ -280,6 +285,48 @@ fail:
     return ret;
 }
 
+static int normalize_track_times(struct Tracks *tracks, int start_index) {
+    // The fragment start times and durations may not match the stream
+    // (track) data, this makes an effort to fix them.
+    int i;
+    int64_t smallest_start_time = INT64_MAX, largest_duration = 0;
+    for (i = start_index; i < tracks->nb_tracks; i++) {
+        smallest_start_time = FFMIN(smallest_start_time,
+                                    tracks->tracks[i]->offsets[0].time);
+    }
+    if (smallest_start_time > 0) {
+        fprintf(stderr, "Subtracting %"PRId64" from all start times\n",
+                smallest_start_time);
+        for (i = start_index; i < tracks->nb_tracks; i++) {
+            struct Track *track = tracks->tracks[i];
+            int j;
+            for (j = 0; j < track->chunks; j++) {
+                track->offsets[j].time -= smallest_start_time;
+            }
+        }
+    }
+    for (i = start_index; i < tracks->nb_tracks; i++) {
+        struct Track *track = tracks->tracks[i];
+        if (track->offsets[track->chunks - 1].time + 1 > track->duration) {
+            fprintf(stderr, "Rewriting track %d duration from "
+                    "%"PRId64" to %"PRId64"\n", track->track_id,
+                    track->duration,
+                    track->offsets[track->chunks - 1].time + 1);
+            track->duration = track->offsets[track->chunks - 1].time;
+            largest_duration = FFMAX(track->duration, largest_duration);
+        }
+        track->offsets[track->chunks - 1].duration =
+            track->duration - track->offsets[track->chunks - 1].time;
+    }
+    if (largest_duration > tracks->duration) {
+        fprintf(stderr, "Rewriting total duration from "
+                "%"PRId64" to %"PRId64"\n", tracks->duration,
+                largest_duration);
+        tracks->duration = largest_duration;
+    }
+    return 0;
+}
+
 static int read_mfra(struct Tracks *tracks, int start_index,
                      const char *file, int split, int ismf,
                      const char *basename, const char* output_prefix)
@@ -288,6 +335,7 @@ static int read_mfra(struct Tracks *tracks, int start_index,
     const char* err_str = "";
     AVIOContext *f = NULL;
     int32_t mfra_size;
+    int normalize = 0;
 
     if ((err = avio_open2(&f, file, AVIO_FLAG_READ, NULL, NULL)) < 0)
         goto fail;
@@ -308,6 +356,21 @@ static int read_mfra(struct Tracks *tracks, int 
start_index,
         /* Empty */
     }
 
+    for (int i = start_index; i < tracks->nb_tracks; i++) {
+        struct Track *track = tracks->tracks[i];
+        int64_t last_time = track->offsets[track->chunks - 1].time;
+        if (track->duration <= last_time) {
+            fprintf(stderr, "Track %d duration %"PRId64" is less than (or "
+                    "equal to) last chunk start time %"PRId64", forcing "
+                    "timestamp normalization\n", track->track_id,
+                    track->duration, last_time);
+            normalize = 1;
+        }
+    }
+    
+    if (normalize)
+        normalize_track_times(tracks, start_index);
+
     if (split || ismf)
         err = write_fragments(tracks, start_index, f, basename, split, ismf,
                               output_prefix);
@@ -524,6 +587,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;
 
@@ -543,8 +607,18 @@ static void print_track_chunks(FILE *out, struct Tracks 
*tracks, int main,
                 }
             }
         }
-        fprintf(out, "\t\t<c n=\"%d\" d=\"%"PRId64"\" />\n",
+        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.
+            fprintf(out, "t=\"%"PRId64"\" ", track->offsets[i].time);
+            pos = track->offsets[i].time;
+        }
+        pos += track->offsets[i].duration;
+        fprintf(out, "/>\n");
     }
 }
 
-- 
1.8.5.2 (Apple Git-48)

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to