X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fdashdec.c;h=271202b0a51bdfe07276e18c2f36f773c8ac62d7;hb=bc52ce309dfcec6151bf1776e6a256f547285700;hp=6b73da62faa1966c7b49a25d20521e5110e78897;hpb=aea524e6e325ff27e4cd0d98212fc5b335c1af48;p=ffmpeg diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index 6b73da62faa..271202b0a51 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -122,19 +122,6 @@ struct representation { typedef struct DASHContext { const AVClass *class; char *base_url; - char *adaptionset_contenttype_val; - char *adaptionset_par_val; - char *adaptionset_lang_val; - char *adaptionset_minbw_val; - char *adaptionset_maxbw_val; - char *adaptionset_minwidth_val; - char *adaptionset_maxwidth_val; - char *adaptionset_minheight_val; - char *adaptionset_maxheight_val; - char *adaptionset_minframerate_val; - char *adaptionset_maxframerate_val; - char *adaptionset_segmentalignment_val; - char *adaptionset_bitstreamswitching_val; int n_videos; struct representation **videos; @@ -363,8 +350,7 @@ static void free_representation(struct representation *pls) free_fragment(&pls->init_section); av_freep(&pls->init_sec_buf); av_freep(&pls->pb.buffer); - if (pls->input) - ff_format_io_close(pls->parent, &pls->input); + ff_format_io_close(pls->parent, &pls->input); if (pls->ctx) { pls->ctx->pb = NULL; avformat_close_input(&pls->ctx); @@ -709,8 +695,8 @@ static int parse_manifest_segmenttimeline(AVFormatContext *s, struct representat return 0; } -static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes) { - +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; @@ -719,7 +705,6 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur char *root_url = NULL; char *text = NULL; char *tmp = NULL; - int isRootHttp = 0; char token ='/'; int start = 0; @@ -795,12 +780,22 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur continue; } text = xmlNodeGetContent(baseurl_nodes[i]); - if (text) { + if (text && !av_strstart(text, "/", NULL)) { memset(tmp_str, 0, strlen(tmp_str)); if (!ishttp(text) && isRootHttp) { av_strlcpy(tmp_str, root_url, size + 1); } start = (text[0] == token); + if (start && av_stristr(tmp_str, text)) { + char *p = tmp_str; + if (!av_strncasecmp(tmp_str, "http://", 7)) { + p += 7; + } else if (!av_strncasecmp(tmp_str, "https://", 8)) { + p += 8; + } + p = strchr(p, '/'); + memset(p + 1, 0, strlen(p)); + } av_strlcat(tmp_str, text + start, tmp_max_url_size); xmlNodeSetContent(baseurl_nodes[i], tmp_str); updated = 1; @@ -842,7 +837,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr representation_segmenttemplate_node = NULL; xmlNodePtr representation_baseurl_node = NULL; xmlNodePtr representation_segmentlist_node = NULL; - xmlNodePtr segmentlists_tab[2]; + xmlNodePtr segmentlists_tab[3]; xmlNodePtr fragment_timeline_node = NULL; xmlNodePtr fragment_templates_tab[5]; char *duration_val = NULL; @@ -877,6 +872,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, ret = AVERROR(ENOMEM); goto end; } + rep->parent = s; representation_segmenttemplate_node = find_child_node_by_name(representation_node, "SegmentTemplate"); representation_baseurl_node = find_child_node_by_name(representation_node, "BaseURL"); representation_segmentlist_node = find_child_node_by_name(representation_node, "SegmentList"); @@ -949,7 +945,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlFree(timescale_val); } if (startnumber_val) { - rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); + rep->start_number = rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); xmlFree(startnumber_val); } @@ -1003,9 +999,11 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr fragmenturl_node = NULL; 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, 2, "duration"); - timescale_val = get_val_from_nodes_tab(segmentlists_tab, 2, "timescale"); + 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); av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); @@ -1016,6 +1014,12 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); xmlFree(timescale_val); } + if (startnumber_val) { + rep->start_number = rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); + xmlFree(startnumber_val); + } + fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node); while (fragmenturl_node) { ret = parse_manifest_segmenturlnode(s, rep, fragmenturl_node, @@ -1107,26 +1111,12 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, xmlNodePtr period_segmentlist_node) { int ret = 0; - DASHContext *c = s->priv_data; xmlNodePtr fragment_template_node = NULL; xmlNodePtr content_component_node = NULL; xmlNodePtr adaptionset_baseurl_node = NULL; xmlNodePtr adaptionset_segmentlist_node = NULL; xmlNodePtr adaptionset_supplementalproperty_node = NULL; xmlNodePtr node = NULL; - c->adaptionset_contenttype_val = xmlGetProp(adaptionset_node, "contentType"); - c->adaptionset_par_val = xmlGetProp(adaptionset_node, "par"); - c->adaptionset_lang_val = xmlGetProp(adaptionset_node, "lang"); - c->adaptionset_minbw_val = xmlGetProp(adaptionset_node, "minBandwidth"); - c->adaptionset_maxbw_val = xmlGetProp(adaptionset_node, "maxBandwidth"); - c->adaptionset_minwidth_val = xmlGetProp(adaptionset_node, "minWidth"); - c->adaptionset_maxwidth_val = xmlGetProp(adaptionset_node, "maxWidth"); - c->adaptionset_minheight_val = xmlGetProp(adaptionset_node, "minHeight"); - c->adaptionset_maxheight_val = xmlGetProp(adaptionset_node, "maxHeight"); - c->adaptionset_minframerate_val = xmlGetProp(adaptionset_node, "minFrameRate"); - c->adaptionset_maxframerate_val = xmlGetProp(adaptionset_node, "maxFrameRate"); - c->adaptionset_segmentalignment_val = xmlGetProp(adaptionset_node, "segmentAlignment"); - c->adaptionset_bitstreamswitching_val = xmlGetProp(adaptionset_node, "bitstreamSwitching"); node = xmlFirstElementChild(adaptionset_node); while (node) { @@ -1185,6 +1175,7 @@ static int parse_programinformation(AVFormatContext *s, xmlNodePtr node) } node = xmlNextElementSibling(node); xmlFree(val); + val = NULL; } return 0; } @@ -1247,7 +1238,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) } else { LIBXML_TEST_VERSION - doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0); + doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0); root_element = xmlDocGetRootElement(doc); node = root_element; @@ -1489,10 +1480,8 @@ static void move_segments(struct representation *rep_src, struct representation static int refresh_manifest(AVFormatContext *s) { - int ret = 0, i; DASHContext *c = s->priv_data; - // save current context int n_videos = c->n_videos; struct representation **videos = c->videos; @@ -1835,7 +1824,7 @@ static int save_avio_options(AVFormatContext *s) { DASHContext *c = s->priv_data; const char *opts[] = { - "headers", "user_agent", "cookies", "http_proxy", "referer", "rw_timeout", NULL }; + "headers", "user_agent", "cookies", "http_proxy", "referer", "rw_timeout", "icy", NULL }; const char **opt = opts; uint8_t *buf = NULL; int ret = 0; @@ -1918,8 +1907,8 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation goto fail; pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO; - pls->ctx->probesize = 1024 * 4; - pls->ctx->max_analyze_duration = 4 * AV_TIME_BASE; + pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4; + pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE; ret = av_probe_input_buffer(&pls->pb, &in_fmt, "", NULL, 0, 0); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Error when loading first fragment, playlist %d\n", (int)pls->rep_idx); @@ -1943,7 +1932,6 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation pls->ctx->streams[i]->r_frame_rate = pls->framerate; } #endif - ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; @@ -1977,7 +1965,7 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p goto fail; } st->id = i; - avcodec_parameters_copy(st->codecpar, pls->ctx->streams[i]->codecpar); + avcodec_parameters_copy(st->codecpar, ist->codecpar); avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); } @@ -2008,19 +1996,26 @@ static int is_common_init_section_exist(struct representation **pls, int n_pls) return 1; } -static void copy_init_section(struct representation *rep_dest, struct representation *rep_src) +static int copy_init_section(struct representation *rep_dest, struct representation *rep_src) { rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size); + if (!rep_dest->init_sec_buf) { + av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n"); + return AVERROR(ENOMEM); + } memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len); rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size; rep_dest->init_sec_data_len = rep_src->init_sec_data_len; rep_dest->cur_timestamp = rep_src->cur_timestamp; + + return 0; } static int dash_read_header(AVFormatContext *s) { DASHContext *c = s->priv_data; + struct representation *rep; int ret = 0; int stream_index = 0; int i; @@ -2046,15 +2041,17 @@ static int dash_read_header(AVFormatContext *s) /* 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]; + rep = c->videos[i]; if (i > 0 && c->is_init_section_common_video) { - copy_init_section(cur_video,c->videos[0]); + ret = copy_init_section(rep, c->videos[0]); + if (ret < 0) + goto fail; } - ret = open_demux_for_component(s, cur_video); + ret = open_demux_for_component(s, rep); if (ret) goto fail; - cur_video->stream_index = stream_index; + rep->stream_index = stream_index; ++stream_index; } @@ -2062,15 +2059,17 @@ static int dash_read_header(AVFormatContext *s) c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios); for (i = 0; i < c->n_audios; i++) { - struct representation *cur_audio = c->audios[i]; + rep = c->audios[i]; if (i > 0 && c->is_init_section_common_audio) { - copy_init_section(cur_audio,c->audios[0]); + ret = copy_init_section(rep, c->audios[0]); + if (ret < 0) + goto fail; } - ret = open_demux_for_component(s, cur_audio); + ret = open_demux_for_component(s, rep); if (ret) goto fail; - cur_audio->stream_index = stream_index; + rep->stream_index = stream_index; ++stream_index; } @@ -2078,19 +2077,20 @@ static int dash_read_header(AVFormatContext *s) c->is_init_section_common_audio = is_common_init_section_exist(c->subtitles, c->n_subtitles); for (i = 0; i < c->n_subtitles; i++) { - struct representation *cur_subtitle = c->subtitles[i]; + rep = c->subtitles[i]; if (i > 0 && c->is_init_section_common_audio) { - copy_init_section(cur_subtitle,c->subtitles[0]); + ret = copy_init_section(rep, c->subtitles[0]); + if (ret < 0) + goto fail; } - ret = open_demux_for_component(s, cur_subtitle); + ret = open_demux_for_component(s, rep); if (ret) goto fail; - cur_subtitle->stream_index = stream_index; + rep->stream_index = stream_index; ++stream_index; } - if (!stream_index) { ret = AVERROR_INVALIDDATA; goto fail; @@ -2105,33 +2105,30 @@ static int dash_read_header(AVFormatContext *s) } 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); + rep = c->videos[i]; + av_program_add_stream_index(s, 0, rep->stream_index); + rep->assoc_stream = s->streams[rep->stream_index]; + if (rep->bandwidth > 0) + av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0); + if (rep->id[0]) + av_dict_set(&rep->assoc_stream->metadata, "id", rep->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); + rep = c->audios[i]; + av_program_add_stream_index(s, 0, rep->stream_index); + rep->assoc_stream = s->streams[rep->stream_index]; + if (rep->bandwidth > 0) + av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0); + if (rep->id[0]) + av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0); } for (i = 0; i < c->n_subtitles; i++) { - struct representation *pls = c->subtitles[i]; - av_program_add_stream_index(s, 0, pls->stream_index); - pls->assoc_stream = s->streams[pls->stream_index]; - if (pls->id[0]) - av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); + rep = c->subtitles[i]; + av_program_add_stream_index(s, 0, rep->stream_index); + rep->assoc_stream = s->streams[rep->stream_index]; + if (rep->id[0]) + av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0); } - } return 0; @@ -2145,8 +2142,8 @@ static void recheck_discard_flags(AVFormatContext *s, struct representation **p, 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; @@ -2158,8 +2155,7 @@ static void recheck_discard_flags(AVFormatContext *s, struct representation **p, 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); + ff_format_io_close(pls->parent, &pls->input); av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index); } } @@ -2171,37 +2167,38 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) int ret = 0, i; int64_t mints = 0; struct representation *cur = NULL; + struct representation *rep = NULL; recheck_discard_flags(s, c->videos, c->n_videos); recheck_discard_flags(s, c->audios, c->n_audios); recheck_discard_flags(s, c->subtitles, c->n_subtitles); for (i = 0; i < c->n_videos; i++) { - struct representation *pls = c->videos[i]; - if (!pls->ctx) + rep = c->videos[i]; + if (!rep->ctx) continue; - if (!cur || pls->cur_timestamp < mints) { - cur = pls; - mints = pls->cur_timestamp; + if (!cur || rep->cur_timestamp < mints) { + cur = rep; + mints = rep->cur_timestamp; } } for (i = 0; i < c->n_audios; i++) { - struct representation *pls = c->audios[i]; - if (!pls->ctx) + rep = c->audios[i]; + if (!rep->ctx) continue; - if (!cur || pls->cur_timestamp < mints) { - cur = pls; - mints = pls->cur_timestamp; + if (!cur || rep->cur_timestamp < mints) { + cur = rep; + mints = rep->cur_timestamp; } } for (i = 0; i < c->n_subtitles; i++) { - struct representation *pls = c->subtitles[i]; - if (!pls->ctx) + rep = c->subtitles[i]; + if (!rep->ctx) continue; - if (!cur || pls->cur_timestamp < mints) { - cur = pls; - mints = pls->cur_timestamp; + if (!cur || rep->cur_timestamp < mints) { + cur = rep; + mints = rep->cur_timestamp; } } @@ -2219,8 +2216,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) 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); + ff_format_io_close(cur->parent, &cur->input); ret = reopen_demux_for_component(s, cur); cur->is_restart_needed = 0; } @@ -2233,7 +2229,6 @@ static int dash_close(AVFormatContext *s) DASHContext *c = s->priv_data; free_audio_list(c); free_video_list(c); - av_dict_free(&c->avio_opts); av_freep(&c->base_url); return 0; @@ -2259,8 +2254,7 @@ static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t see return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags); } - if (pls->input) - ff_format_io_close(pls->parent, &pls->input); + ff_format_io_close(pls->parent, &pls->input); // find the nearest fragment if (pls->n_timelines > 0 && pls->fragment_timescale > 0) { @@ -2340,7 +2334,8 @@ static int dash_probe(const AVProbeData *p) if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") || av_stristr(p->buf, "dash:profile:isoff-live:2011") || av_stristr(p->buf, "dash:profile:isoff-live:2012") || - av_stristr(p->buf, "dash:profile:isoff-main:2011")) { + av_stristr(p->buf, "dash:profile:isoff-main:2011") || + av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) { return AVPROBE_SCORE_MAX; } if (av_stristr(p->buf, "dash:profile")) { @@ -2355,7 +2350,7 @@ static int dash_probe(const AVProbeData *p) static const AVOption dash_options[] = { {"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,webm"}, + {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"}, INT_MIN, INT_MAX, FLAGS}, {NULL} };