[FFmpeg-devel] Seeking in Apple HTTP Live Streaming

Michael Niedermayer michaelni at gmx.at
Mon Nov 28 22:20:56 CET 2011


On Mon, Nov 28, 2011 at 04:45:18AM -0800, Takis Issaris wrote:
> Hi,
> 
> ----- Original Message -----
> 
> > From: Michael Niedermayer <michaelni at gmx.at>
> > To: FFmpeg development discussions and patches <ffmpeg-devel at ffmpeg.org>
> > Cc: 
> > Sent: Tuesday, November 22, 2011 1:20 AM
> > Subject: Re: [FFmpeg-devel] Seeking in Apple HTTP Live Streaming
> > 
> > On Mon, Nov 21, 2011 at 04:14:03PM -0800, Takis Issaris wrote:
> >> 
> >> 
> >>  ----- Original Message -----
> >>  > From: Michael Niedermayer <michaelni at gmx.at>
> >>  > To: FFmpeg development discussions and patches 
> > <ffmpeg-devel at ffmpeg.org>
> >>  > Cc: 
> >>  > Sent: Tuesday, November 22, 2011 12:40 AM
> >>  > Subject: Re: [FFmpeg-devel] Seeking in Apple HTTP Live Streaming
> >>  > 
> >>  > On Mon, Nov 21, 2011 at 03:01:43PM -0800, Takis Issaris wrote:
> >>  >>  Hi Michael,
> >>  >> 
> >>  >> 
> >>  >>  ----- Original Message -----
> >>  >>  > From: Michael Niedermayer <michaelni at gmx.at>
> >>  >>  > To: FFmpeg development discussions and patches 
> >>  > <ffmpeg-devel at ffmpeg.org>
> >>  >>  > Cc: 
> >>  >>  > Sent: Monday, November 21, 2011 8:34 PM
> >>  >>  > Subject: Re: [FFmpeg-devel] Seeking in Apple HTTP Live 
> > Streaming
> >>  >>  > 
> >>  >>  > On Mon, Nov 21, 2011 at 08:21:28AM -0800, Takis Issaris 
> > wrote:
> >>  >>  >>  Hi all,
> >>  >>  >> 
> >>  >>  >> 
> >>  >>  >>  As a follow-up to my previous patch, I'd like to 
> > implement 
> >>  > more exact 
> >>  >>  > seeking on HTTP Live Streams. Currently, when seeking to a 
> > specific 
> >>  > timestamp in 
> >>  >>  > such a stream, the seeking results in arriving at the start 
> > of the 
> >>  > correct 
> >>  >>  > segment, but not at the requested timestamp within that 
> > segment. 
> >>  > Worse, when 
> >>  >>  > seeking to a specific timestamp which happens to be a part 
> > of the 
> >>  > segment which 
> >>  >>  > is currently being played, the playback resets to the start 
> > of the 
> >>  > current 
> >>  >>  > timestamp (that could most likely be fixed rather easily). 
> > So, when 
> >>  > pressing 
> >>  >>  > forward arrow key when using ffplay, you'll actually 
> > move 
> >>  > backwards to the 
> >>  >>  > start of the segment (if current timestamp+10s lies within 
> > the current 
> >>  > segment).
> >>  >>  >> 
> >>  >>  >> 
> >>  >>  >>  I'd like to change that so that the applehttp.c 
> > seeking 
> >>  > implementation 
> >>  >>  > uses mpegts.c to actually seek to the specified timestamp, 
> > but I'm 
> >>  > not sure 
> >>  >>  > on how to implement this.
> >>  >>  >>  Currently, when seeking using applehttp_read_seek, I 
> > think 
> >>  > there's no 
> >>  >>  > valid MPEG-TS demuxer context in that function. Should I 
> > make sure I 
> >>  > get a valid 
> >>  >>  > demuxer there, or should I defer the actual seeking using 
> > the MPEG-TS 
> >>  > demuxer 
> >>  >>  > until a valid demuxer is constructed elsewhere in the 
> > applehttp.c 
> >>  > file?
> >>  >>  > 
> >>  >>  > I assume theres no way to tell the server to start a segment 
> > from a
> >>  >>  > specific time? (i havnt found one)
> >>  >> 
> >>  >>  No, I don't think so (haven't found one either).
> >>  >> 
> >>  >> 
> >>  >>  > Do the servers support seeking to a specific byte position 
> > within a
> >>  >>  > segment ?
> >>  >> 
> >>  >>  Yes, it's just an Apache HTTP server, so it supports GET with 
> > a byte 
> >>  > range (If that
> >>  >>  was what you were hinting at).
> >>  >> 
> >>  >> 
> >>  >>  > If yes, seeking per CBR assumption is an option which also 
> > doesnt need
> >>  >>  > the demuxer
> >>  >> 
> >>  >>  Yes, initially I'd never even considered CBR. But as I start 
> > to think 
> >>  > about it,
> >>  >>  the seeking speedup could counterweight the quality/bitrate 
> > disadvantage.
> >>  >> 
> >>  >> 
> >>  >>  > The reason why i suggect to assume CBR is that the 
> > alternative is
> >>  >>  > the default seek per timestamp which does a binary search 
> > and this
> >>  >>  > could be quite slow with http needing to send a few packets 
> > back and
> >>  >>  > forth for each iteration of the search
> >>  >> 
> >>  >> 
> >>  >>  Yes, but the draft recommends using 10 second segments, so 
> > I'd hoped 
> >>  > that
> >>  >>  the actual number of HTTP GETs needed would be rather limited.
> >>  >> 
> >>  >>   
> >>  >>  > depending on network speed, bitrate and segment size a 
> > linear search
> >>  >>  > could also be considered, that is demux and throw away 
> > packets until
> >>  >>  > the right time, this may or may not be faster than a binary 
> > search
> >>  >> 
> >>  >>  Yes, I'd thought about doing something like that as the 
> > applehttp.c 
> >>  > seek 
> >>  >>  already skips to the correct 10s segment, so a linear search 
> > within that 
> >>  > should
> >>  >>  not take that long.
> >>  >> 
> >>  >>  Would something like that be useful in applehttp.c or should it 
> > be kept in 
> >>  > application
> >>  >>  specific code?
> >>  > 
> >>  > requireing applehttp specific code in every app does not seem a good
> >>  > idea to me thus IMHO its better in applehttp.c
> >> 
> >>  Agreed. Should the seeking be completed after returning from 
> > applehttp.c's
> >>  seeking call or would it be acceptable that the actual search happens 
> > elsewhere?
> >>  (f.e. somewhere near the read frame call or near the open url call).
> > 
> > do whatever makes most sense technically
> > 
> > [...]
> 
> 
> I had a look at this last Tuesday, and only did some experiments, but,
> nevertheless, I'd rather post the code and get your opinion on the approach, then let it
> rot for another week :-/
> 
> It is in no way clean nor did I take into account possible variants, MPEG-TS
> files with many streams etc. But, if the general approach is okay (that is, storing
> seeking state in applehttp_read_seek() and afterwards skipping packets in
> applehttp_read_packet(), I'll start cleaning and correcting the code for all cases.
> 
> So, I'm obviously not suggesting committing this :-)
> 
> In the patch ending in v0p2.diff, I tried to allow seeking to keyframes, but didn't know how to do this cleanly, thus the horrible hack. Should the MPEG TS demuxer be modified to set AV_PKT_FLAG_KEY in pkt.flags?

the AVParser that comes after the demuxer should set that flag
already. judging from your hack it seems it does for some reason not
do that, i dont know why


> 
> 
> With friendly regards,
> Takis

>  applehttp.c |   34 ++++++++++++++++++++++++++--------
>  1 file changed, 26 insertions(+), 8 deletions(-)
> 2e7bec013da203499f9cdf6392571cbcef63fc5f  phmi-20111128T1324-ffmpeg-hls_seek_timestamp_v0.diff
> commit 432ceba2329492669fa19fc87d2114f4b42e67bd
> Author: Panagiotis H.M. Issaris <takis.issaris at uhasselt.be>
> Date:   Tue Nov 22 11:33:17 2011 +0100
> 
>     Seek until right after the requested timestamp
> 
> diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c
> index 1694096..0e7074b 100644
> --- a/libavformat/applehttp.c
> +++ b/libavformat/applehttp.c
> @@ -100,6 +100,7 @@ typedef struct AppleHTTPContext {
>      int end_of_segment;
>      int first_packet;
>      int64_t first_timestamp;
> +    int64_t seek_timestamp;
>      AVIOInterruptCB *interrupt_callback;
>  } AppleHTTPContext;
>  
> @@ -529,6 +530,7 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap)
>  
>      c->first_packet = 1;
>      c->first_timestamp = AV_NOPTS_VALUE;
> +    c->seek_timestamp = AV_NOPTS_VALUE;
>  
>      return 0;
>  fail:
> @@ -588,14 +590,29 @@ start:
>          /* Make sure we've got one buffered packet from each open variant
>           * stream */
>          if (var->needed && !var->pkt.data) {
> -            ret = av_read_frame(var->ctx, &var->pkt);
> -            if (ret < 0) {
> -                if (!url_feof(&var->pb))
> -                    return ret;
> -                reset_packet(&var->pkt);
> -            } else {
> -                if (c->first_timestamp == AV_NOPTS_VALUE)
> -                    c->first_timestamp = var->pkt.dts;
> +            int skipped_packets = 0;
> +            while (1) {
> +                ret = av_read_frame(var->ctx, &var->pkt);
> +                if (ret < 0) {
> +                    if (!url_feof(&var->pb))
> +                        return ret;
> +                    reset_packet(&var->pkt);
> +                } else {
> +                    if (c->first_timestamp == AV_NOPTS_VALUE)
> +                        c->first_timestamp = var->pkt.dts;
> +                }
> +
> +                if (c->seek_timestamp==AV_NOPTS_VALUE)
> +                    break;
> +
> +                int64_t ts_diff = var->pkt.dts - c->seek_timestamp;

i dont think dts is guranteed to be != AV_NOPTS_VALUE here

otherwise the principle looks good


[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The educated differ from the uneducated as much as the living from the
dead. -- Aristotle 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20111128/83e34301/attachment.asc>


More information about the ffmpeg-devel mailing list