From patchwork Fri Mar 20 02:49:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liu Steven X-Patchwork-Id: 18306 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 27ED6449381 for ; Fri, 20 Mar 2020 04:49:18 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 04EC468B6A1; Fri, 20 Mar 2020 04:49:18 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from qq.com (smtpbg467.qq.com [59.36.132.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BA40968B651 for ; Fri, 20 Mar 2020 04:49:10 +0200 (EET) X-QQ-mid: bizesmtp11t1584672544t6pf1o1r Received: from localhost (unknown [123.115.192.205]) by esmtp6.qq.com (ESMTP) with id ; Fri, 20 Mar 2020 10:49:03 +0800 (CST) X-QQ-SSF: 01100000002000K0ZTF0000A0000000 X-QQ-FEAT: bP3hyS9xCjCqvkahguAf9B2m060Fd8PjMp4yw5qWi6LZ3Zm2gcHSiPqiyRoHM 51XiTwZKS4yam4JwWzXH7cVjRLWdY7HbF6JIQtASa0BTfeKWDzyw3iZxXyHsmy+OsCMlWMS 3m6JGhfozZOUQY4/upjukPtsb8owLrW1KThinFDRC1AkgwGB63+TqHJlwWLajcirZhLUFig iXdcFQDCiDjiSq79w4IEOWIdxb0z/Mrb//5uZo0wiyRNIBpeu4IrVO+GNIKYee8p82H9iVi Qvz5hQnTRW7lpFfjo6n4SR7a+Fqdm2UCt9EfNorCAoEcZ/vR2GBnjLKiuz0DAzTb6jP/EQU at6tGpd X-QQ-GoodBg: 0 From: Steven Liu To: ffmpeg-devel@ffmpeg.org Date: Fri, 20 Mar 2020 10:49:00 +0800 Message-Id: <20200320024900.8436-1-lq@chinaffmpeg.org> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200316164701.81967-1-lq@chinaffmpeg.org> References: <20200316164701.81967-1-lq@chinaffmpeg.org> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:chinaffmpeg.org:qybgweb:qybgweb14 Subject: [FFmpeg-devel] [PATCH v2] avformat/dashdec: fix memleak for commit commit e134c203 X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Steven Liu , Nicolas George , Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" These member will be used for get more correct information of the MPD Suggested-by: Andreas Rheinhardt Suggested-by: Nicolas George Signed-off-by: Steven Liu --- 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; + AVRational adaptionset_minframerate; + AVRational adaptionset_maxframerate; + int adaptionset_segmentalignment; + int adaptionset_bitstreamswitching; int n_videos; struct representation **videos; @@ -169,6 +168,51 @@ typedef struct DASHContext { } DASHContext; +#define DASH_GET_PROP_INT64(node, member, key) \ +{ \ + char *val = NULL; \ + char *end_ptr = NULL; \ + val = xmlGetProp((node), (key)); \ + (member) = 0; \ + if (val) { \ + (member) = strtoull(val, &end_ptr, 10); \ + if (errno == ERANGE) \ + av_log((s), AV_LOG_WARNING, "overflow/underflow when get value of %s\n", (key) ); \ + 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); \ + } \ + xmlFree(val); \ + } \ +} + +#define DASH_GET_PROP_RATIO(node, member, key) \ +{ \ + char *val = NULL; \ + val = xmlGetProp((node), (key)); \ + (member) = av_make_q(0, 0); \ + 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); \ + } \ +} + +#define DASH_GET_PROP_BOOL(node, member, key) \ +{ \ + char *val = NULL; \ + val = xmlGetProp((node), (key)); \ + (member) = 0; \ + if (val) { \ + if (!av_strcasecmp(val, "true")) \ + (member) = 1; \ + xmlFree(val); \ + } \ +} + 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) + + 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); + 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); + } } 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); + } } }