From patchwork Sat Dec 4 17:33:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 31960 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:cd86:0:0:0:0:0 with SMTP id d128csp2268106iog; Sat, 4 Dec 2021 09:33:45 -0800 (PST) X-Google-Smtp-Source: ABdhPJypqmV14I8UYAupoVI8YhRGmgWqbkb4mI5eVnCIieRP66upLdNdll5wbe/dEFZ5DQhRwRPo X-Received: by 2002:a17:906:d54c:: with SMTP id cr12mr32329540ejc.56.1638639225253; Sat, 04 Dec 2021 09:33:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1638639225; cv=none; d=google.com; s=arc-20160816; b=AttaaD62wjBGhOPEDC/fXcTqwvf/SNN3aNubWRo8olNZ5qT51mPNvZ//lvpFntNoRp YQsVotFg8UZuumVpKdg5ifcAkbbA74u5SkPurzovAPJ8WXyqAOohViZiWcV2rjd/96LZ oZwDal0aQk1ED3aJk6p/Q4TDjdhBj/+cCZL9zJ1b0YbUV9pMLkdDfH0cEOSOVRRs9rad ugWt28oRJm6nmd5oZ5iJoacl6Q2zGQIUHbV61cTIEhFwjI3dYaEfXHdHYQ2oex3x+elD qpquSWAxj2+tzSI8AGeCmfvhSnoQJ5Q//Lx9W8+AVbDm2HBnIHzlLvjae/ixSUMXEylT kKzw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:delivered-to; bh=3nXbg5fKDm3uBmFlJBKNG4pY5LnandZK3wwoP8QZQdU=; b=BaBCqedIu6LCxFm2GFBM/GmPB2JcR/2+Z6ytecU4GcYQjQuzHzWl0s0w5dvF/RPF28 FwvSUqG4pdynSYWJ7Bb8/2TYb6tTBCodj2ZBO/VXKftJZuVdbljDS9Yare45wJ6xtB3Q N6iDy8l9N7MU6kwTce3iTHJfm7Fg6/gRjVTeobh/aImNly753W8BPRqIDxc2WD3Yj4pp 0hcI1h8/Uq/lRj8izi192i8jij2d8gFThty3/mDbjD9BkRBoXnO9OtV6yO87ZPYioeTu WKEhpEPvhV4zuzh/GECnO8zc6dbw3C3YRsy8G4kZO0JwXH6w5K6qDveTUbdRlqvqytzn 6fAg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id rk27si8769072ejb.268.2021.12.04.09.33.44; Sat, 04 Dec 2021 09:33:45 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 955F868AE57; Sat, 4 Dec 2021 19:33:20 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 47A4A68AAA0 for ; Sat, 4 Dec 2021 19:33:12 +0200 (EET) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id B56A924017A for ; Sat, 4 Dec 2021 18:33:11 +0100 (CET) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id sZfL-UUNjR1w for ; Sat, 4 Dec 2021 18:33:10 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:2a00:c500:561:201::7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "libav.khirnov.net", Issuer "smtp.khirnov.net SMTP CA" (verified OK)) by mail0.khirnov.net (Postfix) with ESMTPS id 6E58224017C for ; Sat, 4 Dec 2021 18:33:09 +0100 (CET) Received: by libav.khirnov.net (Postfix, from userid 1000) id 20A7A3A073E; Sat, 4 Dec 2021 18:33:09 +0100 (CET) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Sat, 4 Dec 2021 18:33:00 +0100 Message-Id: <20211204173300.5742-3-anton@khirnov.net> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211204173300.5742-1-anton@khirnov.net> References: <20211204173300.5742-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/3] lavf/sdp: add more thorough error handling X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: w1Qn7seGoQJT Return error codes when constructing a stream config fails, rather than just disregarding the failure and continuing. Propagate the error codes from av_sdp_create(). --- libavformat/internal.h | 7 +- libavformat/sdp.c | 189 +++++++++++++++++++++++++---------------- 2 files changed, 120 insertions(+), 76 deletions(-) diff --git a/libavformat/internal.h b/libavformat/internal.h index 528ff7e017..db1d83be17 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -545,10 +545,11 @@ uint64_t ff_parse_ntp_time(uint64_t ntp_ts); * @param ttl the time to live of the stream, 0 if not multicast * @param fmt the AVFormatContext, which might contain options modifying * the generated SDP + * @return 0 on success, a negative error code on failure */ -void ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx, - const char *dest_addr, const char *dest_type, - int port, int ttl, AVFormatContext *fmt); +int ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx, + const char *dest_addr, const char *dest_type, + int port, int ttl, AVFormatContext *fmt); /** * Write a packet to another muxer than the one the user originally diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 1cdd21c97b..a5aba8a80c 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -151,7 +151,8 @@ static int sdp_get_address(char *dest_addr, int size, int *ttl, const char *url) } #define MAX_PSET_SIZE 1024 -static char *extradata2psets(AVFormatContext *s, const AVCodecParameters *par) +static int extradata2psets(AVFormatContext *s, const AVCodecParameters *par, + char **out) { char *psets, *p; const uint8_t *r; @@ -162,15 +163,18 @@ static char *extradata2psets(AVFormatContext *s, const AVCodecParameters *par) uint8_t *tmpbuf = NULL; const uint8_t *sps = NULL, *sps_end; + *out = NULL; + if (par->extradata_size > MAX_EXTRADATA_SIZE) { av_log(s, AV_LOG_ERROR, "Too much extradata!\n"); - - return NULL; + return AVERROR_INVALIDDATA; } if (par->extradata[0] == 1) { - if (ff_avc_write_annexb_extradata(par->extradata, &extradata, - &extradata_size)) - return NULL; + int ret = ff_avc_write_annexb_extradata(par->extradata, &extradata, + &extradata_size); + if (ret < 0) + return ret; + tmpbuf = extradata; } @@ -178,7 +182,7 @@ static char *extradata2psets(AVFormatContext *s, const AVCodecParameters *par) if (!psets) { av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the parameter sets.\n"); av_free(tmpbuf); - return NULL; + return AVERROR(ENOMEM); } memcpy(psets, pset_string, strlen(pset_string)); p = psets + strlen(pset_string); @@ -203,11 +207,12 @@ static char *extradata2psets(AVFormatContext *s, const AVCodecParameters *par) sps_end = r1; } if (!av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r)) { - av_log(s, AV_LOG_ERROR, "Cannot Base64-encode %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"!\n", MAX_PSET_SIZE - (p - psets), r1 - r); + av_log(s, AV_LOG_ERROR, "Cannot Base64-encode %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"!\n", + MAX_PSET_SIZE - (p - psets), r1 - r); av_free(psets); av_free(tmpbuf); - return NULL; + return AVERROR_INVALIDDATA; } p += strlen(p); r = r1; @@ -220,10 +225,11 @@ static char *extradata2psets(AVFormatContext *s, const AVCodecParameters *par) } av_free(tmpbuf); - return psets; + *out = psets; + return 0; } -static char *extradata2psets_hevc(const AVCodecParameters *par) +static int extradata2psets_hevc(const AVCodecParameters *par, char **out) { char *psets; uint8_t *extradata = par->extradata; @@ -232,7 +238,9 @@ static char *extradata2psets_hevc(const AVCodecParameters *par) int ps_pos[3] = { 0 }; static const char * const ps_names[3] = { "vps", "sps", "pps" }; int num_arrays, num_nalus; - int pos, i, j; + int pos, i, j, ret; + + *out = NULL; // Convert to hvcc format. Since we need to group multiple NALUs of // the same type, and we might need to convert from one format to the @@ -240,9 +248,13 @@ static char *extradata2psets_hevc(const AVCodecParameters *par) // format. if (par->extradata[0] != 1) { AVIOContext *pb; - if (avio_open_dyn_buf(&pb) < 0) - return NULL; - if (ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0) < 0) { + + ret = avio_open_dyn_buf(&pb); + if (ret < 0) + return ret; + + ret = ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0); + if (ret < 0) { avio_close_dyn_buf(pb, &tmpbuf); goto err; } @@ -285,8 +297,11 @@ static char *extradata2psets_hevc(const AVCodecParameters *par) goto err; psets = av_mallocz(MAX_PSET_SIZE); - if (!psets) + if (!psets) { + ret = AVERROR(ENOMEM); goto err; + } + psets[0] = '\0'; for (i = 0; i < 3; i++) { @@ -317,41 +332,49 @@ static char *extradata2psets_hevc(const AVCodecParameters *par) } av_free(tmpbuf); - return psets; - + *out = psets; + return 0; err: + if (ret >= 0) + ret = AVERROR_INVALIDDATA; av_free(tmpbuf); - return NULL; + return ret; } -static char *extradata2config(AVFormatContext *s, const AVCodecParameters *par) +static int extradata2config(AVFormatContext *s, const AVCodecParameters *par, + char **out) { char *config; + *out = NULL; + if (par->extradata_size > MAX_EXTRADATA_SIZE) { av_log(s, AV_LOG_ERROR, "Too much extradata!\n"); - - return NULL; + return AVERROR_INVALIDDATA; } config = av_malloc(10 + par->extradata_size * 2); if (!config) { av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n"); - return NULL; + return AVERROR(ENOMEM); } memcpy(config, "; config=", 9); ff_data_to_hex(config + 9, par->extradata, par->extradata_size, 0); config[9 + par->extradata_size * 2] = 0; - return config; + *out = config; + return 0; } -static char *xiph_extradata2config(AVFormatContext *s, const AVCodecParameters *par) +static int xiph_extradata2config(AVFormatContext *s, const AVCodecParameters *par, + char **out) { uint8_t *config; char *encoded_config; const uint8_t *header_start[3]; int headers_len, header_len[3], config_len; - int first_header_size; + int first_header_size, ret; + + *out = NULL; switch (par->codec_id) { case AV_CODEC_ID_THEORA: @@ -362,14 +385,15 @@ static char *xiph_extradata2config(AVFormatContext *s, const AVCodecParameters * break; default: av_log(s, AV_LOG_ERROR, "Unsupported Xiph codec ID\n"); - return NULL; + return AVERROR(ENOSYS); } - if (avpriv_split_xiph_headers(par->extradata, par->extradata_size, - first_header_size, header_start, - header_len) < 0) { + ret = avpriv_split_xiph_headers(par->extradata, par->extradata_size, + first_header_size, header_start, + header_len); + if (ret < 0) { av_log(s, AV_LOG_ERROR, "Extradata corrupt.\n"); - return NULL; + return ret; } headers_len = header_len[0] + header_len[2]; @@ -407,12 +431,13 @@ static char *xiph_extradata2config(AVFormatContext *s, const AVCodecParameters * config, config_len); av_free(config); - return encoded_config; + *out = encoded_config; + return 0; xiph_fail: av_log(s, AV_LOG_ERROR, "Not enough memory for configuration string\n"); - return NULL; + return AVERROR(ENOMEM); } static int latm_context2profilelevel(const AVCodecParameters *par) @@ -444,7 +469,8 @@ static int latm_context2profilelevel(const AVCodecParameters *par) return profile_level; } -static char *latm_context2config(AVFormatContext *s, const AVCodecParameters *par) +static int latm_context2config(AVFormatContext *s, const AVCodecParameters *par, + char **out) { /* MP4A-LATM * The RTP payload format specification is described in RFC 3016 @@ -454,12 +480,14 @@ static char *latm_context2config(AVFormatContext *s, const AVCodecParameters *pa int rate_index; char *config; + *out = NULL; + for (rate_index = 0; rate_index < 16; rate_index++) if (avpriv_mpeg4audio_sample_rates[rate_index] == par->sample_rate) break; if (rate_index == 16) { av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n"); - return NULL; + return AVERROR(ENOSYS); } config_byte[0] = 0x40; @@ -472,19 +500,21 @@ static char *latm_context2config(AVFormatContext *s, const AVCodecParameters *pa config = av_malloc(6*2+1); if (!config) { av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n"); - return NULL; + return AVERROR(ENOMEM); } ff_data_to_hex(config, config_byte, 6, 1); config[12] = 0; - return config; + *out = config; + return 0; } -static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st, - int payload_type, AVFormatContext *fmt) +static int sdp_write_media_attributes(char *buff, int size, const AVStream *st, + int payload_type, AVFormatContext *fmt) { char *config = NULL; const AVCodecParameters *p = st->codecpar; + int ret = 0; switch (p->codec_id) { case AV_CODEC_ID_DIRAC: @@ -496,7 +526,9 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st av_opt_flag_is_set(fmt->priv_data, "rtpflags", "h264_mode0")) mode = 0; if (p->extradata_size) { - config = extradata2psets(fmt, p); + ret = extradata2psets(fmt, p, &config); + if (ret < 0) + return ret; } av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n" "a=fmtp:%d packetization-mode=%d%s\r\n", @@ -533,8 +565,11 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st payload_type, p->width, p->height); break; case AV_CODEC_ID_HEVC: - if (p->extradata_size) - config = extradata2psets_hevc(p); + if (p->extradata_size) { + ret = extradata2psets_hevc(p, &config); + if (ret < 0) + return ret; + } av_strlcatf(buff, size, "a=rtpmap:%d H265/90000\r\n", payload_type); if (config) av_strlcatf(buff, size, "a=fmtp:%d %s\r\n", @@ -542,7 +577,9 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st break; case AV_CODEC_ID_MPEG4: if (p->extradata_size) { - config = extradata2config(fmt, p); + ret = extradata2config(fmt, p, &config); + if (ret < 0) + return ret; } av_strlcatf(buff, size, "a=rtpmap:%d MP4V-ES/90000\r\n" "a=fmtp:%d profile-level-id=1%s\r\n", @@ -552,25 +589,24 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st case AV_CODEC_ID_AAC: if (fmt && fmt->oformat && fmt->oformat->priv_class && av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) { - config = latm_context2config(fmt, p); - if (!config) - return NULL; + ret = latm_context2config(fmt, p, &config); + if (ret < 0) + return ret; av_strlcatf(buff, size, "a=rtpmap:%d MP4A-LATM/%d/%d\r\n" "a=fmtp:%d profile-level-id=%d;cpresent=0;config=%s\r\n", payload_type, p->sample_rate, p->channels, payload_type, latm_context2profilelevel(p), config); } else { if (p->extradata_size) { - config = extradata2config(fmt, p); + ret = extradata2config(fmt, p, &config); + if (ret < 0) + return ret; } else { /* FIXME: maybe we can forge config information based on the * codec parameters... */ av_log(fmt, AV_LOG_ERROR, "AAC with no global headers is currently not supported.\n"); - return NULL; - } - if (!config) { - return NULL; + return AVERROR(ENOSYS); } av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n" "a=fmtp:%d profile-level-id=1;" @@ -618,11 +654,13 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st break; case AV_CODEC_ID_VORBIS: if (p->extradata_size) - config = xiph_extradata2config(fmt, p); - else + ret = xiph_extradata2config(fmt, p, &config); + else { av_log(fmt, AV_LOG_ERROR, "Vorbis configuration info missing\n"); - if (!config) - return NULL; + ret = AVERROR_INVALIDDATA; + } + if (ret < 0) + return ret; av_strlcatf(buff, size, "a=rtpmap:%d vorbis/%d/%d\r\n" "a=fmtp:%d configuration=%s\r\n", @@ -643,15 +681,17 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st break; default: av_log(fmt, AV_LOG_ERROR, "Unsupported pixel format.\n"); - return NULL; + return AVERROR(ENOSYS); } if (p->extradata_size) - config = xiph_extradata2config(fmt, p); - else + ret = xiph_extradata2config(fmt, p, &config); + else { av_log(fmt, AV_LOG_ERROR, "Theora configuration info missing\n"); - if (!config) - return NULL; + ret = AVERROR_INVALIDDATA; + } + if (ret < 0) + return ret; av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n" "a=fmtp:%d delivery-method=inline; " @@ -685,7 +725,7 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st break; default: av_log(fmt, AV_LOG_ERROR, "Unsupported pixel format.\n"); - return NULL; + return AVERROR(ENOSYS); } av_strlcatf(buff, size, "a=rtpmap:%d raw/90000\r\n" @@ -763,12 +803,12 @@ static char *sdp_write_media_attributes(char *buff, int size, const AVStream *st av_free(config); - return buff; + return 0; } -void ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx, - const char *dest_addr, const char *dest_type, - int port, int ttl, AVFormatContext *fmt) +int ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx, + const char *dest_addr, const char *dest_type, + int port, int ttl, AVFormatContext *fmt) { const AVCodecParameters *p = st->codecpar; const char *type; @@ -789,7 +829,7 @@ void ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx, av_strlcatf(buff, size, "b=AS:%"PRId64"\r\n", p->bit_rate / 1000); } - sdp_write_media_attributes(buff, size, st, payload_type, fmt); + return sdp_write_media_attributes(buff, size, st, payload_type, fmt); } int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size) @@ -835,10 +875,13 @@ int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size) ttl = 0; } for (j = 0; j < ac[i]->nb_streams; j++) { - ff_sdp_write_media(buf, size, ac[i]->streams[j], index++, - dst[0] ? dst : NULL, dst_type, - (port > 0) ? port + j * 2 : 0, - ttl, ac[i]); + int ret = ff_sdp_write_media(buf, size, ac[i]->streams[j], index++, + dst[0] ? dst : NULL, dst_type, + (port > 0) ? port + j * 2 : 0, + ttl, ac[i]); + if (ret < 0) + return ret; + if (port <= 0) { av_strlcatf(buf, size, "a=control:streamid=%d\r\n", i + j); @@ -867,9 +910,9 @@ int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size) return AVERROR(ENOSYS); } -void ff_sdp_write_media(char *buff, int size, AVStream *st, int idx, - const char *dest_addr, const char *dest_type, - int port, int ttl, AVFormatContext *fmt) +int ff_sdp_write_media(char *buff, int size, AVStream *st, int idx, + const char *dest_addr, const char *dest_type, + int port, int ttl, AVFormatContext *fmt) { } #endif