* commit '0c73a5a53cc97f4291bbe9e1e68226edf6161744': hls: Save and forward avio options Conflicts: libavformat/hls.c
Unified · Split
| @@ -182,6 +182,7 @@ typedef struct HLSContext { · 181 unmodified lines | |||
| 182 | char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context | 182 | char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context |
| 183 | char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context | 183 | char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context |
| 184 | char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context | 184 | char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context |
| 185 | AVDictionary *avio_opts; | ||
| 185 | } HLSContext; | 186 | } HLSContext; |
| 186 | 187 | ||
| 187 | static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) | 188 | static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) |
| @@ -494,6 +495,53 @@ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url · 306 unmodified lines | |||
| 494 | 495 | ||
| 495 | /* pls = NULL => Master Playlist or parentless Media Playlist | 496 | /* pls = NULL => Master Playlist or parentless Media Playlist |
| 496 | * pls = !NULL => parented Media Playlist, playlist+variant allocated */ | 497 | * pls = !NULL => parented Media Playlist, playlist+variant allocated */ |
| 498 | static int open_in(HLSContext *c, AVIOContext **in, const char *url) | ||
| 499 | { | ||
| 500 | AVDictionary *tmp = NULL; | ||
| 501 | int ret; | ||
| 502 | |||
| 503 | av_dict_copy(&tmp, c->avio_opts, 0); | ||
| 504 | |||
| 505 | ret = avio_open2(in, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); | ||
| 506 | |||
| 507 | av_dict_free(&tmp); | ||
| 508 | return ret; | ||
| 509 | } | ||
| 510 | |||
| 511 | static int url_connect(struct playlist *pls, AVDictionary *opts, AVDictionary *opts2) | ||
| 512 | { | ||
| 513 | AVDictionary *tmp = NULL; | ||
| 514 | int ret; | ||
| 515 | |||
| 516 | av_dict_copy(&tmp, opts, 0); | ||
| 517 | av_dict_copy(&tmp, opts2, 0); | ||
| 518 | |||
| 519 | av_opt_set_dict(pls->input, &tmp); | ||
| 520 | |||
| 521 | if ((ret = ffurl_connect(pls->input, NULL)) < 0) { | ||
| 522 | ffurl_close(pls->input); | ||
| 523 | pls->input = NULL; | ||
| 524 | } | ||
| 525 | |||
| 526 | av_dict_free(&tmp); | ||
| 527 | return ret; | ||
| 528 | } | ||
| 529 | |||
| 530 | static int open_url(HLSContext *c, URLContext **uc, const char *url, AVDictionary *opts) | ||
| 531 | { | ||
| 532 | AVDictionary *tmp = NULL; | ||
| 533 | int ret; | ||
| 534 | |||
| 535 | av_dict_copy(&tmp, c->avio_opts, 0); | ||
| 536 | av_dict_copy(&tmp, opts, 0); | ||
| 537 | |||
| 538 | ret = ffurl_open(uc, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); | ||
| 539 | |||
| 540 | av_dict_free(&tmp); | ||
| 541 | |||
| 542 | return ret; | ||
| 543 | } | ||
| 544 | |||
| 497 | static int parse_playlist(HLSContext *c, const char *url, | 545 | static int parse_playlist(HLSContext *c, const char *url, |
| 498 | struct playlist *pls, AVIOContext *in) | 546 | struct playlist *pls, AVIOContext *in) |
| 499 | { | 547 | { |
| @@ -513,6 +561,7 @@ static int parse_playlist(HLSContext *c, const char *url, · 13 unmodified lines | |||
| 513 | char tmp_str[MAX_URL_SIZE]; | 561 | char tmp_str[MAX_URL_SIZE]; |
| 514 | 562 | ||
| 515 | if (!in) { | 563 | if (!in) { |
| 564 | #if 1 | ||
| 516 | AVDictionary *opts = NULL; | 565 | AVDictionary *opts = NULL; |
| 517 | close_in = 1; | 566 | close_in = 1; |
| 518 | /* Some HLS servers don't like being sent the range header */ | 567 | /* Some HLS servers don't like being sent the range header */ |
| @@ -528,6 +577,12 @@ static int parse_playlist(HLSContext *c, const char *url, · 9 unmodified lines | |||
| 528 | av_dict_free(&opts); | 577 | av_dict_free(&opts); |
| 529 | if (ret < 0) | 578 | if (ret < 0) |
| 530 | return ret; | 579 | return ret; |
| 580 | #else | ||
| 581 | ret = open_in(c, &in, url); | ||
| 582 | if (ret < 0) | ||
| 583 | return ret; | ||
| 584 | close_in = 1; | ||
| 585 | #endif | ||
| 531 | } | 586 | } |
| 532 | 587 | ||
| 533 | if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) | 588 | if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) |
| @@ -940,15 +995,13 @@ static int open_input(HLSContext *c, struct playlist *pls) · 406 unmodified lines | |||
| 940 | seg->url, seg->url_offset, pls->index); | 995 | seg->url, seg->url_offset, pls->index); |
| 941 | 996 | ||
| 942 | if (seg->key_type == KEY_NONE) { | 997 | if (seg->key_type == KEY_NONE) { |
| 943 | ret = ffurl_open(&pls->input, seg->url, AVIO_FLAG_READ, | 998 | ret = open_url(pls->parent->priv_data, &pls->input, seg->url, opts); |
| 944 | &pls->parent->interrupt_callback, &opts); | ||
| 945 | |||
| 946 | } else if (seg->key_type == KEY_AES_128) { | 999 | } else if (seg->key_type == KEY_AES_128) { |
| 1000 | // HLSContext *c = var->parent->priv_data; | ||
| 947 | char iv[33], key[33], url[MAX_URL_SIZE]; | 1001 | char iv[33], key[33], url[MAX_URL_SIZE]; |
| 948 | if (strcmp(seg->key, pls->key_url)) { | 1002 | if (strcmp(seg->key, pls->key_url)) { |
| 949 | URLContext *uc; | 1003 | URLContext *uc; |
| 950 | if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ, | 1004 | if (open_url(pls->parent->priv_data, &uc, seg->key, opts2) == 0) { |
| 951 | &pls->parent->interrupt_callback, &opts2) == 0) { | ||
| 952 | if (ffurl_read_complete(uc, pls->key, sizeof(pls->key)) | 1005 | if (ffurl_read_complete(uc, pls->key, sizeof(pls->key)) |
| 953 | != sizeof(pls->key)) { | 1006 | != sizeof(pls->key)) { |
| 954 | av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", | 1007 | av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", |
| @@ -970,15 +1023,14 @@ static int open_input(HLSContext *c, struct playlist *pls) · 15 unmodified lines | |||
| 970 | snprintf(url, sizeof(url), "crypto+%s", seg->url); | 1023 | snprintf(url, sizeof(url), "crypto+%s", seg->url); |
| 971 | else | 1024 | else |
| 972 | snprintf(url, sizeof(url), "crypto:%s", seg->url); | 1025 | snprintf(url, sizeof(url), "crypto:%s", seg->url); |
| 1026 | |||
| 973 | if ((ret = ffurl_alloc(&pls->input, url, AVIO_FLAG_READ, | 1027 | if ((ret = ffurl_alloc(&pls->input, url, AVIO_FLAG_READ, |
| 974 | &pls->parent->interrupt_callback)) < 0) | 1028 | &pls->parent->interrupt_callback)) < 0) |
| 975 | goto cleanup; | 1029 | goto cleanup; |
| 976 | av_opt_set(pls->input->priv_data, "key", key, 0); | 1030 | av_opt_set(pls->input->priv_data, "key", key, 0); |
| 977 | av_opt_set(pls->input->priv_data, "iv", iv, 0); | 1031 | av_opt_set(pls->input->priv_data, "iv", iv, 0); |
| 978 | 1032 | ||
| 979 | if ((ret = ffurl_connect(pls->input, &opts)) < 0) { | 1033 | if ((ret = url_connect(pls, c->avio_opts, opts)) < 0) { |
| 980 | ffurl_close(pls->input); | ||
| 981 | pls->input = NULL; | ||
| 982 | goto cleanup; | 1034 | goto cleanup; |
| 983 | } | 1035 | } |
| 984 | ret = 0; | 1036 | ret = 0; |
| @@ -1254,6 +1306,26 @@ static int select_cur_seq_no(HLSContext *c, struct playlist *pls) · 269 unmodified lines | |||
| 1254 | return pls->start_seq_no; | 1306 | return pls->start_seq_no; |
| 1255 | } | 1307 | } |
| 1256 | 1308 | ||
| 1309 | static int save_avio_options(AVFormatContext *s) | ||
| 1310 | { | ||
| 1311 | HLSContext *c = s->priv_data; | ||
| 1312 | const char *opts[] = { "headers", "user_agent", "user-agent", "cookies", NULL }, **opt = opts; | ||
| 1313 | uint8_t *buf; | ||
| 1314 | int ret = 0; | ||
| 1315 | |||
| 1316 | while (*opt) { | ||
| 1317 | if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { | ||
| 1318 | ret = av_dict_set(&c->avio_opts, *opt, buf, | ||
| 1319 | AV_DICT_DONT_STRDUP_VAL); | ||
| 1320 | if (ret < 0) | ||
| 1321 | return ret; | ||
| 1322 | } | ||
| 1323 | opt++; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | return ret; | ||
| 1327 | } | ||
| 1328 | |||
| 1257 | static int hls_read_header(AVFormatContext *s) | 1329 | static int hls_read_header(AVFormatContext *s) |
| 1258 | { | 1330 | { |
| 1259 | URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; | 1331 | URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; |
| @@ -1281,6 +1353,12 @@ static int hls_read_header(AVFormatContext *s) · 21 unmodified lines | |||
| 1281 | if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) | 1353 | if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) |
| 1282 | goto fail; | 1354 | goto fail; |
| 1283 | 1355 | ||
| 1356 | if ((ret = save_avio_options(s)) < 0) | ||
| 1357 | goto fail; | ||
| 1358 | |||
| 1359 | /* Some HLS servers don't like being sent the range header */ | ||
| 1360 | av_dict_set(&c->avio_opts, "seekable", "0", 0); | ||
| 1361 | |||
| 1284 | if (c->n_variants == 0) { | 1362 | if (c->n_variants == 0) { |
| 1285 | av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); | 1363 | av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); |
| 1286 | ret = AVERROR_EOF; | 1364 | ret = AVERROR_EOF; |
| @@ -1631,6 +1709,9 @@ static int hls_close(AVFormatContext *s) · 344 unmodified lines | |||
| 1631 | free_playlist_list(c); | 1709 | free_playlist_list(c); |
| 1632 | free_variant_list(c); | 1710 | free_variant_list(c); |
| 1633 | free_rendition_list(c); | 1711 | free_rendition_list(c); |
| 1712 | |||
| 1713 | av_dict_free(&c->avio_opts); | ||
| 1714 | |||
| 1634 | return 0; | 1715 | return 0; |
| 1635 | } | 1716 | } |
| 1636 | 1717 | ||