From patchwork Sun Apr 12 12:21:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 18889 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 43A0244B334 for ; Sun, 12 Apr 2020 15:22:13 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1DE7668B5B7; Sun, 12 Apr 2020 15:22:13 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E9D7368B433 for ; Sun, 12 Apr 2020 15:22:05 +0300 (EEST) Received: by mail-wm1-f67.google.com with SMTP id h2so6991671wmb.4 for ; Sun, 12 Apr 2020 05:22:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3KKhLumcADDtVh0hwQBj1CqPCU4HptT73/XJted5r5E=; b=fxhte46fjN/8JzQvbO4E5G5M09Wlizkn8pMR2hXKtZmKAcYBqSNLVf5KhLsh2hHkOa ik3PurQngnI0dIWf3VI3rj/f6qmfWW2DwtZ/Dqj8OnCYC4NXhFU4K4sezjwT1INfU2uQ srP5qU1JFUE0K7OOlBQ0Y/1r+Ey0B78RuDt+lN2cjd6vfz+X4hLynmfv7SyDUqOgNplM n88lu6eLf8VFPO73AL07nkkfvKy0IbCFCe6ErSSc7ZzbOHRUmlp04TwOxoMzoN+fgtf/ uj1S98WP/antqBM4aG5XLuzpyOrm+i2Pb7ruXwtF6J10kBnudb7VSF8YLEZxzHjm6k2x 4+mA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3KKhLumcADDtVh0hwQBj1CqPCU4HptT73/XJted5r5E=; b=MYkvomFBSQFoKaWo7km615KZdt2qaeQL4Onip4UmUk0lp1G7QF0ZMmi7pKEbKUT7pi IzsV6h41kbyzzbxq4znAh3YqkCEPZ1OGgYB+Qhph7ef7IsGHdDshvdhZEKNplsoY4KzL ++6ssUdrFsZJVCCdeY809O1sBqATkteeVJxWCSRPwcxa8U8dipO1P1jWA1lpuLsMb6em RUpfMT6BlUlxcU/5PQu56OCL2qzqc0KZCYqdI7pBOywijHikRShp3yiOx0YWykUFUJeo dOfsTv6vroXEkV40ScAPnRSl89pLcfAJThjfmOS6FOrfXWxuF53zuPjLrlivqyPJlPto wcIA== X-Gm-Message-State: AGi0PuZzksrYmObjb+sZLIJDkjORRUMMLxOuIByD69j5k1u3S0Sr4Zw/ 70KL//AQJPuggIYhCp4TYiHOmMiB X-Google-Smtp-Source: APiQypLijLtURaGzHzDYdy83yX+BDbbM2Xe8cdkrJEBKC4fWRpvoV09uX197dkQE9C5nvwiIhIiB5g== X-Received: by 2002:a05:600c:c8:: with SMTP id u8mr14457143wmm.142.1586694124897; Sun, 12 Apr 2020 05:22:04 -0700 (PDT) Received: from sblaptop.fritz.box (ipbcc1ab57.dynamic.kabel-deutschland.de. [188.193.171.87]) by smtp.gmail.com with ESMTPSA id o9sm10466439wrx.48.2020.04.12.05.22.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 12 Apr 2020 05:22:04 -0700 (PDT) From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Sun, 12 Apr 2020 14:21:58 +0200 Message-Id: <20200412122158.4846-1-andreas.rheinhardt@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200411235642.18193-1-andreas.rheinhardt@gmail.com> References: <20200411235642.18193-1-andreas.rheinhardt@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3] avformat/mux: Make uncoded frames av_packet_unref() compatible 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: Andreas Rheinhardt , Marton Balint Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Currently uncoded frames (i.e. packets whose data actually points to an AVFrame) are not refcounted. As a consequence, calling av_packet_unref() on them will not free them, but may simply make sure that they leak by losing the pointer to the frame. This commit changes this by actually making uncoded frames refcounted. In order not to rely on sizeof(AVFrame) (which is not part of the public API and so must not be used here in libavformat) the packet's data is changed to a (padded) buffer containing just a pointer to an AVFrame. Said buffer is owned by an AVBuffer with a custom free function that frees the frame as well as the buffer. Thereby the pointer/the AVBuffer owns the AVFrame. Said ownership can actually be transferred by copying and resetting the pointer, as might happen when actually writing the uncoded frames in AVOutputFormat.write_uncoded_frame() (although currently no muxer makes use of this possibility). This makes packets containing uncoded frames compatible with av_packet_unref(). This already has three advantages in interleaved mode: 1. If an error happens at the preparatory steps (before the packet is put into the interleavement queue), the frame is properly freed. 2. If the trailer is never written, the frames still in the interleavement queue will now be properly freed by ff_packet_list_free(). 3. The custom code for moving the packet to the packet list in ff_interleave_add_packet() can be removed. It will also simplify fixing further memleaks in future commits. Suggested-by: Marton Balint Signed-off-by: Andreas Rheinhardt --- How embarrassing! The earlier version forgot to check the allocation. libavformat/mux.c | 56 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/libavformat/mux.c b/libavformat/mux.c index cc2d1e275a..bb54fd5528 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -550,12 +550,6 @@ fail: #define AV_PKT_FLAG_UNCODED_FRAME 0x2000 -/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but - it is only being used internally to this file as a consistency check. - The value is chosen to be very unlikely to appear on its own and to cause - immediate failure if used anywhere as a real size. */ -#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame)) - #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS @@ -650,7 +644,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ? - ((AVFrame *)pkt->data)->nb_samples : + (*(AVFrame **)pkt->data)->nb_samples : av_get_audio_frame_duration(st->codec, pkt->size); /* HACK/FIXME, we skip the initial 0 size packets as they are most @@ -746,10 +740,10 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) } if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { - AVFrame *frame = (AVFrame *)pkt->data; - av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); - ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0); - av_frame_free(&frame); + AVFrame **frame = (AVFrame **)pkt->data; + av_assert0(pkt->size == sizeof(*frame)); + ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, frame, 0); + av_packet_unref(pkt); } else { ret = s->oformat->write_packet(s, pkt); } @@ -926,14 +920,9 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, this_pktl = av_malloc(sizeof(AVPacketList)); if (!this_pktl) return AVERROR(ENOMEM); - if (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) { - av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); - av_assert0(((AVFrame *)pkt->data)->buf); - } else { - if ((ret = av_packet_make_refcounted(pkt)) < 0) { - av_free(this_pktl); - return ret; - } + if ((ret = av_packet_make_refcounted(pkt)) < 0) { + av_free(this_pktl); + return ret; } av_packet_move_ref(&this_pktl->pkt, pkt); @@ -1319,22 +1308,45 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, return ret; } +static void uncoded_frame_free(void *unused, uint8_t *data) +{ + av_frame_free((AVFrame **)data); + av_free(data); +} + static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index, AVFrame *frame, int interleaved) { AVPacket pkt, *pktp; av_assert0(s->oformat); - if (!s->oformat->write_uncoded_frame) + if (!s->oformat->write_uncoded_frame) { + av_frame_free(&frame); return AVERROR(ENOSYS); + } if (!frame) { pktp = NULL; } else { + size_t bufsize = sizeof(frame) + AV_INPUT_BUFFER_PADDING_SIZE; + AVFrame **framep = av_mallocz(bufsize); + + if (!framep) + goto fail; pktp = &pkt; av_init_packet(&pkt); - pkt.data = (void *)frame; - pkt.size = UNCODED_FRAME_PACKET_SIZE; + pkt.buf = av_buffer_create((void *)framep, bufsize, + uncoded_frame_free, NULL, 0); + if (!pkt.buf) { + av_free(framep); + fail: + av_frame_free(&frame); + return AVERROR(ENOMEM); + } + *framep = frame; + + pkt.data = (void *)framep; + pkt.size = sizeof(frame); pkt.pts = pkt.dts = frame->pts; pkt.duration = frame->pkt_duration;