Steven Liu (12020-03-24): > These member will be used for get more correct information of the MPD > > Suggested-by: Andreas Rheinhardt <andreas.rheinha...@gmail.com> > Suggested-by: Nicolas George <geo...@nsup.org> > Signed-off-by: Steven Liu <l...@chinaffmpeg.org> > --- > libavformat/dashdec.c | 244 ++++++++++++++++++++++++++++++++++++------ > 1 file changed, 214 insertions(+), 30 deletions(-) > > diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c > index 5bbe5d3985..b5bb8e674c 100644 > --- a/libavformat/dashdec.c > +++ b/libavformat/dashdec.c > @@ -108,6 +108,7 @@ struct representation { > int64_t cur_seg_offset; > int64_t cur_seg_size; > struct fragment *cur_seg; > + char *lang; > > /* Currently active Media Initialization Section */ > struct fragment *init_section; > @@ -122,19 +123,15 @@ 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; > + char *adaptionset_lang; > + uint64_t adaptionset_minbw; > + uint64_t adaptionset_maxbw; > + uint64_t adaptionset_minwidth; > + uint64_t adaptionset_maxwidth; > + uint64_t adaptionset_minheight; > + uint64_t adaptionset_maxheight; > + AVRational adaptionset_minframerate; > + AVRational adaptionset_maxframerate; > > int n_videos; > struct representation **videos; > @@ -169,6 +166,79 @@ typedef struct DASHContext { > > } DASHContext; >
> +static int get_ratio_from_string(AVRational *dst, char *src) const char * > +{ > + char *p = src; Not useful. > + char *end = NULL; > + char *end_ptr = NULL; > + int num, den; > + > + num = (int)strtol(p, &end_ptr, 10); Possible integer overflow. > + if (errno == ERANGE || end_ptr == src) { > + return AVERROR_INVALIDDATA; > + } Unnecessary braces. > + > + if (end_ptr[0] == '\0') { > + dst->den = 1; > + dst->num = num; > + return 0; > + } > + > + if (end_ptr[0] != '/') > + return AVERROR_INVALIDDATA; > + p = end_ptr + 1; Not useful. > + den = (int)strtol(p, &end, 10); Possible integer overflow. > + if (errno == ERANGE || end == src) { > + dst->den = 1; Why? > + return AVERROR_INVALIDDATA; > + } > + dst->den = den; > + > + return 0; > +} > + > +static uint64_t dash_prop_get_int64(AVFormatContext *s, xmlNodePtr node, > uint64_t *dst, const char *key) The return type does not work. > +{ > + char *end_ptr = NULL; > + char *val = xmlGetProp(node, key); > + int ret = 0; > + > + if (val) { > + ret = strtoull(val, &end_ptr, 10); Can't store unsigned long long into int. > + if (errno == ERANGE) { > + av_log(s, AV_LOG_WARNING, "overflow/underflow when get value of > %s\n", key); > + xmlFree(val); > + return AVERROR_INVALIDDATA; > + } > + if (end_ptr == val || end_ptr[0] != '\0') { > + av_log(s, AV_LOG_ERROR, "The %s field value is " > + "not a valid number: %s\n", key, val); > + xmlFree(val); > + return AVERROR_INVALIDDATA; > + } > + *dst = ret; > + xmlFree(val); > + } > + return ret; > +} > + > +static int dash_get_prop_ratio(AVFormatContext *s, xmlNodePtr node, > AVRational *member, const char *key) > +{ > + char *val = xmlGetProp(node, key); > + int ret = 0; > + AVRational rate; > + > + if (val) { > + ret = get_ratio_from_string(&rate, val); > + if (ret < 0) > + av_log(s, AV_LOG_WARNING, "Ignoring invalid %s frame rate > '%s'\n", key, val); > + xmlFree(val); > + } > + member->num = rate.num; > + member->den = rate.den; > + return ret; > +} > + > static int ishttp(char *url) > { > const char *proto_name = avio_find_protocol_name(url); > @@ -885,6 +955,15 @@ static int parse_manifest_representation(AVFormatContext > *s, const char *url, > ret = AVERROR(ENOMEM); > goto end; > } > + if (c->adaptionset_lang) { > + rep->lang = av_strdup(c->adaptionset_lang); > + if (!rep->lang) { > + av_log(s, AV_LOG_ERROR, "alloc language memory failure\n"); > + av_freep(&rep); > + 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"); > @@ -1070,15 +1149,61 @@ static int > parse_manifest_representation(AVFormatContext *s, const char *url, > } > > if (rep) { > + uint64_t width = 0; > + uint64_t height = 0; > + > if (rep->fragment_duration > 0 && !rep->fragment_timescale) > rep->fragment_timescale = 1; > rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0; > + if (rep_bandwidth_val && (rep->bandwidth > c->adaptionset_maxbw > || rep->bandwidth < c->adaptionset_minbw)) { > + av_log(s, AV_LOG_WARNING, "The bandwidth of representation > %s is incorrect, " > + "will ignore this representation.\n", rep_id_val); > + free_representation(rep); > + goto end; > + } > + > + ret = dash_prop_get_int64(s, representation_node, &width, > "width"); > + if (ret < 0) > + av_log(s, AV_LOG_WARNING, "Ignoring the width of > representation %s is incorrect.\n", rep_id_val); > + if (width > c->adaptionset_maxwidth || width < > c->adaptionset_minwidth) { > + av_log(s, AV_LOG_WARNING, "Ignoring width of representation > %s is incorrect, " > + "will ignore this representation.\n", rep_id_val); > + free_representation(rep); > + goto end; > + } > + > + ret = dash_prop_get_int64(s, representation_node, &height, > "height"); > + if (ret < 0) > + av_log(s, AV_LOG_WARNING, "Ignoring the height of > representation %s is incorrect.\n", rep_id_val); > + if (height > c->adaptionset_maxheight || height < > c->adaptionset_minheight) { > + av_log(s, AV_LOG_WARNING, "Ignoring height of representation > %s is incorrect, " > + "will ignore this representation.\n", rep_id_val); > + free_representation(rep); > + goto end; > + } > + Looks unrelated. > 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); > + ret = get_ratio_from_string(&rep->framerate, > rep_framerate_val); > if (ret < 0) > - av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate > '%s'\n", rep_framerate_val); > + av_log(s, AV_LOG_WARNING, "Ignoring invalid frame rate > '%s'\n", rep_framerate_val); > + if (c->adaptionset_maxframerate.num > 0) { > + if (av_cmp_q(rep->framerate, > c->adaptionset_maxframerate) == 1) { > + av_log(s, AV_LOG_WARNING, "Ignoring frame rate of > representation %s incorrect, " > + "will ignore this representation.\n", rep_id_val); > + free_representation(rep); > + goto end; > + } > + } > + if (c->adaptionset_minframerate.num > 0) { > + if (av_cmp_q(rep->framerate, > c->adaptionset_minframerate) == -1) { > + av_log(s, AV_LOG_WARNING, "Ignoring frame rate of > representation %s incorrect, " > + "will ignore this representation.\n", rep_id_val); > + free_representation(rep); > + goto end; > + } > + } This is changing the behavior. I don't know if it is in the desirable direction. > } > > switch (type) { > @@ -1106,6 +1231,7 @@ static int > parse_manifest_representation(AVFormatContext *s, const char *url, > subtitle_rep_idx += type == AVMEDIA_TYPE_SUBTITLE; > > end: > + > if (rep_id_val) > xmlFree(rep_id_val); > if (rep_bandwidth_val) > @@ -1116,6 +1242,62 @@ end: > return ret; > } > > +static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr > adaptionset_node) > +{ > + int ret = 0; > + DASHContext *c = s->priv_data; > + > + if (!adaptionset_node) { > + av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n"); > + return AVERROR(EINVAL); > + } > + c->adaptionset_minframerate = av_make_q(0, 0); > + c->adaptionset_maxframerate = av_make_q(0, 0); > + c->adaptionset_maxbw = UINT64_MAX; > + c->adaptionset_minbw = 0; > + c->adaptionset_minwidth = 0; > + c->adaptionset_maxwidth = UINT64_MAX; > + c->adaptionset_minheight = 0; > + c->adaptionset_maxheight = UINT64_MAX; > + > + c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang"); > + > + ret = dash_prop_get_int64(s, adaptionset_node, &c->adaptionset_minbw, > "minBandwidth"); > + if (ret < 0) > + c->adaptionset_minbw = 0; > + > + ret = dash_prop_get_int64(s, adaptionset_node, &c->adaptionset_maxbw, > "maxBandwidth"); > + if (ret <= 0) > + c->adaptionset_maxbw = UINT64_MAX; > + > + ret = dash_prop_get_int64(s, adaptionset_node, &c->adaptionset_minwidth, > "minWidth"); > + if (ret < 0) > + c->adaptionset_minwidth = 0; > + > + ret = dash_prop_get_int64(s, adaptionset_node, &c->adaptionset_maxwidth, > "maxWidth"); > + if (ret <= 0) > + c->adaptionset_maxwidth = UINT64_MAX; > + > + ret = dash_prop_get_int64(s, adaptionset_node, > &c->adaptionset_minheight, "minHeight"); > + if (ret < 0) > + c->adaptionset_minheight = 0; > + > + ret = dash_prop_get_int64(s, adaptionset_node, > &c->adaptionset_maxheight, "maxHeight"); > + if (ret <= 0) > + c->adaptionset_maxheight = UINT64_MAX; > + > + ret = dash_get_prop_ratio(s, adaptionset_node, > &c->adaptionset_minframerate, "minFrameRate"); > + if (ret < 0) { > + c->adaptionset_minframerate = av_make_q(0, 0); > + } > + > + ret = dash_get_prop_ratio(s, adaptionset_node, > &c->adaptionset_maxframerate, "maxFrameRate"); > + if (ret < 0) > + c->adaptionset_maxframerate = av_make_q(0, 0); If you don't actually use the return code, then have the function use a default value directly, that will make the code more compact. > + > + return ret; > +} > + > static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, > xmlNodePtr adaptionset_node, > xmlNodePtr mpd_baseurl_node, > @@ -1131,19 +1313,10 @@ static int > parse_manifest_adaptationset(AVFormatContext *s, const char *url, > 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"); > + > + ret = parse_manifest_adaptationset_attr(s, adaptionset_node); > + if (ret < 0) > + return ret; > > node = xmlFirstElementChild(adaptionset_node); > while (node) { > @@ -1170,12 +1343,15 @@ static int > parse_manifest_adaptationset(AVFormatContext *s, const char *url, > adaptionset_segmentlist_node, > > adaptionset_supplementalproperty_node); > if (ret < 0) { > - return ret; > + goto end; > } > } > node = xmlNextElementSibling(node); > } > - return 0; > + > +end: > + av_freep(&c->adaptionset_lang); > + return ret; > } > > static int parse_programinformation(AVFormatContext *s, xmlNodePtr node) > @@ -2148,6 +2324,10 @@ static int dash_read_header(AVFormatContext *s) > 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); > + if (rep->lang) { > + av_dict_set(&rep->assoc_stream->metadata, "lang", rep->lang, > 0); > + av_freep(&rep->lang); > + } > } > for (i = 0; i < c->n_subtitles; i++) { > rep = c->subtitles[i]; > @@ -2155,6 +2335,10 @@ static int dash_read_header(AVFormatContext *s) > rep->assoc_stream = s->streams[rep->stream_index]; > if (rep->id[0]) > av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0); > + if (rep->lang) { > + av_dict_set(&rep->assoc_stream->metadata, "lang", rep->lang, > 0); > + av_freep(&rep->lang); > + } > } > } > Regards, -- Nicolas George
signature.asc
Description: PGP signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".