[FFmpeg-devel] [PATCH v3] avformat/dashdec: fix memleak for commit commit e134c203
Andreas Rheinhardt
andreas.rheinhardt at gmail.com
Sat Mar 28 03:37:58 EET 2020
Steven Liu:
> These member will be used for get more correct information of the MPD
>
> Suggested-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
> Suggested-by: Nicolas George <george at nsup.org>
> Signed-off-by: Steven Liu <lq at 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)
> +{
> + char *p = src;
> + char *end = NULL;
> + char *end_ptr = NULL;
> + int num, den;
> +
> + num = (int)strtol(p, &end_ptr, 10);
> + if (errno == ERANGE || end_ptr == src) {
> + return AVERROR_INVALIDDATA;
> + }
> +
> + if (end_ptr[0] == '\0') {
> + dst->den = 1;
> + dst->num = num;
> + return 0;
> + }
> +
> + if (end_ptr[0] != '/')
> + return AVERROR_INVALIDDATA;
> + p = end_ptr + 1;
> + den = (int)strtol(p, &end, 10);
> + if (errno == ERANGE || end == src) {
> + dst->den = 1;
> + 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)
> +{
> + char *end_ptr = NULL;
> + char *val = xmlGetProp(node, key);
> + int ret = 0;
> +
> + if (val) {
> + ret = strtoull(val, &end_ptr, 10);
> + 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;
> + }
> +
> 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;
> + }
> + }
> }
>
> 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);
> +
> + 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);
> + }
> }
> }
>
>
The commit title says that this commit is about fixing a memleak (it btw
has one "commit" too much in it), whereas most of this patch is about
adding new functionality. Which makes me wonder how you intend to fix
this in the old releases? Backport everything?
(This problem would of course not exist if the new functionality would
be split from fixing the memleak.)
- Andreas
More information about the ffmpeg-devel
mailing list