From patchwork Sun Feb 21 17:35:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 25862 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 1AEFD44B02B for ; Sun, 21 Feb 2021 19:36:09 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D2C5F68A583; Sun, 21 Feb 2021 19:36:08 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk1-f177.google.com (mail-qk1-f177.google.com [209.85.222.177]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8507D68A492 for ; Sun, 21 Feb 2021 19:36:01 +0200 (EET) Received: by mail-qk1-f177.google.com with SMTP id x14so10577477qkm.2 for ; Sun, 21 Feb 2021 09:36:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=T2JXZqRANkDgwoD9s9eMl08MgDzE/eGytIftSnYcw6Y=; b=MdknPSXDmaf4NSXmv6LRSvvqVbq3oVdOAN8PtXRcEABXY3242YppnGId6qdqDZwLzP dr4ArWKy2r2GF1QD/S6/I7BkHSjnyFHPLhnJZ2Ktdvpc+AzoExBgwsDUphUuY244GMJe iCR3BnoXaB2v0rUIlH3wpwaEH3650qdntO7nkUxmGcT/vALAXrS3TByhAdSw8XeNSLFp OPdQzdaZch8YmF0IaB7mXqfWd9P+Q4Ds7gauXibmnO0PKAD5zxNcBb/CTEAu5+WlkBdN aDPbe6YcA1aZysRgyoLOePUgCaTBqJ8jRqjsyDYJfvUTN5mf3qRsHYZgqXKEL94OlQoh s3NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=T2JXZqRANkDgwoD9s9eMl08MgDzE/eGytIftSnYcw6Y=; b=XDRNU9p8VYZ/Elza/vnKhb/QQ2ImZqpv3yR2kHu6p80wK69mrOmTxdDg0AP03jBcTg IqnkVmh5g3DUDiFFgNoKdVFvgsQU796u0mgFcJicSHP/WfEPcO1bbn99CLor3ZiwpQCG 2oypaHtlgVmn28cFKjTLgfkK3kI2jjrdoIkE2TvcvGRg80cMda4LGu6EqezqhanMYr3X Y1e2HBrVVJwUOSInY8bRHzkhjMn/kvYlVkSXw23O+88lRdx70NmuHUU1v2beNLqHG8T5 hi3WAZuOo9O45GYY8VBXEqbuNuvKOJleqpJtGd5AMD5migKaUU5G74bKYonmmb5eeIln JEVg== X-Gm-Message-State: AOAM531880Pi0m86kbY7nNkaA0O/qatrCpPPL8vDGkRmIcNOk8JmM9Mm 71kHCrxB5proyf5pyPdSCOCraodq/zs= X-Google-Smtp-Source: ABdhPJzYgKR5g984GstRvTkBQc6D5zswvRv/5veZ+WT1XuNWD46n9h1Gd1vsrWP3pXIClAKpu9ZpkQ== X-Received: by 2002:a05:620a:208c:: with SMTP id e12mr17279239qka.270.1613928959678; Sun, 21 Feb 2021 09:35:59 -0800 (PST) Received: from localhost.localdomain ([181.23.89.132]) by smtp.gmail.com with ESMTPSA id o6sm9408347qtr.20.2021.02.21.09.35.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 21 Feb 2021 09:35:59 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Sun, 21 Feb 2021 14:35:12 -0300 Message-Id: <20210221173512.3070-1-jamrial@gmail.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210220205327.11515-1-jamrial@gmail.com> References: <20210220205327.11515-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2] avcodec: add a get_encoder_buffer() callback to AVCodecContext 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This callback is functionally the same as get_buffer2() is for decoders, and implements for the new encode API the functionality of the old encode API had where the user could provide their own buffers. Signed-off-by: James Almer --- Used the names Lynne suggested this time, plus a line about how the callback must be thread safe. libavcodec/avcodec.h | 45 ++++++++++++++++++++++++++++++++++++ libavcodec/codec.h | 8 ++++--- libavcodec/encode.c | 54 +++++++++++++++++++++++++++++++++++++++++++- libavcodec/encode.h | 8 +++++++ libavcodec/options.c | 1 + 5 files changed, 112 insertions(+), 4 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 7dbf083a24..e60eb16ce1 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -513,6 +513,11 @@ typedef struct AVProducerReferenceTime { */ #define AV_GET_BUFFER_FLAG_REF (1 << 0) +/** + * The encoder will keep a reference to the packet and may reuse it later. + */ +#define AV_GET_ENCODER_BUFFER_FLAG_REF (1 << 0) + struct AVCodecInternal; /** @@ -2346,6 +2351,39 @@ typedef struct AVCodecContext { * - encoding: set by user */ int export_side_data; + + /** + * This callback is called at the beginning of each packet to get a data + * buffer for it. + * + * The following field will be set in the packet before this callback is + * called: + * - size + * This callback must use the above value to calculate the required buffer size, + * which must padded by at least AV_INPUT_BUFFER_PADDING_SIZE bytes. + * + * This callback must fill the following fields in the packet: + * - data + * - buf must contain a pointer to an AVBufferRef structure. The packet's + * data pointer must be contained in it. + * See: av_buffer_create(), av_buffer_alloc(), and av_buffer_ref(). + * + * If AV_CODEC_CAP_DR1 is not set then get_encoder_buffer() must call + * avcodec_default_get_encoder_buffer() instead of providing a buffer allocated by + * some other means. + * + * If AV_GET_ENCODER_BUFFER_FLAG_REF is set in flags then the packet may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * This callback must be thread-safe, as when frame multithreading is used, it may + * be called from multiple threads simultaneously. + * + * @see avcodec_default_get_encoder_buffer() + * + * - encoding: Set by libavcodec, user can override. + * - decoding: unused + */ + int (*get_encoder_buffer)(struct AVCodecContext *s, AVPacket *pkt, int flags); } AVCodecContext; #if FF_API_CODEC_GET_SET @@ -2920,6 +2958,13 @@ void avsubtitle_free(AVSubtitle *sub); */ int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); +/** + * The default callback for AVCodecContext.get_encoder_buffer(). It is made public so + * it can be called by custom get_encoder_buffer() implementations for encoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_encoder_buffer(AVCodecContext *s, AVPacket *pkt, int flags); + /** * Modify width and height values so that they will result in a memory * buffer that is acceptable for the codec if you do not use any horizontal diff --git a/libavcodec/codec.h b/libavcodec/codec.h index 0ccbf0eb19..a679fdc9e1 100644 --- a/libavcodec/codec.h +++ b/libavcodec/codec.h @@ -43,9 +43,11 @@ */ #define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0) /** - * Codec uses get_buffer() for allocating buffers and supports custom allocators. - * If not set, it might not use get_buffer() at all or use operations that - * assume the buffer was allocated by avcodec_default_get_buffer. + * Codec uses get_buffer() or get_encoder_buffer() for allocating buffers and + * supports custom allocators. + * If not set, it might not use get_buffer() or get_encoder_buffer() at all, or + * use operations that assume the buffer was allocated by + * avcodec_default_get_buffer2 or avcodec_default_get_encoder_buffer. */ #define AV_CODEC_CAP_DR1 (1 << 1) #define AV_CODEC_CAP_TRUNCATED (1 << 3) diff --git a/libavcodec/encode.c b/libavcodec/encode.c index 282337e453..f39c8d38ce 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -56,6 +56,52 @@ int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64 return 0; } +int avcodec_default_get_encoder_buffer(AVCodecContext *avctx, AVPacket *avpkt, int flags) +{ + int ret; + + if (avpkt->data || avpkt->buf) { + av_log(avctx, AV_LOG_ERROR, "avpkt->{data,buf} != NULL in avcodec_default_get_encoder_buffer()\n"); + return AVERROR(EINVAL); + } + + ret = av_new_packet(avpkt, avpkt->size); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet of size %d\n", avpkt->size); + + return ret; +} + +int ff_get_encoder_buffer(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int flags) +{ + int ret; + + if (size < 0 || size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + return AVERROR(EINVAL); + + av_assert0(!avpkt->data && !avpkt->buf); + + avpkt->size = size; + ret = avctx->get_encoder_buffer(avctx, avpkt, flags); + if (ret < 0) + goto fail; + + if (!avpkt->data || !avpkt->buf) { + av_log(avctx, AV_LOG_ERROR, "No buffer returned by get_encoder_buffer()\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + ret = 0; +fail: + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "get_encoder_buffer() failed\n"); + av_packet_unref(avpkt); + } + + return ret; +} + /** * Pad last frame with silence. */ @@ -169,7 +215,7 @@ static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt) emms_c(); if (!ret && got_packet) { - if (avpkt->data) { + if (avpkt->data && !(avctx->codec->capabilities & AV_CODEC_CAP_DR1)) { ret = av_packet_make_refcounted(avpkt); if (ret < 0) goto end; @@ -377,6 +423,12 @@ static int compat_encode(AVCodecContext *avctx, AVPacket *avpkt, av_log(avctx, AV_LOG_WARNING, "AVFrame.width or height is not set\n"); } + if (avctx->codec->capabilities & AV_CODEC_CAP_DR1) { + av_log(avctx, AV_LOG_WARNING, "The deprecated avcodec_encode_* API does not support " + "AV_CODEC_CAP_DR1 encoders\n"); + return AVERROR(ENOSYS); + } + ret = avcodec_send_frame(avctx, frame); if (ret == AVERROR_EOF) ret = 0; diff --git a/libavcodec/encode.h b/libavcodec/encode.h index dfa9cb2d97..3192bd9e38 100644 --- a/libavcodec/encode.h +++ b/libavcodec/encode.h @@ -24,6 +24,7 @@ #include "libavutil/frame.h" #include "avcodec.h" +#include "packet.h" /** * Called by encoders to get the next frame for encoding. @@ -36,4 +37,11 @@ */ int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame); +/** + * Get a buffer for a packet. This is a wrapper around + * AVCodecContext.get_encoder_buffer() and should be used instead calling get_encoder_buffer() + * directly. + */ +int ff_get_encoder_buffer(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int flags); + #endif /* AVCODEC_ENCODE_H */ diff --git a/libavcodec/options.c b/libavcodec/options.c index 4bbf74ec7f..cd5fa6eb14 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -130,6 +130,7 @@ static int init_context_defaults(AVCodecContext *s, const AVCodec *codec) s->pkt_timebase = (AVRational){ 0, 1 }; s->get_buffer2 = avcodec_default_get_buffer2; s->get_format = avcodec_default_get_format; + s->get_encoder_buffer = avcodec_default_get_encoder_buffer; s->execute = avcodec_default_execute; s->execute2 = avcodec_default_execute2; s->sample_aspect_ratio = (AVRational){0,1};