[FFmpeg-devel] Seeking in Apple HTTP Live Streaming

Takis Issaris takis.issaris at uhasselt.be
Wed Dec 14 14:59:18 CET 2011


Hi,

2011/12/14 Takis Issaris <t4k1s at yahoo.com>:
> Hi,
>
> ----- Original Message -----
>
>> From: Michael Niedermayer <michaelni at gmx.at>
>> To: FFmpeg development discussions and patches <ffmpeg-devel at ffmpeg.org>
>> Cc:
>> Sent: Monday, November 28, 2011 10:20 PM
>> Subject: Re: [FFmpeg-devel] Seeking in Apple HTTP Live Streaming
>>
>> On Mon, Nov 28, 2011 at 04:45:18AM -0800, Takis Issaris wrote:
>>>  Hi,
>>>
>>> [...]
>>>
>>>  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
>>
>
> That was my mistake, sorry about that. I didn't work  because I had built a minimal FFmpeg version and had left out the AVParser.
>
>
> As all audio packets have the keyframe flag set, seeks would stop on the first audiopacket when seeking for a keyframe. Which is not what one would want. So, in the current patch I keep a variable indicating if the current variant contains video, if so, seeks without AVSEEK_FLAG_ANY will seek to the first video keyframe.
>
>
>>>   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
>
> I'm not sure how to handle this. Would it be better to use pts instead of dts? After looking at the MPEG TS spec it appears pts is more likely to be available then dts.
>
> Currently, I abort seeking when encountering a packet without dts.


Attached, the current code.

>
>>
>> otherwise the principle looks good
>>
>>
>> [...]
>>
>> --
>> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>>
>> The educated differ from the uneducated as much as the living from the
>> dead. -- Aristotle


With friendly regards,
Takis
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Enhance-Apple-HTTP-Livestream-seeking.patch
Type: text/x-patch
Size: 4678 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20111214/c16e1d4f/attachment.bin>


More information about the ffmpeg-devel mailing list