hlsproto.c
Go to the documentation of this file.
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 
28 #include "libavutil/avstring.h"
29 #include "libavutil/time.h"
30 #include "avformat.h"
31 #include "internal.h"
32 #include "url.h"
33 #include "version.h"
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 
47 struct segment {
48  int duration;
49  char url[MAX_URL_SIZE];
50 };
51 
52 struct variant {
53  int bandwidth;
54  char url[MAX_URL_SIZE];
55 };
56 
57 typedef struct HLSContext {
58  char playlisturl[MAX_URL_SIZE];
61  int finished;
63  struct segment **segments;
64  int n_variants;
65  struct variant **variants;
66  int cur_seq_no;
68  int64_t last_load_time;
69 } HLSContext;
70 
71 static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
72 {
73  int len = ff_get_line(s, buf, maxlen);
74  while (len > 0 && av_isspace(buf[len - 1]))
75  buf[--len] = '\0';
76  return len;
77 }
78 
80 {
81  int i;
82  for (i = 0; i < s->n_segments; i++)
83  av_free(s->segments[i]);
84  av_freep(&s->segments);
85  s->n_segments = 0;
86 }
87 
89 {
90  int i;
91  for (i = 0; i < s->n_variants; i++)
92  av_free(s->variants[i]);
93  av_freep(&s->variants);
94  s->n_variants = 0;
95 }
96 
97 struct variant_info {
98  char bandwidth[20];
99 };
100 
101 static void handle_variant_args(struct variant_info *info, const char *key,
102  int key_len, char **dest, int *dest_len)
103 {
104  if (!strncmp(key, "BANDWIDTH=", key_len)) {
105  *dest = info->bandwidth;
106  *dest_len = sizeof(info->bandwidth);
107  }
108 }
109 
110 static int parse_playlist(URLContext *h, const char *url)
111 {
112  HLSContext *s = h->priv_data;
113  AVIOContext *in;
114  int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
115  char line[1024];
116  const char *ptr;
117 
118  if ((ret = avio_open2(&in, url, AVIO_FLAG_READ,
119  &h->interrupt_callback, NULL)) < 0)
120  return ret;
121 
122  read_chomp_line(in, line, sizeof(line));
123  if (strcmp(line, "#EXTM3U"))
124  return AVERROR_INVALIDDATA;
125 
127  s->finished = 0;
128  while (!url_feof(in)) {
129  read_chomp_line(in, line, sizeof(line));
130  if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
131  struct variant_info info = {{0}};
132  is_variant = 1;
134  &info);
135  bandwidth = atoi(info.bandwidth);
136  } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
137  s->target_duration = atoi(ptr);
138  } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
139  s->start_seq_no = atoi(ptr);
140  } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {
141  s->finished = 1;
142  } else if (av_strstart(line, "#EXTINF:", &ptr)) {
143  is_segment = 1;
144  duration = atoi(ptr);
145  } else if (av_strstart(line, "#", NULL)) {
146  continue;
147  } else if (line[0]) {
148  if (is_segment) {
149  struct segment *seg = av_malloc(sizeof(struct segment));
150  if (!seg) {
151  ret = AVERROR(ENOMEM);
152  goto fail;
153  }
154  seg->duration = duration;
155  ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);
156  dynarray_add(&s->segments, &s->n_segments, seg);
157  is_segment = 0;
158  } else if (is_variant) {
159  struct variant *var = av_malloc(sizeof(struct variant));
160  if (!var) {
161  ret = AVERROR(ENOMEM);
162  goto fail;
163  }
164  var->bandwidth = bandwidth;
165  ff_make_absolute_url(var->url, sizeof(var->url), url, line);
166  dynarray_add(&s->variants, &s->n_variants, var);
167  is_variant = 0;
168  }
169  }
170  }
171  s->last_load_time = av_gettime();
172 
173 fail:
174  avio_close(in);
175  return ret;
176 }
177 
178 static int hls_close(URLContext *h)
179 {
180  HLSContext *s = h->priv_data;
181 
184  ffurl_close(s->seg_hd);
185  return 0;
186 }
187 
188 static int hls_open(URLContext *h, const char *uri, int flags)
189 {
190  HLSContext *s = h->priv_data;
191  int ret, i;
192  const char *nested_url;
193 
194  if (flags & AVIO_FLAG_WRITE)
195  return AVERROR(ENOSYS);
196 
197  h->is_streamed = 1;
198 
199  if (av_strstart(uri, "hls+", &nested_url)) {
200  av_strlcpy(s->playlisturl, nested_url, sizeof(s->playlisturl));
201  } else if (av_strstart(uri, "hls://", &nested_url)) {
202  av_log(h, AV_LOG_ERROR,
203  "No nested protocol specified. Specify e.g. hls+http://%s\n",
204  nested_url);
205  ret = AVERROR(EINVAL);
206  goto fail;
207  } else {
208  av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri);
209  ret = AVERROR(EINVAL);
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",
217  s->playlisturl);
218 
219  if ((ret = parse_playlist(h, s->playlisturl)) < 0)
220  goto fail;
221 
222  if (s->n_segments == 0 && s->n_variants > 0) {
223  int max_bandwidth = 0, maxvar = -1;
224  for (i = 0; i < s->n_variants; i++) {
225  if (s->variants[i]->bandwidth > max_bandwidth || i == 0) {
226  max_bandwidth = s->variants[i]->bandwidth;
227  maxvar = i;
228  }
229  }
230  av_strlcpy(s->playlisturl, s->variants[maxvar]->url,
231  sizeof(s->playlisturl));
232  if ((ret = parse_playlist(h, s->playlisturl)) < 0)
233  goto fail;
234  }
235 
236  if (s->n_segments == 0) {
237  av_log(h, AV_LOG_WARNING, "Empty playlist\n");
238  ret = AVERROR(EIO);
239  goto fail;
240  }
241  s->cur_seq_no = s->start_seq_no;
242  if (!s->finished && s->n_segments >= 3)
243  s->cur_seq_no = s->start_seq_no + s->n_segments - 3;
244 
245  return 0;
246 
247 fail:
248  hls_close(h);
249  return ret;
250 }
251 
252 static int hls_read(URLContext *h, uint8_t *buf, int size)
253 {
254  HLSContext *s = h->priv_data;
255  const char *url;
256  int ret;
257  int64_t reload_interval;
258 
259 start:
260  if (s->seg_hd) {
261  ret = ffurl_read(s->seg_hd, buf, size);
262  if (ret > 0)
263  return ret;
264  }
265  if (s->seg_hd) {
266  ffurl_close(s->seg_hd);
267  s->seg_hd = NULL;
268  s->cur_seq_no++;
269  }
270  reload_interval = s->n_segments > 0 ?
271  s->segments[s->n_segments - 1]->duration :
272  s->target_duration;
273  reload_interval *= 1000000;
274 retry:
275  if (!s->finished) {
276  int64_t now = av_gettime();
277  if (now - s->last_load_time >= reload_interval) {
278  if ((ret = parse_playlist(h, s->playlisturl)) < 0)
279  return ret;
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. */
283  reload_interval = s->target_duration * 500000LL;
284  }
285  }
286  if (s->cur_seq_no < s->start_seq_no) {
288  "skipping %d segments ahead, expired from playlist\n",
289  s->start_seq_no - s->cur_seq_no);
290  s->cur_seq_no = s->start_seq_no;
291  }
292  if (s->cur_seq_no - s->start_seq_no >= s->n_segments) {
293  if (s->finished)
294  return AVERROR_EOF;
295  while (av_gettime() - s->last_load_time < reload_interval) {
297  return AVERROR_EXIT;
298  av_usleep(100*1000);
299  }
300  goto retry;
301  }
302  url = s->segments[s->cur_seq_no - s->start_seq_no]->url,
303  av_log(h, AV_LOG_DEBUG, "opening %s\n", url);
304  ret = ffurl_open(&s->seg_hd, url, AVIO_FLAG_READ,
305  &h->interrupt_callback, NULL);
306  if (ret < 0) {
308  return AVERROR_EXIT;
309  av_log(h, AV_LOG_WARNING, "Unable to open %s\n", url);
310  s->cur_seq_no++;
311  goto retry;
312  }
313  goto start;
314 }
315 
317  .name = "hls",
318  .url_open = hls_open,
319  .url_read = hls_read,
320  .url_close = hls_close,
322  .priv_data_size = sizeof(HLSContext),
323 };
Definition: start.py:1
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int bandwidth
Definition: hls.c:72
int is_streamed
true if streamed (no seek possible), default = false
Definition: url.h:48
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
AVIOInterruptCB interrupt_callback
Definition: url.h:50
#define AVIO_FLAG_READ
read-only
Definition: avio.h:332
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference visit they are quite exhaustive You do not need a special username or password All you need is to provide a ssh public key to the Git server admin What follows now is a basic introduction to Git and some FFmpeg specific guidelines Read it at least if you are granted commit privileges to the FFmpeg project you are expected to be familiar with these rules I if not You can get git from etc no matter how small Every one of them has been saved from looking like a fool by this many times It s very easy for stray debug output or cosmetic modifications to slip in
Definition: git-howto.txt:5
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:56
char url[MAX_URL_SIZE]
Definition: hls.c:60
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
#define MAX_URL_SIZE
uint8_t
int n_variants
Definition: hls.c:97
static uint64_t max_bandwidth
Definition: ffserver.c:322
#define AVERROR_EOF
End of file.
Definition: error.h:55
int target_duration
Definition: hlsproto.c:59
static void free_variant_list(HLSContext *s)
Definition: hlsproto.c:88
char playlisturl[MAX_URL_SIZE]
Definition: hlsproto.c:58
struct variant ** variants
Definition: hls.c:98
int n_segments
Definition: hlsproto.c:62
URLContext * seg_hd
Definition: hlsproto.c:67
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
struct HLSContext HLSContext
char bandwidth[20]
Definition: hls.c:173
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:821
static int parse_playlist(URLContext *h, const char *url)
Definition: hlsproto.c:110
#define URL_PROTOCOL_FLAG_NESTED_SCHEME
Definition: url.h:34
Definition: graph2dot.c:48
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.c:298
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:82
int size
Definition: hls.c:58
char url[MAX_URL_SIZE]
Definition: hls.c:73
MIPS optimizations info
Definition: mips.txt:2
#define dynarray_add(tab, nb_ptr, elem)
static void handle_variant_args(struct variant_info *info, const char *key, int key_len, char **dest, int *dest_len)
Definition: hlsproto.c:101
URLProtocol ff_hls_protocol
Definition: hlsproto.c:316
void(* ff_parse_key_val_cb)(void *context, const char *key, int key_len, char **dest, int *dest_len)
Callback function type for ff_parse_key_value.
static int hls_read(URLContext *h, uint8_t *buf, int size)
Definition: hlsproto.c:252
ret
Definition: avfilter.c:821
Definition: hls.c:96
int ff_get_line(AVIOContext *s, char *buf, int maxlen)
Read a whole line of text from AVIOContext.
Definition: aviobuf.c:618
Libavformat version macros.
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:56
int duration
Definition: hls.c:59
int url_feof(AVIOContext *s)
feof() equivalent for AVIOContext.
Definition: aviobuf.c:280
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
NULL
Definition: eval.c:55
dest
Definition: start.py:60
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrup a blocking function associated with cb.
Definition: avio.c:428
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
Definition: hlsproto.c:71
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
Definition: url.h:41
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
synthesis window for stochastic i
void * priv_data
Definition: url.h:44
int64_t last_load_time
Definition: hlsproto.c:68
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:804
char key[MAX_URL_SIZE]
Definition: hls.c:61
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
const char * name
Definition: url.h:55
static int flags
Definition: cpu.c:23
int ffurl_close(URLContext *h)
Definition: avio.c:359
void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf, void *context)
Parse a string with comma-separated key=value pairs.
int start_seq_no
Definition: hlsproto.c:60
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:33
Main libavformat public API header.
struct segment ** segments
Definition: hlsproto.c:63
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:247
int cur_seq_no
Definition: hls.c:99
static void free_segment_list(HLSContext *s)
Definition: hlsproto.c:79
int cur_seq_no
Definition: hls.c:89
int len
static int hls_open(URLContext *h, const char *uri, int flags)
Definition: hlsproto.c:188
static int hls_close(URLContext *h)
Definition: hlsproto.c:178
Definition: hls.c:71
void INT64 start
Definition: avisynth_c.h:594
unbuffered private I/O API
int finished
Definition: hlsproto.c:61
void ff_make_absolute_url(char *buf, int size, const char *base, const char *rel)
Convert a relative url into an absolute url, given a base url.
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...
Definition: avio.c:303