42 #define INITIAL_BUFFER_SIZE 32768
44 #define MAX_FIELD_LEN 64
45 #define MAX_CHARACTERISTICS_LEN 512
47 #define MPEG_TIME_BASE 90000
48 #define MPEG_TIME_BASE_Q (AVRational){1, MPEG_TIME_BASE}
287 const char *
url,
const char *base)
313 int key_len,
char **dest,
int *dest_len)
315 if (!strncmp(key,
"BANDWIDTH=", key_len)) {
318 }
else if (!strncmp(key,
"AUDIO=", key_len)) {
320 *dest_len =
sizeof(info->
audio);
321 }
else if (!strncmp(key,
"VIDEO=", key_len)) {
323 *dest_len =
sizeof(info->
video);
324 }
else if (!strncmp(key,
"SUBTITLES=", key_len)) {
337 int key_len,
char **dest,
int *dest_len)
339 if (!strncmp(key,
"METHOD=", key_len)) {
341 *dest_len =
sizeof(info->
method);
342 }
else if (!strncmp(key,
"URI=", key_len)) {
344 *dest_len =
sizeof(info->
uri);
345 }
else if (!strncmp(key,
"IV=", key_len)) {
347 *dest_len =
sizeof(info->
iv);
364 const char *url_base)
368 char *characteristic;
372 if (!strcmp(info->
type,
"AUDIO"))
374 else if (!strcmp(info->
type,
"VIDEO"))
376 else if (!strcmp(info->
type,
"SUBTITLES"))
378 else if (!strcmp(info->
type,
"CLOSED-CAPTIONS"))
414 int langlen = strlen(rend->
language);
415 if (langlen <
sizeof(rend->
language) - 3) {
418 sizeof(rend->
language) - langlen - 2);
424 if (!strcmp(info->
forced,
"YES"))
428 while ((characteristic =
av_strtok(chr_ptr,
",", &saveptr))) {
429 if (!strcmp(characteristic,
"public.accessibility.describes-music-and-sound"))
431 else if (!strcmp(characteristic,
"public.accessibility.describes-video"))
441 int key_len,
char **dest,
int *dest_len)
443 if (!strncmp(key,
"TYPE=", key_len)) {
445 *dest_len =
sizeof(info->
type);
446 }
else if (!strncmp(key,
"URI=", key_len)) {
448 *dest_len =
sizeof(info->
uri);
449 }
else if (!strncmp(key,
"GROUP-ID=", key_len)) {
452 }
else if (!strncmp(key,
"LANGUAGE=", key_len)) {
455 }
else if (!strncmp(key,
"ASSOC-LANGUAGE=", key_len)) {
458 }
else if (!strncmp(key,
"NAME=", key_len)) {
460 *dest_len =
sizeof(info->
name);
461 }
else if (!strncmp(key,
"DEFAULT=", key_len)) {
464 }
else if (!strncmp(key,
"FORCED=", key_len)) {
466 *dest_len =
sizeof(info->
forced);
467 }
else if (!strncmp(key,
"CHARACTERISTICS=", key_len)) {
497 int ret = 0, is_segment = 0, is_variant = 0;
506 int64_t seg_offset = 0;
507 int64_t seg_size = -1;
534 if (strcmp(line,
"#EXTM3U")) {
546 if (
av_strstart(line,
"#EXT-X-STREAM-INF:", &ptr)) {
548 memset(&variant_info, 0,
sizeof(variant_info));
551 }
else if (
av_strstart(line,
"#EXT-X-KEY:", &ptr)) {
557 if (!strcmp(info.
method,
"AES-128"))
559 if (!strncmp(info.
iv,
"0x", 2) || !strncmp(info.
iv,
"0X", 2)) {
564 }
else if (
av_strstart(line,
"#EXT-X-MEDIA:", &ptr)) {
569 }
else if (
av_strstart(line,
"#EXT-X-TARGETDURATION:", &ptr)) {
574 }
else if (
av_strstart(line,
"#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
579 }
else if (
av_strstart(line,
"#EXT-X-PLAYLIST-TYPE:", &ptr)) {
583 if (!strcmp(ptr,
"EVENT"))
585 else if (!strcmp(ptr,
"VOD"))
587 }
else if (
av_strstart(line,
"#EXT-X-ENDLIST", &ptr)) {
593 }
else if (
av_strstart(line,
"#EXT-X-BYTERANGE:", &ptr)) {
594 seg_size = atoi(ptr);
595 ptr = strchr(ptr,
'@');
597 seg_offset = atoi(ptr+1);
600 }
else if (line[0]) {
625 memcpy(seg->
iv, iv,
sizeof(iv));
628 memset(seg->
iv, 0,
sizeof(seg->
iv));
656 seg->
size = seg_size;
659 seg_offset += seg_size;
710 static const char id3_priv_owner_ts[] =
"com.apple.streaming.transportStreamTimestamp";
714 for (meta = *extra_meta; meta; meta = meta->
next) {
715 if (!strcmp(meta->
tag,
"PRIV")) {
717 if (priv->
datasize == 8 && !strcmp(priv->
owner, id3_priv_owner_ts)) {
721 if ((ts & ~((1ULL << 33) - 1)) == 0)
726 }
else if (!strcmp(meta->
tag,
"APIC") && apic)
740 if (!oldentry || strcmp(oldentry->
value, entry->
value) != 0)
768 parse_id3(pls->
ctx, pb, &metadata, ×tamp, &apic, &extra_meta);
804 int buf_size,
int *
len)
826 }
else if (*len <= 0) {
838 int64_t maxsize = seg->
size >= 0 ? seg->
size : 1024*1024;
840 int tag_got_bytes =
FFMIN(taglen, *len);
841 int remaining = taglen - tag_got_bytes;
843 if (taglen > maxsize) {
859 memcpy(pls->
id3_buf + id3_buf_pos, buf, tag_got_bytes);
860 id3_buf_pos += tag_got_bytes;
863 *len -= tag_got_bytes;
864 memmove(buf, buf + tag_got_bytes, *len);
871 id3_buf_pos += remaining;
882 if (*len >= 0 && (fill_buf || *len == 0)) {
919 if (seg->
size >= 0) {
923 char end_offset[24] = { 0 };
924 snprintf(offset,
sizeof(offset) - 1,
"%"PRId64,
926 snprintf(end_offset,
sizeof(end_offset) - 1,
"%"PRId64,
946 !=
sizeof(pls->
key)) {
959 iv[32] = key[32] =
'\0';
960 if (strstr(seg->
url,
"://"))
1012 int just_opened = 0;
1019 int64_t reload_interval;
1057 "skipping %d segments ahead, expired from playlists\n",
1103 int variant_count = 0;
1106 for (i = 0; i < c->
n_variants && variant_count < 2; i++) {
1117 return variant_count >= 2;
1128 if (rend->
type == type && !strcmp(rend->
group_id, group_id)) {
1159 if (rend->
type != type)
1177 int64_t timestamp,
int *seq_no)
1183 if (timestamp < pos) {
1243 int ret = 0, i, j, stream_offset = 0;
1247 c->first_packet = 1;
1256 if (
c->user_agent && !strlen(
c->user_agent))
1262 if (
c->cookies && !strlen(
c->cookies))
1268 if (
c->headers && !strlen(
c->headers))
1275 if (
c->n_variants == 0) {
1282 if (
c->n_playlists > 1 ||
c->playlists[0]->n_segments == 0) {
1283 for (i = 0; i <
c->n_playlists; i++) {
1290 if (
c->variants[0]->playlists[0]->n_segments == 0) {
1298 if (
c->variants[0]->playlists[0]->finished) {
1300 for (i = 0; i <
c->variants[0]->playlists[0]->n_segments; i++)
1301 duration +=
c->variants[0]->playlists[0]->segments[i]->duration;
1306 for (i = 0; i <
c->n_variants; i++) {
1307 struct variant *var =
c->variants[i];
1318 for (i = 0; i <
c->n_playlists; i++) {
1398 for (i = 0; i <
c->n_variants; i++) {
1400 char bitrate_str[20];
1510 int64_t ts_b,
struct playlist *pls_b)
1521 int ret, i, minplaylist = -1;
1579 struct playlist *minpls = minplaylist < 0 ?
1581 if (minplaylist < 0) {
1584 int64_t dts = pls->
pkt.
dts;
1585 int64_t mindts = minpls->
pkt.
dts;
1595 if (minplaylist >= 0) {
1622 int64_t timestamp,
int flags)
1644 if (0 < duration && duration < seek_timestamp - first_timestamp)
1685 if (pls != seek_pls) {
1705 if (strncmp(p->
buf,
"#EXTM3U", 7))
1707 if (strstr(p->
buf,
"#EXT-X-STREAM-INF:") ||
1708 strstr(p->
buf,
"#EXT-X-TARGETDURATION:") ||
1709 strstr(p->
buf,
"#EXT-X-MEDIA-SEQUENCE:"))
1715 .
name =
"hls,applehttp",