applehttp: Fix seeking in streams not starting at DTS=0

Message ID 1321433744-15415-1-git-send-email-martin@martin.st
State Committed
Headers show

Commit Message

Martin Storsjö Nov. 16, 2011, 8:55 a.m.
From: Panagiotis H.M. Issaris <takis.issaris@uhasselt.be>

The Apple HTTP Live Streaming demuxer's implementation of
seeking searches for the MPEG TS segment which contains the
requested timestamp.  In its current implementation it assumes
that the first segment will start from 0.

But, MPEG TS streams do not necessarily start with timestamp
(near) 0, causing seeking to fail for those streams.

This also occurs when using live streaming of HTTP Live Streams.
In this case sliding playlists may be used, which means that in
that case only the last x encoded segments are stored, the earlier
segments get deleted from disk and removed from the playlist.
Because of this, when starting playback of a stream in the middle
of such a broadcast, the initial segment fetched after parsing
the m3u8 playlist will not start from timestamp (near) 0, causing
(the admittedly limited live) seeking to fail.

This patch changes this demuxers seeking implementation to use
the initial DTS as an offset for searching the segments containing
the requested timestamp.
---
 libavformat/applehttp.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

Comments

Anton Khirnov Nov. 18, 2011, 7:12 a.m. | #1
On Wed, 16 Nov 2011 10:55:44 +0200, Martin Storsjö <martin@martin.st> wrote:
> From: Panagiotis H.M. Issaris <takis.issaris@uhasselt.be>
> 
> The Apple HTTP Live Streaming demuxer's implementation of
> seeking searches for the MPEG TS segment which contains the
> requested timestamp.  In its current implementation it assumes
> that the first segment will start from 0.
> 
> But, MPEG TS streams do not necessarily start with timestamp
> (near) 0, causing seeking to fail for those streams.
> 
> This also occurs when using live streaming of HTTP Live Streams.
> In this case sliding playlists may be used, which means that in
> that case only the last x encoded segments are stored, the earlier
> segments get deleted from disk and removed from the playlist.
> Because of this, when starting playback of a stream in the middle
> of such a broadcast, the initial segment fetched after parsing
> the m3u8 playlist will not start from timestamp (near) 0, causing
> (the admittedly limited live) seeking to fail.
> 
> This patch changes this demuxers seeking implementation to use
> the initial DTS as an offset for searching the segments containing
> the requested timestamp.
> ---
>  libavformat/applehttp.c |   11 ++++++++++-
>  1 files changed, 10 insertions(+), 1 deletions(-)
> 
> diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c
> index e0773ae..6570370 100644
> --- a/libavformat/applehttp.c
> +++ b/libavformat/applehttp.c
> @@ -99,6 +99,7 @@ typedef struct AppleHTTPContext {
>      int cur_seq_no;
>      int end_of_segment;
>      int first_packet;
> +    int64_t first_timestamp;
>      AVIOInterruptCB *interrupt_callback;
>  } AppleHTTPContext;
>  
> @@ -527,6 +528,7 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap)
>      }
>  
>      c->first_packet = 1;
> +    c->first_timestamp = AV_NOPTS_VALUE;
>  
>      return 0;
>  fail:
> @@ -591,6 +593,9 @@ start:
>                  if (!var->pb.eof_reached)
>                      return ret;
>                  reset_packet(&var->pkt);
> +            } else {
> +                if (c->first_timestamp == AV_NOPTS_VALUE)
> +                    c->first_timestamp = var->pkt.dts;
>              }
>          }
>          /* Check if this stream has the packet with the lowest dts */
> @@ -639,7 +644,11 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index,
>      for (i = 0; i < c->n_variants; i++) {
>          /* Reset reading */
>          struct variant *var = c->variants[i];
> -        int64_t pos = 0;
> +        int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
> +                      av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ?
> +                               s->streams[stream_index]->time_base.den :
> +                               AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
> +                               AV_ROUND_DOWN : AV_ROUND_UP);

The code looks sane and if you think it's ok, then feel free to push.
Just a nitpick for this last block -- it looks a bit unreadable. Could you
restructure it a little?

Patch

diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c
index e0773ae..6570370 100644
--- a/libavformat/applehttp.c
+++ b/libavformat/applehttp.c
@@ -99,6 +99,7 @@  typedef struct AppleHTTPContext {
     int cur_seq_no;
     int end_of_segment;
     int first_packet;
+    int64_t first_timestamp;
     AVIOInterruptCB *interrupt_callback;
 } AppleHTTPContext;
 
@@ -527,6 +528,7 @@  static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap)
     }
 
     c->first_packet = 1;
+    c->first_timestamp = AV_NOPTS_VALUE;
 
     return 0;
 fail:
@@ -591,6 +593,9 @@  start:
                 if (!var->pb.eof_reached)
                     return ret;
                 reset_packet(&var->pkt);
+            } else {
+                if (c->first_timestamp == AV_NOPTS_VALUE)
+                    c->first_timestamp = var->pkt.dts;
             }
         }
         /* Check if this stream has the packet with the lowest dts */
@@ -639,7 +644,11 @@  static int applehttp_read_seek(AVFormatContext *s, int stream_index,
     for (i = 0; i < c->n_variants; i++) {
         /* Reset reading */
         struct variant *var = c->variants[i];
-        int64_t pos = 0;
+        int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
+                      av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ?
+                               s->streams[stream_index]->time_base.den :
+                               AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
+                               AV_ROUND_DOWN : AV_ROUND_UP);
         if (var->input) {
             ffurl_close(var->input);
             var->input = NULL;