| 
				
				
					
				
				
				 | 
			
			 | 
			@@ -61,6 +61,8 @@ struct variant { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    AVPacket pkt; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int stream_offset; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int finished; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int target_duration; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int start_seq_no; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int n_segments; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    struct segment **segments; | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -68,8 +70,6 @@ struct variant { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			typedef struct AppleHTTPContext { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int target_duration; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int finished; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int n_variants; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    struct variant **variants; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int cur_seq_no; | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -170,9 +170,10 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        goto fail; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    } | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (var) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (var) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        free_segment_list(var); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    c->finished = 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        var->finished = 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    } | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    while (!in->eof_reached) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        read_chomp_line(in, line, sizeof(line)); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -182,7 +183,14 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                               &info); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            bandwidth = atoi(info.bandwidth); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            c->target_duration = atoi(ptr); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (!var) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                var = new_variant(c, 0, url, NULL); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if (!var) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    ret = AVERROR(ENOMEM); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    goto fail; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                } | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            } | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            var->target_duration = atoi(ptr); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (!var) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                var = new_variant(c, 0, url, NULL); | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -193,7 +201,8 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            } | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            var->start_seq_no = atoi(ptr); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            c->finished = 1; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (var) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                var->finished = 1; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        } else if (av_strstart(line, "#EXTINF:", &ptr)) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            is_segment = 1; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            duration   = atoi(ptr); | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -268,7 +277,7 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    /* If this isn't a live stream, calculate the total duration of the | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			     * stream. */ | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (c->finished) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (c->variants[0]->finished) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        int64_t duration = 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        for (i = 0; i < c->variants[0]->n_segments; i++) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            duration += c->variants[0]->segments[i]->duration; | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -306,7 +315,7 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    c->cur_seq_no = c->max_start_seq; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    /* If this is a live stream with more than 3 segments, start at the | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			     * third last segment. */ | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!c->finished && c->min_end_seq - c->max_start_seq > 3) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!c->variants[0]->finished && c->min_end_seq - c->max_start_seq > 3) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        c->cur_seq_no = c->min_end_seq - 2; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return 0; | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -326,7 +335,7 @@ static int open_variant(AppleHTTPContext *c, struct variant *var, int skip) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    } | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (c->cur_seq_no - var->start_seq_no >= var->n_segments) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return c->finished ? AVERROR_EOF : 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return c->variants[0]->finished ? AVERROR_EOF : 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    ret = avio_open(&var->pb, | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    var->segments[c->cur_seq_no - var->start_seq_no]->url, | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    URL_RDONLY); | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -390,7 +399,7 @@ start: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        } else if (!var->pb && var->needed) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (first) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                av_log(s, AV_LOG_DEBUG, "Opening variant stream %d\n", i); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (first && !c->finished) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            if (first && !var->finished) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                if ((ret = parse_playlist(c, var->url, var, NULL)) < 0) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                    return ret; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            ret = open_variant(c, var, first); | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -442,11 +451,11 @@ start: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    first = 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    c->cur_seq_no++; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			reload: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!c->finished) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!c->variants[0]->finished) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        /* If this is a live stream and target_duration has elapsed since | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			         * the last playlist reload, reload the variant playlists now. */ | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        int64_t now = av_gettime(); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (now - c->last_load_time >= c->target_duration*1000000) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (now - c->last_load_time >= c->variants[0]->target_duration*1000000) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            c->max_start_seq = 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            c->min_end_seq   = INT_MAX; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            for (i = 0; i < c->n_variants; i++) { | 
		
		
	
	
		
			
				| 
				
					
				
				
					
				
				
				 | 
			
			 | 
			@@ -473,9 +482,10 @@ reload: | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        goto start; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    /* We've reached the end of the playlists - return eof if this is a | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			     * non-live stream, wait until the next playlist reload if it is live. */ | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (c->finished) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (c->variants[0]->finished) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return AVERROR_EOF; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    while (av_gettime() - c->last_load_time < c->target_duration*1000000) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    while (av_gettime() - c->last_load_time < | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			           c->variants[0]->target_duration*1000000) { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (url_interrupt_cb()) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			            return AVERROR_EXIT; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        usleep(100*1000); | 
		
		
	
	
		
			
				| 
				
				
				
					
				
				 | 
			
			 | 
			@@ -500,7 +510,7 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index, | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int i; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    struct variant *var = c->variants[0]; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if ((flags & AVSEEK_FLAG_BYTE) || !c->finished) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished) | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        return AVERROR(ENOSYS); | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
  | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    /* Reset the variants */ | 
		
		
	
	
		
			
				| 
				
					
				
				
				
				 | 
			
			 | 
			
  |