[3/5] dashenc: Set the Period start time to the latest stream start time when using timeline

Message ID 1416234526-54560-3-git-send-email-martin@martin.st
State Deferred
Headers show

Commit Message

Martin Storsjö Nov. 17, 2014, 2:28 p.m.
If one stream doesn't start exactly at time 0 (as signaled via
the SegmentTimeline) while the Period says playback starts at 0,
dash.js won't be able to start playing it, since it doesn't find
any segment corresponding to time 0.

Currently this isn't needed yet, when segment timestamps are based
on dts (which by default are adjusted to start at zero), but will
become necessary later.
---
 libavformat/dashenc.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

Comments

Martin Storsjö Nov. 18, 2014, 9:04 p.m. | #1
On Mon, 17 Nov 2014, Martin Storsjö wrote:

> If one stream doesn't start exactly at time 0 (as signaled via
> the SegmentTimeline) while the Period says playback starts at 0,
> dash.js won't be able to start playing it, since it doesn't find
> any segment corresponding to time 0.
>
> Currently this isn't needed yet, when segment timestamps are based
> on dts (which by default are adjusted to start at zero), but will
> become necessary later.
> ---
> libavformat/dashenc.c | 21 ++++++++++++++++-----
> 1 file changed, 16 insertions(+), 5 deletions(-)

OK'd by Derek on irc.

// Martin
Martin Storsjö Nov. 24, 2014, 9:58 a.m. | #2
On Mon, 17 Nov 2014, Martin Storsjö wrote:

> If one stream doesn't start exactly at time 0 (as signaled via
> the SegmentTimeline) while the Period says playback starts at 0,
> dash.js won't be able to start playing it, since it doesn't find
> any segment corresponding to time 0.
>
> Currently this isn't needed yet, when segment timestamps are based
> on dts (which by default are adjusted to start at zero), but will
> become necessary later.
> ---
> libavformat/dashenc.c | 21 ++++++++++++++++-----
> 1 file changed, 16 insertions(+), 5 deletions(-)

Actually, I don't think this is correct. dash.js seems to have problems 
with nonzero start times, and this is a workaround for that (which only 
works on the current 1.2.0 release, not on the latest git version). After 
thinking more about it, the workaround itself is incorrect as well.

It is only required if writing timelines based on pts (for dts, the start 
timestamp is forced to zero anyway).

We do however already do the same in sidxindex, since a player reading the 
sidx boxes does get the presentation timestamps which don't start from 
zero. (That corner case doesn't work currently on the next dash.js 
development version as well.)

So this patchset is deferred for now. The patch for using pts instead of 
dts in the timeline is correct as far as I know, except that it breaks 
playback in dash.js with anything that uses b-frames, so I'll hold off 
that one for now, at least until the situation has been sorted out on 
their side.

// Martin

Patch

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 1368b19..66d8a13 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -291,6 +291,7 @@  static int write_manifest(AVFormatContext *s, int final)
     char temp_filename[1024];
     int ret, i;
     AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
+    int64_t start_time;
 
     snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename);
     ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
@@ -346,13 +347,23 @@  static int write_manifest(AVFormatContext *s, int final)
     if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) {
         OutputStream *os = &c->streams[0];
         int start_index = FFMAX(os->nb_segments - c->window_size, 0);
-        int64_t start_time = av_rescale_q(os->segments[start_index]->time, s->streams[0]->time_base, AV_TIME_BASE_Q);
-        avio_printf(out, "\t<Period start=\"");
-        write_time(out, start_time, 1, AV_ROUND_UP);
-        avio_printf(out, "\">\n");
+        start_time = av_rescale_q(os->segments[start_index]->time, s->streams[0]->time_base, AV_TIME_BASE_Q);
+    } else if (c->use_template && c->use_timeline) {
+        start_time = 0;
+        for (i = 0; i < s->nb_streams; i++) {
+            if (c->streams[i].first_dts != AV_NOPTS_VALUE) {
+                start_time = FFMAX(start_time,
+                                   av_rescale_q_rnd(c->streams[i].first_dts,
+                                                    s->streams[i]->time_base,
+                                                    AV_TIME_BASE_Q, AV_ROUND_UP));
+            }
+        }
     } else {
-        avio_printf(out, "\t<Period start=\"PT0.0S\">\n");
+        start_time = 0;
     }
+    avio_printf(out, "\t<Period start=\"");
+    write_time(out, start_time, 3, AV_ROUND_UP);
+    avio_printf(out, "\">\n");
 
     if (c->has_video) {
         avio_printf(out, "\t\t<AdaptationSet id=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n");