Steven Liu (12020-03-20): > 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 | 180 +++++++++++++++++++++++++++++++++++------- > 1 file changed, 151 insertions(+), 29 deletions(-) > > diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c > index 5bbe5d3985..df8f30dcb5 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,17 @@ 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; Unused: remove. Add later if you have something to do with it. > + AVRational adaptionset_minframerate; > + AVRational adaptionset_maxframerate; > + int adaptionset_segmentalignment; > + int adaptionset_bitstreamswitching; Unused: remove. > > int n_videos; > struct representation **videos; > @@ -169,6 +168,51 @@ typedef struct DASHContext { > > } DASHContext; > > +#define DASH_GET_PROP_INT64(node, member, key) \ No reason to make it a macro: make it a function. > +{ \ > + char *val = NULL; \ Useless initialization. > + char *end_ptr = NULL; \ > + val = xmlGetProp((node), (key)); \ > + (member) = 0; \ This overwrites previous initializations, like "c->adaptionset_maxbw = INT64_MAX". > + if (val) { \ > + (member) = strtoull(val, &end_ptr, 10); \ If the value is syntactically incorrect, the error return value of strtoull() will be stored in member, this is not good: use a temp variable. > + if (errno == ERANGE) \ > + av_log((s), AV_LOG_WARNING, "overflow/underflow when get value > of %s\n", (key) ); \ And do nothing? > + 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(EINVAL); \ This is not an invalid value from the user, it's from a file: INVALIDDATA. Also, sometimes you treat an invalid value as an error, sometimes as a warning: inconsistent. > + } \ > + xmlFree(val); \ > + } \ > +} > + > +#define DASH_GET_PROP_RATIO(node, member, key) \ No need to make it a macro. > +{ \ > + char *val = NULL; \ > + val = xmlGetProp((node), (key)); \ > + (member) = av_make_q(0, 0); \ Redundant init. > + if (val) { \ > + ret = get_ratio_from_string(&(member), val); \ > + if (ret < 0) \ > + av_log(s, AV_LOG_WARNING, "Ignoring invalid %s frame rate > '%s'\n", (key), val); \ > + xmlFree(val); \ > + } \ Leak. > +} > + > +#define DASH_GET_PROP_BOOL(node, member, key) \ No need to make it a macro. > +{ \ > + char *val = NULL; \ > + val = xmlGetProp((node), (key)); \ > + (member) = 0; \ Redundant init. > + if (val) { \ > + if (!av_strcasecmp(val, "true")) \ > + (member) = 1; \ > + xmlFree(val); \ > + } \ Leak. > +} > + > static int ishttp(char *url) > { > const char *proto_name = avio_find_protocol_name(url); > @@ -406,6 +450,32 @@ static void free_subtitle_list(DASHContext *c) > c->n_subtitles = 0; > } > > +#define CHECK_STRTOL_RESULT(keystr, dest) \ > +{ \ > + char *end_ptr = NULL; \ > + if ((keystr)) { \ > + (dest) = (int) strtol(keystr, &end_ptr, 10); \ > + if (errno == ERANGE) { \ > + return AVERROR(ERANGE); \ > + } \ > + if (end_ptr == keystr || end_ptr[0] != '\0') { \ > + return AVERROR(EINVAL); \ > + } \ > + } \ > +} > +static int get_ratio_from_string(AVRational *dst, char *src) > +{ > + char *start = NULL; > + char *end = NULL; > + > + dst->den = 1; > + start = av_strtok(src, "/", &end); > + CHECK_STRTOL_RESULT(start, dst->num) > + CHECK_STRTOL_RESULT(end, dst->den) end can be NULL. Don't use av_strtok(), it's not the proper function here. Use strtol(), it returns to you the end of the number. It's bad style to modify a string while parsing if it's not necessary. > + > + return 0; > +} > + > static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, > AVDictionary *opts, AVDictionary *opts2, int *is_http) > { > @@ -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"); > @@ -1073,12 +1152,25 @@ static int > parse_manifest_representation(AVFormatContext *s, const char *url, > 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 > c->adaptionset_maxbw || rep->bandwidth < > c->adaptionset_minbw) > + av_log(s, AV_LOG_WARNING, "The bandwidth of representation > %s id incorrect\n", rep_id_val); > + This warning seems to be of dubious use: warnings should be useful to users; what can a user do here? > 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); > + 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, " > + "higher than max framerate, you should check the > mpd\n", rep_id_val); > + } > + 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, " > + "lower than min framerate, you should check the > mpd\n", rep_id_val); > + } Ditto. > } > > switch (type) { > @@ -1116,6 +1208,34 @@ 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_maxbw = INT64_MAX; > + c->adaptionset_minbw = 0; > + c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang"); > + > + DASH_GET_PROP_INT64(adaptionset_node, c->adaptionset_minbw, > "minBandwidth") > + DASH_GET_PROP_INT64(adaptionset_node, c->adaptionset_maxbw, > "maxBandwidth") > + DASH_GET_PROP_INT64(adaptionset_node, c->adaptionset_minwidth, > "minWidth") > + DASH_GET_PROP_INT64(adaptionset_node, c->adaptionset_maxwidth, > "maxWidth") > + DASH_GET_PROP_INT64(adaptionset_node, c->adaptionset_minheight, > "minHeight") > + DASH_GET_PROP_INT64(adaptionset_node, c->adaptionset_maxheight, > "maxHeight") > + DASH_GET_PROP_RATIO(adaptionset_node, c->adaptionset_minframerate, > "minFrameRate") > + DASH_GET_PROP_RATIO(adaptionset_node, c->adaptionset_maxframerate, > "maxFrameRate") > + DASH_GET_PROP_BOOL(adaptionset_node, c->adaptionset_segmentalignment, > "segmentAlignment") > + DASH_GET_PROP_BOOL(adaptionset_node, c->adaptionset_bitstreamswitching, > "bitstreamSwitching") > + > + return ret; > +} > + > static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, > xmlNodePtr adaptionset_node, > xmlNodePtr mpd_baseurl_node, > @@ -1131,19 +1251,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 +1281,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 +2262,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 +2273,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".