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