From 4392febd0285859e7340f924d33b6ad693d3b9ea Mon Sep 17 00:00:00 2001 From: Markham Date: Sun, 4 Nov 2018 16:58:30 +0100 Subject: [PATCH] armbox: bump version ffmpeg-4.0.3 --- ...fmpeg-3.4.2-chunked_transfer_fix_eof.patch | 16 - .../ffmpeg-3.4.2-dashdec_improvements.patch | 1565 ----------------- .../ffmpeg/ffmpeg-3.4.2-fix-dash-build.patch | 11 - .../ffmpeg/ffmpeg-3.4.2-fix_mpegts.patch | 16 - ...llow_to_choose_rtmp_impl_at_runtime.patch} | 74 +- ... ffmpeg-4.0.3-fix_edit_list_parsing.patch} | 2 +- ...x-hls.patch => ffmpeg-4.0.3-fix_hls.patch} | 6 +- .../ffmpeg/ffmpeg-4.0.3-fix_mpegts.patch | 15 + ...=> ffmpeg-4.0.3-hls_replace_key_uri.patch} | 36 +- ...> ffmpeg-4.0.3-increase_buffer_size.patch} | 40 +- ....patch => ffmpeg-4.0.3-optimize_aac.patch} | 2 +- make/ffmpeg.mk | 23 +- make/versions.mk | 2 +- 13 files changed, 119 insertions(+), 1689 deletions(-) delete mode 100644 archive-patches/ffmpeg/ffmpeg-3.4.2-chunked_transfer_fix_eof.patch delete mode 100644 archive-patches/ffmpeg/ffmpeg-3.4.2-dashdec_improvements.patch delete mode 100644 archive-patches/ffmpeg/ffmpeg-3.4.2-fix-dash-build.patch delete mode 100644 archive-patches/ffmpeg/ffmpeg-3.4.2-fix_mpegts.patch rename archive-patches/ffmpeg/{ffmpeg-3.4.2-allow_to_choose_rtmp_impl_at_runtime.patch => ffmpeg-4.0.3-allow_to_choose_rtmp_impl_at_runtime.patch} (60%) rename archive-patches/ffmpeg/{ffmpeg-3.4.2-fix-edit-list-parsing.patch => ffmpeg-4.0.3-fix_edit_list_parsing.patch} (97%) rename archive-patches/ffmpeg/{ffmpeg-3.4.2-fix-hls.patch => ffmpeg-4.0.3-fix_hls.patch} (70%) create mode 100644 archive-patches/ffmpeg/ffmpeg-4.0.3-fix_mpegts.patch rename archive-patches/ffmpeg/{ffmpeg-3.4.2-hls_replace_key_uri.patch => ffmpeg-4.0.3-hls_replace_key_uri.patch} (63%) rename archive-patches/ffmpeg/{ffmpeg-3.4.2-buffer-size.patch => ffmpeg-4.0.3-increase_buffer_size.patch} (69%) rename archive-patches/ffmpeg/{ffmpeg-3.4.2-aac.patch => ffmpeg-4.0.3-optimize_aac.patch} (98%) diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-chunked_transfer_fix_eof.patch b/archive-patches/ffmpeg/ffmpeg-3.4.2-chunked_transfer_fix_eof.patch deleted file mode 100644 index 99ac875..0000000 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-chunked_transfer_fix_eof.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -uNr ffmpeg-3.4.2/libavformat/http.c ffmpeg-3.4.2_chunked_transfer_fix_eof/libavformat/http.c ---- ffmpeg-3.4.2/libavformat/http.c 2018-02-12 01:29:06.000000000 +0100 -+++ ffmpeg-3.4.2_chunked_transfer_fix_eof/libavformat/http.c 2018-02-14 19:56:02.371892777 +0100 -@@ -1296,8 +1296,11 @@ - "Chunked encoding data size: %"PRIu64"'\n", - s->chunksize); - -- if (!s->chunksize) -+ if (!s->chunksize) { -+ /* we need to remember endof*/ -+ s->chunksize = UINT64_MAX; - return 0; -+ } - else if (s->chunksize == UINT64_MAX) { - av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n", - s->chunksize); diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-dashdec_improvements.patch b/archive-patches/ffmpeg/ffmpeg-3.4.2-dashdec_improvements.patch deleted file mode 100644 index 42dbf1a..0000000 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-dashdec_improvements.patch +++ /dev/null @@ -1,1565 +0,0 @@ -diff -uNr ffmpeg-3.4.2/libavformat/dashdec.c ffmpeg-3.4.2_dashdec/libavformat/dashdec.c ---- ffmpeg-3.4.2/libavformat/dashdec.c 2018-02-12 01:29:06.000000000 +0100 -+++ ffmpeg-3.4.2_dashdec/libavformat/dashdec.c 2018-02-15 19:43:08.889757019 +0100 -@@ -39,7 +39,7 @@ - /* - * reference to : ISO_IEC_23009-1-DASH-2012 - * Section: 5.3.9.6.2 -- * Table: Table 17 — Semantics of SegmentTimeline element -+ * Table: Table 17 — Semantics of SegmentTimeline element - * */ - struct timeline { - /* starttime: Element or Attribute Name -@@ -80,10 +80,13 @@ - AVFormatContext *ctx; - AVPacket pkt; - int rep_idx; -- int rep_count; - int stream_index; - - enum AVMediaType type; -+ char id[20]; -+ int bandwidth; -+ AVRational framerate; -+ AVStream *assoc_stream; /* demuxer stream associated with this representation */ - - int n_fragments; - struct fragment **fragments; /* VOD list of fragment for profile */ -@@ -113,13 +116,32 @@ - uint32_t init_sec_buf_read_offset; - int64_t cur_timestamp; - int is_restart_needed; -+ -+ /* used for live stream were each fragment starts with -+ * 0 pts, so we need to -+ */ -+ int64_t pkt_start_time_offset; -+ int is_first_pkt; - }; - - typedef struct DASHContext { - const AVClass *class; - char *base_url; -- struct representation *cur_video; -- struct representation *cur_audio; -+ -+ int n_videos; -+ struct representation **videos; -+ int n_audios; -+ struct representation **audios; -+ -+ /* Temporary variables used during manifest parsing */ -+ int tmp_video_rep_idx; -+ int tmp_audio_rep_idx; -+ -+ /* Used to force using selected representation */ -+ int video_rep_index; -+ int audio_rep_index; -+ -+ int64_t last_load_time; - - /* MediaPresentationDescription Attribute */ - uint64_t media_presentation_duration; -@@ -141,8 +163,34 @@ - char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context - char *allowed_extensions; - AVDictionary *avio_opts; -+ int max_url_size; - } DASHContext; - -+static int sleep_ms(DASHContext *c, uint32_t time_ms) -+{ -+ int ret = 0; -+ int64_t start_time = av_gettime_relative(); -+ do { -+ if (ff_check_interrupt(c->interrupt_callback)) { -+ ret = 1; -+ break; -+ } -+ av_usleep(100*1000); -+ } while (av_gettime_relative() - start_time < (time_ms*1000)); -+ return ret; -+} -+ -+static int ishttp(char *url) -+{ -+ const char *proto_name = avio_find_protocol_name(url); -+ return av_strstart(proto_name, "http", NULL); -+} -+ -+static int aligned(int val) -+{ -+ return ((val + 0x3F) >> 6) << 6; -+} -+ - static uint64_t get_current_time_in_sec(void) - { - return av_gettime() / 1000000; -@@ -328,17 +376,39 @@ - } - - av_freep(&pls->url_template); -- av_freep(pls); -+ av_freep(&pls); -+} -+ -+static void free_video_list(DASHContext *c) -+{ -+ int i; -+ for (i = 0; i < c->n_videos; i++) { -+ struct representation *pls = c->videos[i]; -+ free_representation(pls); -+ } -+ av_freep(&c->videos); -+ c->n_videos = 0; - } - --static void set_httpheader_options(DASHContext *c, AVDictionary *opts) -+static void free_audio_list(DASHContext *c) -+{ -+ int i; -+ for (i = 0; i < c->n_audios; i++) { -+ struct representation *pls = c->audios[i]; -+ free_representation(pls); -+ } -+ av_freep(&c->audios); -+ c->n_audios = 0; -+} -+ -+static void set_httpheader_options(DASHContext *c, AVDictionary **opts) - { - // broker prior HTTP options that should be consistent across requests -- av_dict_set(&opts, "user-agent", c->user_agent, 0); -- av_dict_set(&opts, "cookies", c->cookies, 0); -- av_dict_set(&opts, "headers", c->headers, 0); -+ av_dict_set(opts, "user-agent", c->user_agent, 0); -+ av_dict_set(opts, "cookies", c->cookies, 0); -+ av_dict_set(opts, "headers", c->headers, 0); - if (c->is_live) { -- av_dict_set(&opts, "seekable", "0", 0); -+ av_dict_set(opts, "seekable", "0", 0); - } - } - static void update_options(char **dest, const char *name, void *src) -@@ -392,7 +462,8 @@ - else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5)) - return AVERROR_INVALIDDATA; - -- ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); -+ av_freep(pb); -+ ret = avio_open2(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); - if (ret >= 0) { - // update cookies on http response with setcookies. - char *new_cookies = NULL; -@@ -418,6 +489,7 @@ - - static char *get_content_url(xmlNodePtr *baseurl_nodes, - int n_baseurl_nodes, -+ int max_url_size, - char *rep_id_val, - char *rep_bandwidth_val, - char *val) -@@ -425,10 +497,12 @@ - int i; - char *text; - char *url = NULL; -- char tmp_str[MAX_URL_SIZE]; -- char tmp_str_2[MAX_URL_SIZE]; -+ char *tmp_str = av_mallocz(max_url_size); -+ char *tmp_str_2 = av_mallocz(max_url_size); - -- memset(tmp_str, 0, sizeof(tmp_str)); -+ if (!tmp_str || !tmp_str_2) { -+ return NULL; -+ } - - for (i = 0; i < n_baseurl_nodes; ++i) { - if (baseurl_nodes[i] && -@@ -436,32 +510,36 @@ - baseurl_nodes[i]->children->type == XML_TEXT_NODE) { - text = xmlNodeGetContent(baseurl_nodes[i]->children); - if (text) { -- memset(tmp_str, 0, sizeof(tmp_str)); -- memset(tmp_str_2, 0, sizeof(tmp_str_2)); -- ff_make_absolute_url(tmp_str_2, MAX_URL_SIZE, tmp_str, text); -- av_strlcpy(tmp_str, tmp_str_2, sizeof(tmp_str)); -+ memset(tmp_str, 0, max_url_size); -+ memset(tmp_str_2, 0, max_url_size); -+ ff_make_absolute_url(tmp_str_2, max_url_size, tmp_str, text); -+ av_strlcpy(tmp_str, tmp_str_2, max_url_size); - xmlFree(text); - } - } - } - - if (val) -- av_strlcat(tmp_str, (const char*)val, sizeof(tmp_str)); -+ av_strlcat(tmp_str, (const char*)val, max_url_size); - - if (rep_id_val) { - url = av_strireplace(tmp_str, "$RepresentationID$", (const char*)rep_id_val); - if (!url) { -- return NULL; -+ goto end; - } -- av_strlcpy(tmp_str, url, sizeof(tmp_str)); -- av_free(url); -+ av_strlcpy(tmp_str, url, max_url_size); - } - if (rep_bandwidth_val && tmp_str[0] != '\0') { -+ // free any previously assigned url before reassigning -+ av_free(url); - url = av_strireplace(tmp_str, "$Bandwidth$", (const char*)rep_bandwidth_val); - if (!url) { -- return NULL; -+ goto end; - } - } -+end: -+ av_free(tmp_str); -+ av_free(tmp_str_2); - return url; - } - -@@ -522,55 +600,85 @@ - return type; - } - -+static struct fragment * get_Fragment(char *range) -+{ -+ struct fragment * seg = av_mallocz(sizeof(struct fragment)); -+ -+ if (!seg) -+ return NULL; -+ -+ seg->size = -1; -+ if (range) { -+ char *str_end_offset; -+ char *str_offset = av_strtok(range, "-", &str_end_offset); -+ seg->url_offset = strtoll(str_offset, NULL, 10); -+ seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset; -+ } -+ -+ return seg; -+} -+ - static int parse_manifest_segmenturlnode(AVFormatContext *s, struct representation *rep, - xmlNodePtr fragmenturl_node, - xmlNodePtr *baseurl_nodes, - char *rep_id_val, - char *rep_bandwidth_val) - { -+ DASHContext *c = s->priv_data; - char *initialization_val = NULL; - char *media_val = NULL; -+ char *range_val = NULL; -+ int max_url_size = c ? c->max_url_size: MAX_URL_SIZE; - - if (!av_strcasecmp(fragmenturl_node->name, (const char *)"Initialization")) { - initialization_val = xmlGetProp(fragmenturl_node, "sourceURL"); -- if (initialization_val) { -- rep->init_section = av_mallocz(sizeof(struct fragment)); -+ range_val = xmlGetProp(fragmenturl_node, "range"); -+ if (initialization_val || range_val) { -+ rep->init_section = get_Fragment(range_val); - if (!rep->init_section) { - xmlFree(initialization_val); -+ xmlFree(range_val); - return AVERROR(ENOMEM); - } - rep->init_section->url = get_content_url(baseurl_nodes, 4, -+ max_url_size, - rep_id_val, - rep_bandwidth_val, - initialization_val); -+ - if (!rep->init_section->url) { - av_free(rep->init_section); - xmlFree(initialization_val); -+ xmlFree(range_val); - return AVERROR(ENOMEM); - } -- rep->init_section->size = -1; - xmlFree(initialization_val); -+ xmlFree(range_val); - } - } else if (!av_strcasecmp(fragmenturl_node->name, (const char *)"SegmentURL")) { - media_val = xmlGetProp(fragmenturl_node, "media"); -- if (media_val) { -- struct fragment *seg = av_mallocz(sizeof(struct fragment)); -+ range_val = xmlGetProp(fragmenturl_node, "mediaRange"); -+ if (media_val || range_val) { -+ struct fragment *seg = get_Fragment(range_val); - if (!seg) { - xmlFree(media_val); -+ xmlFree(range_val); - return AVERROR(ENOMEM); - } - seg->url = get_content_url(baseurl_nodes, 4, -+ max_url_size, - rep_id_val, - rep_bandwidth_val, - media_val); - if (!seg->url) { - av_free(seg); - xmlFree(media_val); -+ xmlFree(range_val); - return AVERROR(ENOMEM); - } -- seg->size = -1; - dynarray_add(&rep->fragments, &rep->n_fragments, seg); - xmlFree(media_val); -+ xmlFree(range_val); - } - } - -@@ -613,26 +721,155 @@ - return 0; - } - -+static int fill_timelines(AVFormatContext *s, struct representation *rep, xmlNodePtr *nodes, const int n_nodes) -+{ -+ xmlNodePtr fragment_timeline_node; -+ int ret = 0; -+ int i = 0; -+ for (; i < n_nodes; ++i) { -+ if (nodes[i]) { -+ -+ fragment_timeline_node = find_child_node_by_name(nodes[i], "SegmentTimeline"); -+ if (fragment_timeline_node) { -+ fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); -+ while (fragment_timeline_node) { -+ ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node); -+ if (ret < 0) { -+ return ret; -+ } -+ fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node); -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes) { -+ -+ char *tmp_str = NULL; -+ char *path = NULL; -+ char *mpdName = NULL; -+ xmlNodePtr node = NULL; -+ char *baseurl = NULL; -+ char *root_url = NULL; -+ char *text = NULL; -+ -+ int isRootHttp = 0; -+ char token ='/'; -+ int start = 0; -+ int rootId = 0; -+ int updated = 0; -+ int size = 0; -+ int i; -+ int tmp_max_url_size = strlen(url); -+ -+ for (i = n_baseurl_nodes-1; i >= 0 ; i--) { -+ text = xmlNodeGetContent(baseurl_nodes[i]); -+ if (!text) -+ continue; -+ tmp_max_url_size += strlen(text); -+ if (ishttp(text)) { -+ xmlFree(text); -+ break; -+ } -+ xmlFree(text); -+ } -+ -+ tmp_max_url_size = aligned(tmp_max_url_size); -+ text = av_mallocz(tmp_max_url_size); -+ if (!text) { -+ updated = AVERROR(ENOMEM); -+ goto end; -+ } -+ av_strlcpy(text, url, strlen(url)+1); -+ while (mpdName = av_strtok(text, "/", &text)) { -+ size = strlen(mpdName); -+ } -+ -+ path = av_mallocz(tmp_max_url_size); -+ tmp_str = av_mallocz(tmp_max_url_size); -+ if (!tmp_str || !path) { -+ updated = AVERROR(ENOMEM); -+ goto end; -+ } -+ -+ av_strlcpy (path, url, strlen(url) - size + 1); -+ for (rootId = n_baseurl_nodes - 1; rootId > 0; rootId --) { -+ if (!(node = baseurl_nodes[rootId])) { -+ continue; -+ } -+ if (ishttp(xmlNodeGetContent(node))) { -+ break; -+ } -+ } -+ -+ node = baseurl_nodes[rootId]; -+ baseurl = xmlNodeGetContent(node); -+ root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path; -+ if (node) { -+ xmlNodeSetContent(node, root_url); -+ updated = 1; -+ } -+ -+ size = strlen(root_url); -+ isRootHttp = ishttp(root_url); -+ -+ if (root_url[size - 1] != token) { -+ av_strlcat(root_url, "/", size + 2); -+ size += 2; -+ } -+ -+ for (i = 0; i < n_baseurl_nodes; ++i) { -+ if (i == rootId) { -+ continue; -+ } -+ text = xmlNodeGetContent(baseurl_nodes[i]); -+ if (text) { -+ memset(tmp_str, 0, strlen(tmp_str)); -+ if (!ishttp(text) && isRootHttp) { -+ av_strlcpy(tmp_str, root_url, size + 1); -+ } -+ start = (text[0] == token); -+ av_strlcat(tmp_str, text + start, tmp_max_url_size); -+ xmlNodeSetContent(baseurl_nodes[i], tmp_str); -+ updated = 1; -+ xmlFree(text); -+ } -+ } -+ -+end: -+ if (tmp_max_url_size > *max_url_size) { -+ *max_url_size = tmp_max_url_size; -+ } -+ av_free(path); -+ av_free(tmp_str); -+ return updated; -+ -+} -+ - static int parse_manifest_representation(AVFormatContext *s, const char *url, - xmlNodePtr node, - xmlNodePtr adaptionset_node, - xmlNodePtr mpd_baseurl_node, - xmlNodePtr period_baseurl_node, -+ xmlNodePtr period_segmenttemplate_node, -+ xmlNodePtr period_segmentlist_node, - xmlNodePtr fragment_template_node, - xmlNodePtr content_component_node, -- xmlNodePtr adaptionset_baseurl_node) -+ xmlNodePtr adaptionset_baseurl_node, -+ xmlNodePtr adaptionset_segmentlist_node) - { - int32_t ret = 0; -- int32_t audio_rep_idx = 0; -- int32_t video_rep_idx = 0; - DASHContext *c = s->priv_data; - struct representation *rep = NULL; - struct fragment *seg = NULL; - xmlNodePtr representation_segmenttemplate_node = NULL; - xmlNodePtr representation_baseurl_node = NULL; - xmlNodePtr representation_segmentlist_node = NULL; -- xmlNodePtr fragment_timeline_node = NULL; -- xmlNodePtr fragment_templates_tab[2]; -+ xmlNodePtr segmentlists_tab[3]; -+ xmlNodePtr fragment_templates_tab[5]; - char *duration_val = NULL; - char *presentation_timeoffset_val = NULL; - char *startnumber_val = NULL; -@@ -643,6 +880,7 @@ - xmlNodePtr representation_node = node; - char *rep_id_val = xmlGetProp(representation_node, "id"); - char *rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth"); -+ char *rep_framerate_val = xmlGetProp(representation_node, "frameRate"); - enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; - - // try get information from representation -@@ -656,7 +894,7 @@ - type = get_content_type(adaptionset_node); - if (type == AVMEDIA_TYPE_UNKNOWN) { - av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skipp not supported representation type\n", url); -- } else if ((type == AVMEDIA_TYPE_VIDEO && !c->cur_video) || (type == AVMEDIA_TYPE_AUDIO && !c->cur_audio)) { -+ } else if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { - // convert selected representation to our internal struct - rep = av_mallocz(sizeof(struct representation)); - if (!rep) { -@@ -672,17 +910,24 @@ - baseurl_nodes[2] = adaptionset_baseurl_node; - baseurl_nodes[3] = representation_baseurl_node; - -- if (representation_segmenttemplate_node || fragment_template_node) { -- fragment_timeline_node = NULL; -+ ret = resolve_content_path(s, url, &c->max_url_size, baseurl_nodes, 4); -+ c->max_url_size = aligned(c->max_url_size + strlen(rep_id_val) + strlen(rep_bandwidth_val)); -+ if (ret == AVERROR(ENOMEM) || ret == 0) { -+ goto end; -+ } -+ if (representation_segmenttemplate_node || fragment_template_node || period_segmenttemplate_node) { - fragment_templates_tab[0] = representation_segmenttemplate_node; -- fragment_templates_tab[1] = fragment_template_node; -- -- presentation_timeoffset_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "presentationTimeOffset"); -- duration_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "duration"); -- startnumber_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "startNumber"); -- timescale_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "timescale"); -- initialization_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "initialization"); -- media_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "media"); -+ fragment_templates_tab[1] = adaptionset_segmentlist_node; -+ fragment_templates_tab[2] = fragment_template_node; -+ fragment_templates_tab[3] = period_segmenttemplate_node; -+ fragment_templates_tab[4] = period_segmentlist_node; -+ -+ presentation_timeoffset_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "presentationTimeOffset"); -+ duration_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "duration"); -+ startnumber_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "startNumber"); -+ timescale_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "timescale"); -+ initialization_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "initialization"); -+ media_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "media"); - - if (initialization_val) { - rep->init_section = av_mallocz(sizeof(struct fragment)); -@@ -691,7 +936,8 @@ - ret = AVERROR(ENOMEM); - goto end; - } -- rep->init_section->url = get_content_url(baseurl_nodes, 4, rep_id_val, rep_bandwidth_val, initialization_val); -+ c->max_url_size = aligned(c->max_url_size + strlen(initialization_val)); -+ rep->init_section->url = get_content_url(baseurl_nodes, 4, c->max_url_size, rep_id_val, rep_bandwidth_val, initialization_val); - if (!rep->init_section->url) { - av_free(rep->init_section); - av_free(rep); -@@ -703,7 +949,8 @@ - } - - if (media_val) { -- rep->url_template = get_content_url(baseurl_nodes, 4, rep_id_val, rep_bandwidth_val, media_val); -+ c->max_url_size = aligned(c->max_url_size + strlen(media_val)); -+ rep->url_template = get_content_url(baseurl_nodes, 4, c->max_url_size, rep_id_val, rep_bandwidth_val, media_val); - xmlFree(media_val); - } - -@@ -719,32 +966,27 @@ - rep->fragment_timescale = (int64_t) strtoll(timescale_val, NULL, 10); - xmlFree(timescale_val); - } -+ -+ ret = fill_timelines(s, rep, fragment_templates_tab, 5); -+ if (ret < 0) { -+ return ret; -+ } -+ - if (startnumber_val) { -- rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); -+ if (rep->n_timelines) -+ rep->start_number = (int64_t) strtoll(startnumber_val, NULL, 10); -+ else -+ rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); - xmlFree(startnumber_val); - } - -- fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline"); -- -- if (!fragment_timeline_node) -- fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline"); -- if (fragment_timeline_node) { -- fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); -- while (fragment_timeline_node) { -- ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node); -- if (ret < 0) { -- return ret; -- } -- fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node); -- } -- } - } else if (representation_baseurl_node && !representation_segmentlist_node) { - seg = av_mallocz(sizeof(struct fragment)); - if (!seg) { - ret = AVERROR(ENOMEM); - goto end; - } -- seg->url = get_content_url(baseurl_nodes, 4, rep_id_val, rep_bandwidth_val, NULL); -+ seg->url = get_content_url(baseurl_nodes, 4, c->max_url_size, rep_id_val, rep_bandwidth_val, NULL); - if (!seg->url) { - av_free(seg); - ret = AVERROR(ENOMEM); -@@ -756,8 +998,14 @@ - // TODO: https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html - // http://www-itec.uni-klu.ac.at/dash/ddash/mpdGenerator.php?fragmentlength=15&type=full - xmlNodePtr fragmenturl_node = NULL; -- duration_val = xmlGetProp(representation_segmentlist_node, "duration"); -- timescale_val = xmlGetProp(representation_segmentlist_node, "timescale"); -+ segmentlists_tab[0] = representation_segmentlist_node; -+ segmentlists_tab[1] = adaptionset_segmentlist_node; -+ segmentlists_tab[2] = period_segmentlist_node; -+ -+ duration_val = get_val_from_nodes_tab(segmentlists_tab, 3, "duration"); -+ timescale_val = get_val_from_nodes_tab(segmentlists_tab, 3, "timescale"); -+ startnumber_val = get_val_from_nodes_tab(segmentlists_tab, 3, "startNumber"); -+ - if (duration_val) { - rep->fragment_duration = (int64_t) strtoll(duration_val, NULL, 10); - xmlFree(duration_val); -@@ -766,6 +1014,10 @@ - rep->fragment_timescale = (int64_t) strtoll(timescale_val, NULL, 10); - xmlFree(timescale_val); - } -+ if (startnumber_val) { -+ rep->start_number = (int64_t) strtoll(startnumber_val, NULL, 10); -+ xmlFree(startnumber_val); -+ } - fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node); - while (fragmenturl_node) { - ret = parse_manifest_segmenturlnode(s, rep, fragmenturl_node, -@@ -778,19 +1030,9 @@ - fragmenturl_node = xmlNextElementSibling(fragmenturl_node); - } - -- fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline"); -- -- if (!fragment_timeline_node) -- fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline"); -- if (fragment_timeline_node) { -- fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); -- while (fragment_timeline_node) { -- ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node); -- if (ret < 0) { -- return ret; -- } -- fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node); -- } -+ ret = fill_timelines(s, rep, segmentlists_tab, 3); -+ if (ret < 0) { -+ return ret; - } - } else { - free_representation(rep); -@@ -801,24 +1043,37 @@ - if (rep) { - if (rep->fragment_duration > 0 && !rep->fragment_timescale) - rep->fragment_timescale = 1; -- if (type == AVMEDIA_TYPE_VIDEO) { -- rep->rep_idx = video_rep_idx; -- c->cur_video = rep; -+ rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0; -+ strncpy(rep->id, rep_id_val ? rep_id_val : "", sizeof(rep->id)); -+ rep->framerate = av_make_q(0, 0); -+ if (type == AVMEDIA_TYPE_VIDEO && rep_framerate_val) { -+ ret = av_parse_video_rate(&rep->framerate, rep_framerate_val); -+ if (ret < 0) -+ av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val); -+ } -+ if (type == AVMEDIA_TYPE_VIDEO && (c->video_rep_index == -1 || c->video_rep_index == c->tmp_video_rep_idx)) { -+ rep->rep_idx = c->tmp_video_rep_idx; -+ dynarray_add(&c->videos, &c->n_videos, rep); -+ } else if (type == AVMEDIA_TYPE_AUDIO && (c->audio_rep_index == -1 || c->audio_rep_index == c->tmp_audio_rep_idx)) { -+ rep->rep_idx = c->tmp_audio_rep_idx; -+ dynarray_add(&c->audios, &c->n_audios, rep); - } else { -- rep->rep_idx = audio_rep_idx; -- c->cur_audio = rep; -+ free_representation(rep); -+ rep = NULL; - } - } - } -- -- video_rep_idx += type == AVMEDIA_TYPE_VIDEO; -- audio_rep_idx += type == AVMEDIA_TYPE_AUDIO; -+ -+ c->tmp_video_rep_idx += type == AVMEDIA_TYPE_VIDEO; -+ c->tmp_audio_rep_idx += type == AVMEDIA_TYPE_AUDIO; - - end: - if (rep_id_val) - xmlFree(rep_id_val); - if (rep_bandwidth_val) - xmlFree(rep_bandwidth_val); -+ if (rep_framerate_val) -+ xmlFree(rep_framerate_val); - - return ret; - } -@@ -826,12 +1081,15 @@ - static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, - xmlNodePtr adaptionset_node, - xmlNodePtr mpd_baseurl_node, -- xmlNodePtr period_baseurl_node) -+ xmlNodePtr period_baseurl_node, -+ xmlNodePtr period_segmenttemplate_node, -+ xmlNodePtr period_segmentlist_node) - { - int ret = 0; - xmlNodePtr fragment_template_node = NULL; - xmlNodePtr content_component_node = NULL; - xmlNodePtr adaptionset_baseurl_node = NULL; -+ xmlNodePtr adaptionset_segmentlist_node = NULL; - xmlNodePtr node = NULL; - - node = xmlFirstElementChild(adaptionset_node); -@@ -842,14 +1100,19 @@ - content_component_node = node; - } else if (!av_strcasecmp(node->name, (const char *)"BaseURL")) { - adaptionset_baseurl_node = node; -+ } else if (!av_strcasecmp(node->name, (const char *)"SegmentList")) { -+ adaptionset_segmentlist_node = node; - } else if (!av_strcasecmp(node->name, (const char *)"Representation")) { - ret = parse_manifest_representation(s, url, node, - adaptionset_node, - mpd_baseurl_node, - period_baseurl_node, -+ period_segmenttemplate_node, -+ period_segmentlist_node, - fragment_template_node, - content_component_node, -- adaptionset_baseurl_node); -+ adaptionset_baseurl_node, -+ adaptionset_segmentlist_node); - if (ret < 0) { - return ret; - } -@@ -874,18 +1137,21 @@ - xmlNodePtr period_node = NULL; - xmlNodePtr mpd_baseurl_node = NULL; - xmlNodePtr period_baseurl_node = NULL; -+ xmlNodePtr period_segmenttemplate_node = NULL; -+ xmlNodePtr period_segmentlist_node = NULL; - xmlNodePtr adaptionset_node = NULL; - xmlAttrPtr attr = NULL; - char *val = NULL; - uint32_t perdiod_duration_sec = 0; - uint32_t perdiod_start_sec = 0; -- int32_t audio_rep_idx = 0; -- int32_t video_rep_idx = 0; -+ -+ c->tmp_audio_rep_idx = 0; -+ c->tmp_video_rep_idx = 0; - - if (!in) { - close_in = 1; - -- set_httpheader_options(c, opts); -+ set_httpheader_options(c, &opts); - ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); - av_dict_free(&opts); - if (ret < 0) -@@ -967,6 +1233,9 @@ - } - - mpd_baseurl_node = find_child_node_by_name(node, "BaseURL"); -+ if (!mpd_baseurl_node) { -+ mpd_baseurl_node = xmlNewNode(NULL, "BaseURL"); -+ } - - // at now we can handle only one period, with the longest duration - node = xmlFirstElementChild(node); -@@ -989,7 +1258,7 @@ - period_node = node; - c->period_duration = perdiod_duration_sec; - c->period_start = perdiod_start_sec; -- if (c->period_start > 0) -+ if (c->period_duration > 0) - c->media_presentation_duration = c->period_duration; - } - } -@@ -1005,19 +1274,15 @@ - while (adaptionset_node) { - if (!av_strcasecmp(adaptionset_node->name, (const char *)"BaseURL")) { - period_baseurl_node = adaptionset_node; -+ } else if (!av_strcasecmp(adaptionset_node->name, (const char *)"SegmentTemplate")) { -+ period_segmenttemplate_node = adaptionset_node; -+ } else if (!av_strcasecmp(adaptionset_node->name, (const char *)"SegmentList")) { -+ period_segmentlist_node = adaptionset_node; - } else if (!av_strcasecmp(adaptionset_node->name, (const char *)"AdaptationSet")) { -- parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node); -+ parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node, period_segmenttemplate_node, period_segmentlist_node); - } - adaptionset_node = xmlNextElementSibling(adaptionset_node); - } -- if (c->cur_video) { -- c->cur_video->rep_count = video_rep_idx; -- av_log(s, AV_LOG_VERBOSE, "rep_idx[%d]\n", (int)c->cur_video->rep_idx); -- av_log(s, AV_LOG_VERBOSE, "rep_count[%d]\n", (int)video_rep_idx); -- } -- if (c->cur_audio) { -- c->cur_audio->rep_count = audio_rep_idx; -- } - cleanup: - /*free the document */ - xmlFreeDoc(doc); -@@ -1029,6 +1294,7 @@ - if (close_in) { - avio_close(in); - } -+ c->last_load_time = av_gettime_relative(); - return ret; - } - -@@ -1042,15 +1308,17 @@ - if (pls->n_fragments) { - num = pls->first_seq_no; - } else if (pls->n_timelines) { -+ - start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - pls->timelines[pls->first_seq_no]->starttime; // total duration of playlist -- if (start_time_offset < 60 * pls->fragment_timescale) -+ if (start_time_offset < 60*pls->fragment_timescale) - start_time_offset = 0; - else - start_time_offset = start_time_offset - 60 * pls->fragment_timescale; -- -+ - num = calc_next_seg_no_from_timelines(pls, pls->timelines[pls->first_seq_no]->starttime + start_time_offset); - if (num == -1) - num = pls->first_seq_no; -+ - } else if (pls->fragment_duration){ - if (pls->presentation_timeoffset) { - num = pls->presentation_timeoffset * pls->fragment_timescale / pls->fragment_duration; -@@ -1079,9 +1347,8 @@ - return num; - } - --static int64_t calc_max_seg_no(struct representation *pls) -+static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c) - { -- DASHContext *c = pls->parent->priv_data; - int64_t num = 0; - - if (pls->n_fragments) { -@@ -1101,83 +1368,119 @@ - return num; - } - --static void move_timelines(struct representation *rep_src, struct representation *rep_dest) -+static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) - { - if (rep_dest && rep_src ) { - free_timelines_list(rep_dest); - rep_dest->timelines = rep_src->timelines; - rep_dest->n_timelines = rep_src->n_timelines; - rep_dest->first_seq_no = rep_src->first_seq_no; -- rep_dest->last_seq_no = calc_max_seg_no(rep_dest); -+ rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); -+ rep_dest->start_number = rep_src->start_number; - rep_src->timelines = NULL; - rep_src->n_timelines = 0; - rep_dest->cur_seq_no = rep_src->cur_seq_no; - } - } - --static void move_segments(struct representation *rep_src, struct representation *rep_dest) -+static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) - { -- if (rep_dest && rep_src ) { -+ if (rep_dest && rep_src) { - free_fragment_list(rep_dest); -- if (rep_src->start_number > (rep_dest->start_number + rep_dest->n_fragments)) -+ if (rep_src->start_number > (rep_dest->start_number + rep_dest->cur_seq_no)) - rep_dest->cur_seq_no = 0; - else -- rep_dest->cur_seq_no += rep_src->start_number - rep_dest->start_number; -+ rep_dest->cur_seq_no = rep_src->n_fragments - ((rep_src->start_number + rep_src->n_fragments) - (rep_dest->start_number + rep_dest->cur_seq_no)); - rep_dest->fragments = rep_src->fragments; - rep_dest->n_fragments = rep_src->n_fragments; - rep_dest->parent = rep_src->parent; -- rep_dest->last_seq_no = calc_max_seg_no(rep_dest); -+ rep_dest->start_number = rep_src->start_number; -+ rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); - rep_src->fragments = NULL; - rep_src->n_fragments = 0; - } - } - -+static int64_t default_reload_interval_us(AVFormatContext *s) -+{ -+ return 2000 * 1000; -+} - - static int refresh_manifest(AVFormatContext *s) - { - -- int ret = 0; -+ int ret = 0, i; - DASHContext *c = s->priv_data; - - // save current context -- struct representation *cur_video = c->cur_video; -- struct representation *cur_audio = c->cur_audio; -+ int n_videos = c->n_videos; -+ struct representation **videos = c->videos; -+ int n_audios = c->n_audios; -+ struct representation **audios = c->audios; - char *base_url = c->base_url; -+ int64_t reload_interval_us = 0; - - c->base_url = NULL; -- c->cur_video = NULL; -- c->cur_audio = NULL; -+ c->n_videos = 0; -+ c->videos = NULL; -+ c->n_audios = 0; -+ c->audios = NULL; -+ -+ reload_interval_us = default_reload_interval_us(s); -+ while (av_gettime_relative() - c->last_load_time < reload_interval_us) { -+ if (ff_check_interrupt(c->interrupt_callback)) -+ return AVERROR_EXIT; -+ av_usleep(100*1000); -+ } -+ - ret = parse_manifest(s, s->filename, NULL); - if (ret) - goto finish; - -- if (cur_video && cur_video->timelines || cur_audio && cur_audio->timelines) { -- // calc current time -- int64_t currentVideoTime = 0; -- int64_t currentAudioTime = 0; -- if (cur_video && cur_video->timelines) -- currentVideoTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale; -- if (cur_audio && cur_audio->timelines) -- currentAudioTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale; -- // update segments -- if (cur_video && cur_video->timelines) { -- c->cur_video->cur_seq_no = calc_next_seg_no_from_timelines(c->cur_video, currentVideoTime * cur_video->fragment_timescale - 1); -- if (c->cur_video->cur_seq_no >= 0) { -- move_timelines(c->cur_video, cur_video); -- } -- } -- if (cur_audio && cur_audio->timelines) { -- c->cur_audio->cur_seq_no = calc_next_seg_no_from_timelines(c->cur_audio, currentAudioTime * cur_audio->fragment_timescale - 1); -- if (c->cur_audio->cur_seq_no >= 0) { -- move_timelines(c->cur_audio, cur_audio); -- } -- } -+ if (c->n_videos != n_videos) { -+ av_log(c, AV_LOG_ERROR, -+ "new manifest has mismatched no. of video representations, %d -> %d\n", -+ n_videos, c->n_videos); -+ return AVERROR_INVALIDDATA; - } -- if (cur_video && cur_video->fragments) { -- move_segments(c->cur_video, cur_video); -+ if (c->n_audios != n_audios) { -+ av_log(c, AV_LOG_ERROR, -+ "new manifest has mismatched no. of audio representations, %d -> %d\n", -+ n_audios, c->n_audios); -+ return AVERROR_INVALIDDATA; - } -- if (cur_audio && cur_audio->fragments) { -- move_segments(c->cur_audio, cur_audio); -+ -+ for (i = 0; i < n_videos; i++) { -+ struct representation *cur_video = videos[i]; -+ struct representation *ccur_video = c->videos[i]; -+ if (cur_video->timelines) { -+ // calc current time -+ int64_t current_time = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale; -+ // update segments -+ ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, current_time * cur_video->fragment_timescale - 1); -+ if (ccur_video->cur_seq_no >= 0) { -+ move_timelines(ccur_video, cur_video, c); -+ } -+ } -+ if (cur_video->fragments) { -+ move_segments(ccur_video, cur_video, c); -+ } -+ } -+ for (i = 0; i < n_audios; i++) { -+ struct representation *cur_audio = audios[i]; -+ struct representation *ccur_audio = c->audios[i]; -+ if (cur_audio->timelines) { -+ // calc current time -+ int64_t current_time = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale; -+ // update segments -+ ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, current_time * cur_audio->fragment_timescale - 1); -+ if (ccur_audio->cur_seq_no >= 0) { -+ move_timelines(ccur_audio, cur_audio, c); -+ } -+ } -+ if (cur_audio->fragments) { -+ move_segments(ccur_audio, cur_audio, c); -+ } - } - - finish: -@@ -1186,12 +1489,14 @@ - av_free(base_url); - else - c->base_url = base_url; -- if (c->cur_audio) -- free_representation(c->cur_audio); -- if (c->cur_video) -- free_representation(c->cur_video); -- c->cur_audio = cur_audio; -- c->cur_video = cur_video; -+ if (c->audios) -+ free_audio_list(c); -+ if (c->videos) -+ free_video_list(c); -+ c->n_audios = n_audios; -+ c->audios = audios; -+ c->n_videos = n_videos; -+ c->videos = videos; - return ret; - } - -@@ -1225,17 +1530,29 @@ - } - } - if (c->is_live) { -- min_seq_no = calc_min_seg_no(pls->parent, pls); -- max_seq_no = calc_max_seg_no(pls); -- -- if (pls->timelines || pls->fragments) { -- refresh_manifest(pls->parent); -- } -- if (pls->cur_seq_no <= min_seq_no) { -- av_log(pls->parent, AV_LOG_VERBOSE, "old fragment: cur[%"PRId64"] min[%"PRId64"] max[%"PRId64"], playlist %d\n", (int64_t)pls->cur_seq_no, min_seq_no, max_seq_no, (int)pls->rep_idx); -- pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls); -- } else if (pls->cur_seq_no > max_seq_no) { -- av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] max[%"PRId64"], playlist %d\n", min_seq_no, max_seq_no, (int)pls->rep_idx); -+ while (!ff_check_interrupt(c->interrupt_callback)) { -+ min_seq_no = calc_min_seg_no(pls->parent, pls); -+ max_seq_no = calc_max_seg_no(pls, c); -+ -+ if (pls->cur_seq_no <= min_seq_no) { -+ av_log(pls->parent, AV_LOG_VERBOSE, "to old fragment: cur[%"PRId64"] min[%"PRId64"] max[%"PRId64"], playlist %d\n", (int64_t)pls->cur_seq_no, min_seq_no, max_seq_no, (int)pls->rep_idx); -+ if (pls->timelines || pls->fragments) { -+ refresh_manifest(pls->parent); -+ } -+ pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls); -+ } else if (pls->cur_seq_no > max_seq_no) { -+ av_log(pls->parent, AV_LOG_VERBOSE, "wait for new fragment:cur[%"PRId64"] min[%"PRId64"] max[%"PRId64"], playlist %d\n", pls->cur_seq_no, min_seq_no, max_seq_no, (int)pls->rep_idx); -+ if (pls->timelines || pls->fragments) { -+ refresh_manifest(pls->parent); -+ } else { -+ /* maybe the better solution will be to sleep based on pls->fragment_duration -+ * for example: 1000 * pls->fragment_duration / pls->fragment_timescale ??? -+ */ -+ sleep_ms(c, 2000); -+ } -+ continue; -+ } -+ break; - } - seg = av_mallocz(sizeof(struct fragment)); - if (!seg) { -@@ -1248,19 +1565,22 @@ - } - } - if (seg) { -- char tmpfilename[MAX_URL_SIZE]; -- -- ff_dash_fill_tmpl_params(tmpfilename, sizeof(tmpfilename), pls->url_template, 0, pls->cur_seq_no, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no)); -+ char *tmpfilename= av_mallocz(c->max_url_size); -+ if (!tmpfilename) { -+ return NULL; -+ } -+ ff_dash_fill_tmpl_params(tmpfilename, c->max_url_size, pls->url_template, 0, pls->cur_seq_no + pls->start_number, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no)); - seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename); - if (!seg->url) { - av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template); - seg->url = av_strdup(pls->url_template); - if (!seg->url) { - av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template); -+ av_free(tmpfilename); - return NULL; - } - } -- -+ av_free(tmpfilename); - seg->size = -1; - } - -@@ -1299,10 +1619,14 @@ - static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg) - { - AVDictionary *opts = NULL; -- char url[MAX_URL_SIZE]; -- int ret; -+ char *url = NULL; -+ int ret = 0; - -- set_httpheader_options(c, opts); -+ url = av_mallocz(c->max_url_size); -+ if (!url) { -+ goto cleanup; -+ } -+ set_httpheader_options(c, &opts); - if (seg->size >= 0) { - /* try to restrict the HTTP request to the part we want - * (if this is in fact a HTTP request) */ -@@ -1310,7 +1634,7 @@ - av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0); - } - -- ff_make_absolute_url(url, MAX_URL_SIZE, c->base_url, seg->url); -+ ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url); - av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64", playlist %d\n", - url, seg->url_offset, pls->rep_idx); - ret = open_url(pls->parent, &pls->input, url, c->avio_opts, opts, NULL); -@@ -1318,19 +1642,8 @@ - goto cleanup; - } - -- /* Seek to the requested position. If this was a HTTP request, the offset -- * should already be where want it to, but this allows e.g. local testing -- * without a HTTP server. */ -- if (!ret && seg->url_offset) { -- int64_t seekret = avio_seek(pls->input, seg->url_offset, SEEK_SET); -- if (seekret < 0) { -- av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of DASH fragment '%s'\n", seg->url_offset, seg->url); -- ret = (int) seekret; -- ff_format_io_close(pls->parent, &pls->input); -- } -- } -- - cleanup: -+ av_free(url); - av_dict_free(&opts); - pls->cur_seg_offset = 0; - pls->cur_seg_size = seg->size; -@@ -1416,13 +1729,28 @@ - - ret = open_input(c, v, v->cur_seg); - if (ret < 0) { -- if (ff_check_interrupt(c->interrupt_callback)) { -- goto end; -- ret = AVERROR_EXIT; -+ av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist %d error [%s]\n", v->rep_idx, av_err2str(ret)); -+ if (ret == AVERROR_HTTP_NOT_FOUND || \ -+ ret == AVERROR_HTTP_BAD_REQUEST || \ -+ ret == AVERROR_HTTP_OTHER_4XX || \ -+ ret == AVERROR_HTTP_SERVER_ERROR) { -+ if (ret == AVERROR_HTTP_OTHER_4XX) { -+ /* 410 - Gone ? our download is to slow? */ -+ v->cur_seq_no++; -+ } else if (c->is_live && v->timelines || v->fragments) { -+ refresh_manifest(v->parent); -+ } else if (!c->is_live) { -+ /* skip missing segment in VOD */ -+ v->cur_seq_no++; -+ } -+ if (ff_check_interrupt(c->interrupt_callback)) { -+ goto end; -+ ret = AVERROR_EXIT; -+ } -+ goto restart; - } -- av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist %d\n", v->rep_idx); -- v->cur_seq_no++; -- goto restart; -+ ret = AVERROR_INVALIDDATA; -+ goto end; - } - } - -@@ -1447,9 +1775,11 @@ - if (ret > 0) - goto end; - -- if (!v->is_restart_needed) -- v->cur_seq_no++; -- v->is_restart_needed = 1; -+ if (c->is_live || v->cur_seq_no < v->last_seq_no) { -+ if (!v->is_restart_needed) -+ v->cur_seq_no++; -+ v->is_restart_needed = 1; -+ } - - end: - return ret; -@@ -1466,8 +1796,12 @@ - if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { - if (buf[0] != '\0') { - ret = av_dict_set(&c->avio_opts, *opt, buf, AV_DICT_DONT_STRDUP_VAL); -- if (ret < 0) -+ if (ret < 0) { -+ av_freep(&buf); - return ret; -+ } -+ } else { -+ av_freep(&buf); - } - } - opt++; -@@ -1486,21 +1820,26 @@ - return AVERROR(EPERM); - } - -+static void close_demux_for_component(struct representation *pls) -+{ -+ /* note: the internal buffer could have changed */ -+ av_freep(&pls->pb.buffer); -+ memset(&pls->pb, 0x00, sizeof(AVIOContext)); -+ pls->ctx->pb = NULL; -+ avformat_close_input(&pls->ctx); -+ pls->ctx = NULL; -+} -+ - static int reopen_demux_for_component(AVFormatContext *s, struct representation *pls) - { - DASHContext *c = s->priv_data; - AVInputFormat *in_fmt = NULL; - AVDictionary *in_fmt_opts = NULL; - uint8_t *avio_ctx_buffer = NULL; -- int ret = 0; -+ int ret = 0, i; - - if (pls->ctx) { -- /* note: the internal buffer could have changed, and be != avio_ctx_buffer */ -- av_freep(&pls->pb.buffer); -- memset(&pls->pb, 0x00, sizeof(AVIOContext)); -- pls->ctx->pb = NULL; -- avformat_close_input(&pls->ctx); -- pls->ctx = NULL; -+ close_demux_for_component(pls); - } - if (!(pls->ctx = avformat_alloc_context())) { - ret = AVERROR(ENOMEM); -@@ -1538,12 +1877,22 @@ - pls->ctx->pb = &pls->pb; - pls->ctx->io_open = nested_io_open; - -+ pls->is_first_pkt = 1; -+ pls->pkt_start_time_offset = 0; -+ - // provide additional information from mpd if available - ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url - av_dict_free(&in_fmt_opts); - if (ret < 0) - goto fail; - if (pls->n_fragments) { -+#if FF_API_R_FRAME_RATE -+ if (pls->framerate.den) { -+ for (i = 0; i < pls->ctx->nb_streams; i++) -+ pls->ctx->streams[i]->r_frame_rate = pls->framerate; -+ } -+#endif -+ - ret = avformat_find_stream_info(pls->ctx, NULL); - if (ret < 0) - goto fail; -@@ -1560,7 +1909,7 @@ - - pls->parent = s; - pls->cur_seq_no = calc_cur_seg_no(s, pls); -- pls->last_seq_no = calc_max_seg_no(pls); -+ pls->last_seq_no = calc_max_seg_no(pls, s->priv_data); - - ret = reopen_demux_for_component(s, pls); - if (ret < 0) { -@@ -1589,6 +1938,7 @@ - DASHContext *c = s->priv_data; - int ret = 0; - int stream_index = 0; -+ int i; - - c->interrupt_callback = &s->interrupt_callback; - // if the URL context is good, read important options we must broker later -@@ -1610,27 +1960,23 @@ - s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE; - } - -- /* Open the demuxer for curent video and current audio components if available */ -- if (!ret && c->cur_video) { -- ret = open_demux_for_component(s, c->cur_video); -- if (!ret) { -- c->cur_video->stream_index = stream_index; -- ++stream_index; -- } else { -- free_representation(c->cur_video); -- c->cur_video = NULL; -- } -+ /* Open the demuxer for video and audio components if available */ -+ for (i = 0; i < c->n_videos; i++) { -+ struct representation *cur_video = c->videos[i]; -+ ret = open_demux_for_component(s, cur_video); -+ if (ret) -+ goto fail; -+ cur_video->stream_index = stream_index; -+ ++stream_index; - } - -- if (!ret && c->cur_audio) { -- ret = open_demux_for_component(s, c->cur_audio); -- if (!ret) { -- c->cur_audio->stream_index = stream_index; -- ++stream_index; -- } else { -- free_representation(c->cur_audio); -- c->cur_audio = NULL; -- } -+ for (i = 0; i < c->n_audios; i++) { -+ struct representation *cur_audio = c->audios[i]; -+ ret = open_demux_for_component(s, cur_audio); -+ if (ret) -+ goto fail; -+ cur_audio->stream_index = stream_index; -+ ++stream_index; - } - - if (!stream_index) { -@@ -1646,11 +1992,25 @@ - goto fail; - } - -- if (c->cur_video) { -- av_program_add_stream_index(s, 0, c->cur_video->stream_index); -- } -- if (c->cur_audio) { -- av_program_add_stream_index(s, 0, c->cur_audio->stream_index); -+ for (i = 0; i < c->n_videos; i++) { -+ struct representation *pls = c->videos[i]; -+ -+ av_program_add_stream_index(s, 0, pls->stream_index); -+ pls->assoc_stream = s->streams[pls->stream_index]; -+ if (pls->bandwidth > 0) -+ av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0); -+ if (pls->id[0]) -+ av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); -+ } -+ for (i = 0; i < c->n_audios; i++) { -+ struct representation *pls = c->audios[i]; -+ -+ av_program_add_stream_index(s, 0, pls->stream_index); -+ pls->assoc_stream = s->streams[pls->stream_index]; -+ if (pls->bandwidth > 0) -+ av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0); -+ if (pls->id[0]) -+ av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); - } - } - -@@ -1659,43 +2019,89 @@ - return ret; - } - -+static void recheck_discard_flags(AVFormatContext *s, struct representation **p, int n) -+{ -+ int i, j; -+ -+ for (i = 0; i < n; i++) { -+ struct representation *pls = p[i]; -+ -+ int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL; -+ if (needed && !pls->ctx) { -+ pls->cur_seg_offset = 0; -+ pls->init_sec_buf_read_offset = 0; -+ /* Catch up */ -+ for (j = 0; j < n; j++) { -+ pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no); -+ } -+ reopen_demux_for_component(s, pls); -+ av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index); -+ } else if (!needed && pls->ctx) { -+ close_demux_for_component(pls); -+ if (pls->input) -+ ff_format_io_close(pls->parent, &pls->input); -+ av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index); -+ } -+ } -+} -+ - static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) - { - DASHContext *c = s->priv_data; -- int ret = 0; -+ int ret = 0, i; -+ int64_t mints = 0; - struct representation *cur = NULL; - -- if (!c->cur_audio && !c->cur_video ) { -- return AVERROR_INVALIDDATA; -+ recheck_discard_flags(s, c->videos, c->n_videos); -+ recheck_discard_flags(s, c->audios, c->n_audios); -+ -+ for (i = 0; i < c->n_videos; i++) { -+ struct representation *pls = c->videos[i]; -+ if (!pls->ctx) -+ continue; -+ if (!cur || pls->cur_timestamp < mints) { -+ cur = pls; -+ mints = pls->cur_timestamp; -+ } - } -- if (c->cur_audio && !c->cur_video) { -- cur = c->cur_audio; -- } else if (!c->cur_audio && c->cur_video) { -- cur = c->cur_video; -- } else if (c->cur_video->cur_timestamp < c->cur_audio->cur_timestamp) { -- cur = c->cur_video; -- } else { -- cur = c->cur_audio; -+ for (i = 0; i < c->n_audios; i++) { -+ struct representation *pls = c->audios[i]; -+ if (!pls->ctx) -+ continue; -+ if (!cur || pls->cur_timestamp < mints) { -+ cur = pls; -+ mints = pls->cur_timestamp; -+ } - } - -- if (cur->ctx) { -- while (!ff_check_interrupt(c->interrupt_callback) && !ret) { -- ret = av_read_frame(cur->ctx, pkt); -- if (ret >= 0) { -- /* If we got a packet, return it */ -- cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den); -- pkt->stream_index = cur->stream_index; -- return 0; -- } -- if (cur->is_restart_needed) { -- cur->cur_seg_offset = 0; -- cur->init_sec_buf_read_offset = 0; -- if (cur->input) -- ff_format_io_close(cur->parent, &cur->input); -- ret = reopen_demux_for_component(s, cur); -- cur->is_restart_needed = 0; -- } -- -+ if (!cur) { -+ return AVERROR_INVALIDDATA; -+ } -+ while (!ff_check_interrupt(c->interrupt_callback) && !ret) { -+ ret = av_read_frame(cur->ctx, pkt); -+ if (ret >= 0) { -+ if (c->is_live && cur->is_first_pkt && 0 == pkt->pts) { -+ cur->pkt_start_time_offset = get_segment_start_time_based_on_timeline(cur, cur->cur_seq_no); -+ } -+ if (cur->pkt_start_time_offset) { -+ AVRational bq; -+ bq.num = 1; -+ bq.den = (int)cur->fragment_timescale; -+ pkt->pts += av_rescale_q(cur->pkt_start_time_offset, bq,cur->ctx->streams[0]->time_base); -+ } -+ /* If we got a packet, return it */ -+ cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den); -+ pkt->stream_index = cur->stream_index; -+ cur->is_first_pkt = 0; -+ return 0; -+ } -+ if (cur->is_restart_needed) { -+ cur->cur_seg_offset = 0; -+ cur->init_sec_buf_read_offset = 0; -+ if (cur->input) -+ ff_format_io_close(cur->parent, &cur->input); -+ ret = reopen_demux_for_component(s, cur); -+ cur->is_restart_needed = 0; - } - } - return AVERROR_EOF; -@@ -1704,12 +2110,8 @@ - static int dash_close(AVFormatContext *s) - { - DASHContext *c = s->priv_data; -- if (c->cur_audio) { -- free_representation(c->cur_audio); -- } -- if (c->cur_video) { -- free_representation(c->cur_video); -- } -+ free_audio_list(c); -+ free_video_list(c); - - av_freep(&c->cookies); - av_freep(&c->user_agent); -@@ -1718,19 +2120,22 @@ - return 0; - } - --static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags) -+static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run) - { - int ret = 0; - int i = 0; - int j = 0; - int64_t duration = 0; - -- av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d\n", seek_pos_msec, pls->rep_idx); -+ av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d%s\n", -+ seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : ""); - - // single fragment mode - if (pls->n_fragments == 1) { - pls->cur_timestamp = 0; - pls->cur_seg_offset = 0; -+ if (dry_run) -+ return 0; - ff_read_frame_flush(pls->ctx); - return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags); - } -@@ -1769,20 +2174,20 @@ - } else if (pls->fragment_duration > 0) { - pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000; - } else { -- av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing fragment_duration\n"); -+ av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n"); - pls->cur_seq_no = pls->first_seq_no; - } - pls->cur_timestamp = 0; - pls->cur_seg_offset = 0; - pls->init_sec_buf_read_offset = 0; -- ret = reopen_demux_for_component(s, pls); -+ ret = dry_run ? 0 : reopen_demux_for_component(s, pls); - - return ret; - } - - static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) - { -- int ret = 0; -+ int ret = 0, i; - DASHContext *c = s->priv_data; - int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000, - s->streams[stream_index]->time_base.den, -@@ -1790,12 +2195,17 @@ - AV_ROUND_DOWN : AV_ROUND_UP); - if ((flags & AVSEEK_FLAG_BYTE) || c->is_live) - return AVERROR(ENOSYS); -- if (c->cur_audio) { -- ret = dash_seek(s, c->cur_audio, seek_pos_msec, flags); -- } -- if (!ret && c->cur_video) { -- ret = dash_seek(s, c->cur_video, seek_pos_msec, flags); -+ -+ /* Seek in discarded streams with dry_run=1 to avoid reopening them */ -+ for (i = 0; i < c->n_videos; i++) { -+ if (!ret) -+ ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx); -+ } -+ for (i = 0; i < c->n_audios; i++) { -+ if (!ret) -+ ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx); - } -+ - return ret; - } - -@@ -1820,6 +2230,10 @@ - #define OFFSET(x) offsetof(DASHContext, x) - #define FLAGS AV_OPT_FLAG_DECODING_PARAM - static const AVOption dash_options[] = { -+ {"audio_rep_index", "audio representation index to be used", -+ OFFSET(audio_rep_index), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, FLAGS}, -+ {"video_rep_index", "video representation index to be used", -+ OFFSET(video_rep_index), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, FLAGS}, - {"allowed_extensions", "List of file extensions that dash is allowed to access", - OFFSET(allowed_extensions), AV_OPT_TYPE_STRING, - {.str = "aac,m4a,m4s,m4v,mov,mp4"}, -@@ -1845,4 +2259,4 @@ - .read_close = dash_close, - .read_seek = dash_read_seek, - .flags = AVFMT_NO_BYTE_SEEK, --}; -+}; -\ No newline at end of file diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-dash-build.patch b/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-dash-build.patch deleted file mode 100644 index 49e9642..0000000 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-dash-build.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/libavformat/Makefile -+++ b/libavformat/Makefile -@@ -135,7 +135,7 @@ - OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o - OBJS-$(CONFIG_DATA_MUXER) += rawenc.o - OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o --OBJS-$(CONFIG_DASH_DEMUXER) += dashdec.o -+OBJS-$(CONFIG_DASH_DEMUXER) += dash.o dashdec.o - OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o - OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o - OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix_mpegts.patch b/archive-patches/ffmpeg/ffmpeg-3.4.2-fix_mpegts.patch deleted file mode 100644 index bfd7f72..0000000 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix_mpegts.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -uNr ffmpeg-3.4.2/libavformat/mpegts.c ffmpeg-3.4.2_fix_mpegts/libavformat/mpegts.c ---- ffmpeg-3.4.2/libavformat/mpegts.c 2018-02-12 01:29:06.000000000 +0100 -+++ ffmpeg-3.4.2_fix_mpegts/libavformat/mpegts.c 2018-02-14 19:36:28.175054407 +0100 -@@ -917,10 +917,12 @@ - pes->buffer = NULL; - reset_pes_packet_state(pes); - -+ /* - sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1); - if (!sd) - return AVERROR(ENOMEM); - *sd = pes->stream_id; -+ */ - - return 0; - } diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-allow_to_choose_rtmp_impl_at_runtime.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-allow_to_choose_rtmp_impl_at_runtime.patch similarity index 60% rename from archive-patches/ffmpeg/ffmpeg-3.4.2-allow_to_choose_rtmp_impl_at_runtime.patch rename to archive-patches/ffmpeg/ffmpeg-4.0.3-allow_to_choose_rtmp_impl_at_runtime.patch index 914f841..b369da7 100644 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-allow_to_choose_rtmp_impl_at_runtime.patch +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-allow_to_choose_rtmp_impl_at_runtime.patch @@ -1,7 +1,6 @@ -diff -uNr ffmpeg-3.4.2/configure ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/configure ---- ffmpeg-3.4.2/configure 2018-02-12 01:29:18.000000000 +0100 -+++ ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/configure 2018-02-14 21:07:28.278640757 +0100 -@@ -3128,10 +3128,8 @@ +--- a/configure 2018-08-17 11:51:31.066805453 +0200 ++++ b/configure 2018-08-17 12:03:19.617555506 +0200 +@@ -3251,10 +3251,8 @@ # protocols async_protocol_deps="threads" bluray_protocol_deps="libbluray" @@ -12,52 +11,62 @@ diff -uNr ffmpeg-3.4.2/configure ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runti ffrtmphttp_protocol_select="http_protocol" ftp_protocol_select="tcp_protocol" gopher_protocol_select="network" -@@ -3148,14 +3146,12 @@ - libssh_protocol_deps="libssh" - mmsh_protocol_select="http_protocol" +@@ -3277,20 +3275,18 @@ mmst_protocol_select="network" + libsrt_protocol_deps="libsrt" + libsrt_protocol_select="network" -rtmp_protocol_conflict="librtmp_protocol" -rtmp_protocol_select="tcp_protocol" +-rtmp_protocol_suggest="zlib" -rtmpe_protocol_select="ffrtmpcrypt_protocol" +-rtmpe_protocol_suggest="zlib" -rtmps_protocol_conflict="librtmp_protocol" -rtmps_protocol_select="tls_protocol" +-rtmps_protocol_suggest="zlib" -rtmpt_protocol_select="ffrtmphttp_protocol" +-rtmpt_protocol_suggest="zlib" -rtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol" +-rtmpte_protocol_suggest="zlib" -rtmpts_protocol_select="ffrtmphttp_protocol https_protocol" +-rtmpts_protocol_suggest="zlib" +ffrtmp_protocol_select="tcp_protocol" ++ffrtmp_protocol_suggest="zlib" +ffrtmpe_protocol_select="ffrtmpcrypt_protocol" ++ffrtmpe_protocol_suggest="zlib" +ffrtmps_protocol_select="tls_protocol" ++ffrtmps_protocol_suggest="zlib" +ffrtmpt_protocol_select="ffrtmphttp_protocol" ++ffrtmpt_protocol_suggest="zlib" +ffrtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol" ++ffrtmpte_protocol_suggest="zlib" +ffrtmpts_protocol_select="ffrtmphttp_protocol https_protocol" ++ffrtmpts_protocol_suggest="zlib" rtp_protocol_select="udp_protocol" + schannel_conflict="openssl gnutls libtls" sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags" - sctp_protocol_select="network" -diff -uNr ffmpeg-3.4.2/libavformat/Makefile ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/libavformat/Makefile ---- ffmpeg-3.4.2/libavformat/Makefile 2018-02-12 01:29:06.000000000 +0100 -+++ ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/libavformat/Makefile 2018-02-14 20:10:19.763205912 +0100 -@@ -575,12 +575,12 @@ +--- a/libavformat/Makefile 2018-07-18 15:52:01.000000000 +0200 ++++ b/libavformat/Makefile 2018-08-17 12:06:16.348291303 +0200 +@@ -594,12 +594,12 @@ OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o --OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o --OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o --OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o --OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o --OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o --OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o -+OBJS-$(CONFIG_FFRTMP_PROTOCOL) += rtmpproto.o rtmppkt.o -+OBJS-$(CONFIG_FFRTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o -+OBJS-$(CONFIG_FFRTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o -+OBJS-$(CONFIG_FFRTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o -+OBJS-$(CONFIG_FFRTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o -+OBJS-$(CONFIG_FFRTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o +-OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +-OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +-OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +-OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +-OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +-OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o ++OBJS-$(CONFIG_FFRTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o ++OBJS-$(CONFIG_FFRTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o ++OBJS-$(CONFIG_FFRTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o ++OBJS-$(CONFIG_FFRTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o ++OBJS-$(CONFIG_FFRTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o ++OBJS-$(CONFIG_FFRTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o -diff -uNr ffmpeg-3.4.2/libavformat/protocols.c ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/libavformat/protocols.c ---- ffmpeg-3.4.2/libavformat/protocols.c 2018-02-12 01:29:06.000000000 +0100 -+++ ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/libavformat/protocols.c 2018-02-14 20:12:01.235570344 +0100 +--- a/libavformat/protocols.c 2018-08-17 12:07:59.489872867 +0200 ++++ b/libavformat/protocols.c 2018-08-17 12:08:24.450255607 +0200 @@ -44,12 +44,12 @@ extern const URLProtocol ff_md5_protocol; extern const URLProtocol ff_pipe_protocol; @@ -77,10 +86,9 @@ diff -uNr ffmpeg-3.4.2/libavformat/protocols.c ffmpeg-3.4.2_allow_to_choose_rtmp extern const URLProtocol ff_rtp_protocol; extern const URLProtocol ff_sctp_protocol; extern const URLProtocol ff_srtp_protocol; -diff -uNr ffmpeg-3.4.2/libavformat/rtmpproto.c ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/libavformat/rtmpproto.c ---- ffmpeg-3.4.2/libavformat/rtmpproto.c 2018-02-12 01:29:06.000000000 +0100 -+++ ffmpeg-3.4.2_allow_to_choose_rtmp_impl_at_runtime/libavformat/rtmpproto.c 2018-02-14 20:21:41.701280041 +0100 -@@ -2626,7 +2626,7 @@ +--- a/libavformat/rtmpproto.c 2018-07-18 15:52:02.000000000 +0200 ++++ b/libavformat/rtmpproto.c 2018-08-17 12:11:43.844590847 +0200 +@@ -2592,7 +2592,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts) { RTMPContext *rt = s->priv_data; @@ -89,7 +97,7 @@ diff -uNr ffmpeg-3.4.2/libavformat/rtmpproto.c ffmpeg-3.4.2_allow_to_choose_rtmp char *old_app, *qmark, *n, fname_buffer[1024]; uint8_t buf[2048]; int port; -@@ -2637,7 +2637,9 @@ +@@ -2603,7 +2603,9 @@ rt->is_input = !(flags & AVIO_FLAG_WRITE); @@ -100,7 +108,7 @@ diff -uNr ffmpeg-3.4.2/libavformat/rtmpproto.c ffmpeg-3.4.2_allow_to_choose_rtmp hostname, sizeof(hostname), &port, path, sizeof(path), s->filename); -@@ -3171,9 +3173,9 @@ +@@ -3137,9 +3139,9 @@ }; diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-edit-list-parsing.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_edit_list_parsing.patch similarity index 97% rename from archive-patches/ffmpeg/ffmpeg-3.4.2-fix-edit-list-parsing.patch rename to archive-patches/ffmpeg/ffmpeg-4.0.3-fix_edit_list_parsing.patch index a266023..f9e56fc 100644 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-edit-list-parsing.patch +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_edit_list_parsing.patch @@ -3,7 +3,7 @@ http://git.videolan.org/gitweb.cgi/ffmpeg.git/?p=ffmpeg.git;a=commitdiff;h=ca6ca --- a/libavformat/mov.c +++ b/libavformat/mov.c -@@ -3191,8 +3191,10 @@ +@@ -3543,8 +3543,10 @@ if (ctts_data_old && ctts_index_old < ctts_count_old) { curr_ctts = ctts_data_old[ctts_index_old].duration; diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-hls.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_hls.patch similarity index 70% rename from archive-patches/ffmpeg/ffmpeg-3.4.2-fix-hls.patch rename to archive-patches/ffmpeg/ffmpeg-4.0.3-fix_hls.patch index a57cbc8..861d6ae 100644 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-fix-hls.patch +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_hls.patch @@ -1,6 +1,6 @@ ---- a/libavformat/hls.c -+++ b/libavformat/hls.c -@@ -1924,8 +1924,10 @@ +--- a/libavformat/hls.c 2018-08-17 13:06:01.428702126 +0200 ++++ b/libavformat/hls.c 2018-08-17 13:06:15.077944569 +0200 +@@ -2079,8 +2079,10 @@ HLSContext *c = s->priv_data; int ret, i, minplaylist = -1; diff --git a/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_mpegts.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_mpegts.patch new file mode 100644 index 0000000..a78057f --- /dev/null +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-fix_mpegts.patch @@ -0,0 +1,15 @@ +--- a/libavformat/mpegts.c 2018-02-12 01:29:06.000000000 +0100 ++++ b/libavformat/mpegts.c 2018-02-14 19:36:28.175054407 +0100 +@@ -930,10 +930,12 @@ + pes->buffer = NULL; + reset_pes_packet_state(pes); + ++ /* + sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1); + if (!sd) + return AVERROR(ENOMEM); + *sd = pes->stream_id; ++ */ + + return 0; + } diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-hls_replace_key_uri.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-hls_replace_key_uri.patch similarity index 63% rename from archive-patches/ffmpeg/ffmpeg-3.4.2-hls_replace_key_uri.patch rename to archive-patches/ffmpeg/ffmpeg-4.0.3-hls_replace_key_uri.patch index 4248694..f176282 100644 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-hls_replace_key_uri.patch +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-hls_replace_key_uri.patch @@ -1,22 +1,21 @@ ---- ffmpeg-3.4.2/libavformat/hls.c -+++ ffmpeg-3.4.2/libavformat/hls.c -@@ -206,6 +206,8 @@ - int strict_std_compliance; - char *allowed_extensions; +--- a/libavformat/hls.c 2018-08-17 13:16:57.721007600 +0200 ++++ b/libavformat/hls.c 2018-08-17 13:33:57.530170057 +0200 +@@ -213,6 +213,8 @@ int max_reload; + int http_persistent; + int http_multiple; + char *key_uri_replace_old; + char *key_uri_replace_new; + AVIOContext *playlist_pb; } HLSContext; - static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) -@@ -1127,8 +1129,17 @@ +@@ -1196,8 +1198,16 @@ AVDictionary *opts2 = NULL; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { + char *key_url = NULL; - AVIOContext *pb; + AVIOContext *pb = NULL; - if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts, NULL) == 0) { -+ + if (NULL != c->key_uri_replace_old && \ + NULL != c-> key_uri_replace_new && \ + '\0' != c->key_uri_replace_old[0]) { @@ -28,7 +27,7 @@ ret = avio_read(pb, pls->key, sizeof(pls->key)); if (ret != sizeof(pls->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", -@@ -1140,6 +1151,8 @@ +@@ -1209,6 +1219,8 @@ seg->key); } av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url)); @@ -37,19 +36,10 @@ } ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); ff_data_to_hex(key, pls->key, sizeof(pls->key), 0); -@@ -1846,7 +1859,7 @@ - for (i = 0; i < c->n_playlists; i++) - c->playlists[i]->cur_needed = 0; - -- for (i = 0; i < s->nb_streams; i++) { -+ for (i = 0; i < s->nb_streams && s->streams[i]->id < c->n_playlists; i++) { - AVStream *st = s->streams[i]; - struct playlist *pls = c->playlists[s->streams[i]->id]; - if (st->discard < AVDISCARD_ALL) -@@ -2159,6 +2172,8 @@ - INT_MIN, INT_MAX, FLAGS}, - {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded", - OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS}, +@@ -2332,6 +2344,8 @@ + OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, + {"http_multiple", "Use multiple HTTP connections for fetching segments", + OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS}, + { "key_uri_old", "allow to replace part of AES key uri - old", OFFSET(key_uri_replace_old), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, FLAGS }, + { "key_uri_new", "allow to replace part of AES key uri - new", OFFSET(key_uri_replace_new), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, FLAGS }, {NULL} diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-buffer-size.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-increase_buffer_size.patch similarity index 69% rename from archive-patches/ffmpeg/ffmpeg-3.4.2-buffer-size.patch rename to archive-patches/ffmpeg/ffmpeg-4.0.3-increase_buffer_size.patch index bf465aa..dd80a06 100644 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-buffer-size.patch +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-increase_buffer_size.patch @@ -1,6 +1,18 @@ +From 90aa7aea0baa100719456e6a5b6e6682a5401aa0 Mon Sep 17 00:00:00 2001 +From: Markus Volk +Date: Sat, 14 Oct 2017 17:39:14 +0200 + +--- + libavformat/avio.h | 6 ------ + libavformat/aviobuf.c | 12 +++++------- + libavformat/utils.c | 19 +++++++++++++++++++ + 3 files changed, 24 insertions(+), 13 deletions(-) + +diff --git a/libavformat/avio.h b/libavformat/avio.h +index 75912ce..56f0a4d 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h -@@ -291,12 +291,6 @@ +@@ -290,12 +290,6 @@ typedef struct AVIOContext { */ int writeout_count; @@ -13,6 +25,8 @@ /** * Threshold to favor readahead over seek. +diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c +index e752d0e..108f089 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -33,7 +33,7 @@ @@ -24,15 +38,15 @@ /** * Do seeks within this distance ahead of the current buffer by skipping -@@ -88,7 +88,6 @@ - int64_t (*seek)(void *opaque, int64_t offset, int whence)) - { +@@ -90,7 +90,6 @@ int ffio_init_context(AVIOContext *s, + memset(s, 0, sizeof(AVIOContext)); + s->buffer = buffer; - s->orig_buffer_size = s->buffer_size = buffer_size; s->buf_ptr = buffer; s->buf_ptr_max = buffer; -@@ -557,16 +556,16 @@ +@@ -570,16 +569,16 @@ static void fill_buffer(AVIOContext *s) } /* make buffer smaller in case it ended up large after probing */ @@ -52,8 +66,8 @@ + len = max_buffer_size; } - if (s->read_packet) -@@ -1009,7 +1008,6 @@ + len = read_packet_wrapper(s, dst, len); +@@ -1087,7 +1086,6 @@ int ffio_set_buf_size(AVIOContext *s, int buf_size) av_free(s->buffer); s->buffer = buffer; @@ -61,13 +75,14 @@ s->buffer_size = buf_size; s->buf_ptr = s->buf_ptr_max = buffer; url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); +diff --git a/libavformat/utils.c b/libavformat/utils.c +index c25eab4..02ce5e2 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c -@@ -118,6 +118,25 @@ - MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb) - FF_ENABLE_DEPRECATION_WARNINGS +@@ -138,6 +138,25 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif -+ + #endif + +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) +{ + if (min_size < *size) @@ -86,6 +101,7 @@ + + return ptr; +} - ++ int64_t av_stream_get_end_pts(const AVStream *st) { + if (st->internal->priv_pts) { diff --git a/archive-patches/ffmpeg/ffmpeg-3.4.2-aac.patch b/archive-patches/ffmpeg/ffmpeg-4.0.3-optimize_aac.patch similarity index 98% rename from archive-patches/ffmpeg/ffmpeg-3.4.2-aac.patch rename to archive-patches/ffmpeg/ffmpeg-4.0.3-optimize_aac.patch index 7bab442..480b163 100644 --- a/archive-patches/ffmpeg/ffmpeg-3.4.2-aac.patch +++ b/archive-patches/ffmpeg/ffmpeg-4.0.3-optimize_aac.patch @@ -1,6 +1,6 @@ --- a/libavcodec/aacdec_template.c +++ b/libavcodec/aacdec_template.c -@@ -2453,7 +2453,7 @@ +@@ -2483,7 +2483,7 @@ * @param decode 1 if tool is used normally, 0 if tool is used in LTP. * @param coef spectral coefficients */ diff --git a/make/ffmpeg.mk b/make/ffmpeg.mk index 38284aa..31ce7b9 100644 --- a/make/ffmpeg.mk +++ b/make/ffmpeg.mk @@ -437,18 +437,27 @@ FFMPEG_DEP = $(D)/libass $(D)/alsa-lib FFMPEG_CONFIGURE += --cpu=cortex-a15 --disable-vfp --extra-cflags="-Wno-deprecated-declarations -I$(TARGETPREFIX)/include" endif +# +# ffmpeg_patches +# +FFMPEG_PATCHES = \ + ffmpeg-$(FFMPEG_VER)-fix_hls.patch \ + ffmpeg-$(FFMPEG_VER)-increase_buffer_size.patch \ + ffmpeg-$(FFMPEG_VER)-optimize_aac.patch \ + ffmpeg-$(FFMPEG_VER)-fix_edit_list_parsing.patch \ + ffmpeg-$(FFMPEG_VER)-fix_mpegts.patch \ + ffmpeg-$(FFMPEG_VER)-allow_to_choose_rtmp_impl_at_runtime.patch \ + ffmpeg-$(FFMPEG_VER)-hls_replace_key_uri.patch + ffmpeg-armbox: $(ARCHIVE)/ffmpeg-$(FFMPEG_VER).tar.xz | $(TARGETPREFIX) $(START_BUILD) $(REMOVE)/ffmpeg-$(FFMPEG_VER) $(UNTAR)/ffmpeg-$(FFMPEG_VER).tar.xz set -e; pushd $(BUILD_TMP)/ffmpeg-$(FFMPEG_VER) && \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-fix_hls.patch; \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-increase_buffer_size.patch; \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-optimize_aac.patch; \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-fix_edit_list_parsing.patch; \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-fix_mpegts.patch; \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-allow_to_choose_rtmp_impl_at_runtime.patch; \ - $(PATCH)/ffmpeg/ffmpeg-$(FFMPEG_VER)-hls_replace_key_uri.patch; \ + for i in $(FFMPEG_PATCHES); do \ + echo -e "==> $(TERM_RED)Applying Patch:$(TERM_NORMAL) $$i"; \ + $(PATCH)/ffmpeg/$$i; \ + done; \ $(BUILDENV) \ ./configure \ $(FFMPEG_CONFIGURE) \ diff --git a/make/versions.mk b/make/versions.mk index d248858..337342a 100644 --- a/make/versions.mk +++ b/make/versions.mk @@ -63,7 +63,7 @@ FBSHOT_VER = 0.3 # FFMPEG | A complete, cross-platform solution to record, convert and stream audio and video ifeq ($(BOXTYPE), armbox) -FFMPEG_VER = 4.0.2 +FFMPEG_VER = 4.0.3 else FFMPEG_GIT = 2ba896f endif -- 2.39.5