1 /*
2 * Apple HTTP Live Streaming Protocol Handler
3 * Copyright (c) 2010 Martin Storsjo
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * Apple HTTP Live Streaming Protocol Handler
25 * http://tools.ietf.org/html/draft-pantos-http-live-streaming
26 */
27
34
35 /*
36 * An apple http stream consists of a playlist with media segment files,
37 * played sequentially. There may be several playlists with the same
38 * video content, in different bandwidth variants, that are played in
39 * parallel (preferably only one bandwidth variant at a time). In this case,
40 * the user supplied the url to a main playlist that only lists the variant
41 * playlists.
42 *
43 * If the main playlist doesn't point at any variants, we still create
44 * one anonymous toplevel variant for this, to maintain the structure.
45 */
46
50 };
51
55 };
56
70
72 {
77 }
78
80 {
81 int i;
86 }
87
89 {
90 int i;
95 }
96
99 };
100
102 int key_len, char **dest, int *dest_len)
103 {
104 if (!strncmp(key, "BANDWIDTH=", key_len)) {
107 }
108 }
109
111 {
114 int ret = 0,
duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
116 const char *ptr;
117
121
123 if (strcmp(line, "#EXTM3U"))
125
130 if (
av_strstart(line,
"#EXT-X-STREAM-INF:", &ptr)) {
132 is_variant = 1;
134 &info);
136 }
else if (
av_strstart(line,
"#EXT-X-TARGETDURATION:", &ptr)) {
138 }
else if (
av_strstart(line,
"#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
140 }
else if (
av_strstart(line,
"#EXT-X-ENDLIST", &ptr)) {
143 is_segment = 1;
146 continue;
147 } else if (line[0]) {
148 if (is_segment) {
150 if (!seg) {
152 goto fail;
153 }
157 is_segment = 0;
158 } else if (is_variant) {
160 if (!var) {
162 goto fail;
163 }
167 is_variant = 0;
168 }
169 }
170 }
172
173 fail:
176 }
177
179 {
181
185 return 0;
186 }
187
189 {
192 const char *nested_url;
193
196
198
201 }
else if (
av_strstart(uri,
"hls://", &nested_url)) {
203 "No nested protocol specified. Specify e.g. hls+http://%s\n",
204 nested_url);
206 goto fail;
207 } else {
210 goto fail;
211 }
213 "Using the hls protocol is discouraged, please try using the "
214 "hls demuxer instead. The hls demuxer should be more complete "
215 "and work as well as the protocol implementation. (If not, "
216 "please report it.) To use the demuxer, simply use %s as url.\n",
218
220 goto fail;
221
227 maxvar = i;
228 }
229 }
233 goto fail;
234 }
235
239 goto fail;
240 }
244
245 return 0;
246
247 fail:
250 }
251
253 {
257 int64_t reload_interval;
258
262 if (ret > 0)
264 }
269 }
273 reload_interval *= 1000000;
274 retry:
280 /* If we need to reload the playlist again below (if
281 * there's still no more segments), switch to a reload
282 * interval of half the target duration. */
284 }
285 }
288 "skipping %d segments ahead, expired from playlist\n",
291 }
299 }
300 goto retry;
301 }
306 if (ret < 0) {
311 goto retry;
312 }
314 }
315
323 };