]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/applehttp.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavformat / applehttp.c
index 32a51fede1adac15f2fd6817512b3b00db5a9754..7e6346a98910277372056ff3054ac91e574cad42 100644 (file)
@@ -2,20 +2,20 @@
  * Apple HTTP Live Streaming demuxer
  * Copyright (c) 2010 Martin Storsjo
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -100,6 +100,8 @@ typedef struct AppleHTTPContext {
     int end_of_segment;
     int first_packet;
     int64_t first_timestamp;
+    int64_t seek_timestamp;
+    int seek_flags;
     AVIOInterruptCB *interrupt_callback;
 } AppleHTTPContext;
 
@@ -226,7 +228,7 @@ static int parse_playlist(AppleHTTPContext *c, const char *url,
         free_segment_list(var);
         var->finished = 0;
     }
-    while (!in->eof_reached) {
+    while (!url_feof(in)) {
         read_chomp_line(in, line, sizeof(line));
         if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
             struct variant_info info = {{0}};
@@ -545,6 +547,7 @@ static int applehttp_read_header(AVFormatContext *s)
 
     c->first_packet = 1;
     c->first_timestamp = AV_NOPTS_VALUE;
+    c->seek_timestamp = AV_NOPTS_VALUE;
 
     return 0;
 fail:
@@ -559,7 +562,7 @@ static int recheck_discard_flags(AVFormatContext *s, int first)
 
     /* Check if any new streams are needed */
     for (i = 0; i < c->n_variants; i++)
-        c->variants[i]->cur_needed = 0;;
+        c->variants[i]->cur_needed = 0;
 
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
@@ -604,14 +607,44 @@ 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 (!var->pb.eof_reached)
-                    return ret;
-                reset_packet(&var->pkt);
-            } else {
-                if (c->first_timestamp == AV_NOPTS_VALUE)
-                    c->first_timestamp = var->pkt.dts;
+            while (1) {
+                int64_t ts_diff;
+                ret = av_read_frame(var->ctx, &var->pkt);
+                if (ret < 0) {
+                    if (!url_feof(&var->pb)) {
+                        return ret;
+                    } else {
+                        if ((var->cur_seq_no - var->start_seq_no) == (var->n_segments)) {
+                            return AVERROR_EOF;
+                        }
+                    }
+                    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;
+
+                if (var->pkt.dts == AV_NOPTS_VALUE) {
+                    c->seek_timestamp = AV_NOPTS_VALUE;
+                    break;
+                }
+
+                ts_diff = var->pkt.dts - c->seek_timestamp;
+                if (ts_diff >= 0) {
+                    if (c->seek_flags & AVSEEK_FLAG_ANY) {
+                        c->seek_timestamp = AV_NOPTS_VALUE;
+                        break;
+                    }
+
+                    /* Seek to keyframe */
+                    if (var->pkt.flags & AV_PKT_FLAG_KEY) {
+                        c->seek_timestamp = AV_NOPTS_VALUE;
+                        break;
+                    }
+                }
             }
         }
         /* Check if this stream has the packet with the lowest dts */
@@ -652,19 +685,27 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index,
     if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
         return AVERROR(ENOSYS);
 
+    c->seek_timestamp = timestamp;
+    c->seek_flags = flags;
     timestamp = av_rescale_rnd(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 (s->duration < c->seek_timestamp) {
+        c->seek_timestamp = AV_NOPTS_VALUE;
+        return AVERROR(EIO);
+    }
+
     ret = AVERROR(EIO);
     for (i = 0; i < c->n_variants; i++) {
         /* Reset reading */
         struct variant *var = c->variants[i];
         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) {
+                      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;
         }
@@ -682,6 +723,8 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index,
             }
             pos += var->segments[j]->duration;
         }
+        if (ret != 0)
+            c->seek_timestamp = AV_NOPTS_VALUE;
     }
     return ret;
 }