From patchwork Sat Feb 20 20:53:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 25850 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 ED17444B02D for ; Sat, 20 Feb 2021 22:54:57 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D4EB468A67C; Sat, 20 Feb 2021 22:54:57 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qv1-f50.google.com (mail-qv1-f50.google.com [209.85.219.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5BCF3689D59 for ; Sat, 20 Feb 2021 22:54:51 +0200 (EET) Received: by mail-qv1-f50.google.com with SMTP id k8so3917614qvm.6 for ; Sat, 20 Feb 2021 12:54:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=YOgzc2aSfeoP9NhaeE5YqMtmdlaIlRTCiQEY4zJZyjE=; b=suZ0nLtukOlojiwSOU8cb5WqrVsxklgiufLtW+1C6Oj6CdJIDv0o7T9wFPXFozAUmV x63kkkDX5D4iuRGqH6r7gCqThRekZC94uTPaMVfFWSW+42Nz1ecTooqC9Qb37Pk9fppA /5i5kh4s/5v5cmxMJSqiJp6JTR9+OihMml2yA6371eXUsRyI6omD34Les6K+ExnUaImI 0JhjKNwTo5rMkXE/CiL+cEwNmx76n8Ytar1oh3zcnpJoEmMPGUdPTUP3n08SLUC+dT78 sd1jjwKNV0WIqxucP3TcK453FV+xEoY+eYNGfQrvMP909O0IwYNzjuEZbFjPgcUy5Z+Z Liiw== 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:mime-version :content-transfer-encoding; bh=YOgzc2aSfeoP9NhaeE5YqMtmdlaIlRTCiQEY4zJZyjE=; b=ek64r37E2IQEL45liOyD2punTwAbOqueMuvttyWAfqIlXIrAX0/EY/CYj1ekgIGm6u SFJI34i3NH4yHy765Sq94Sw9keU2CRHd+mdRPJmvHffoDsaO7/Sa1LveNFY5Q77uOGuz YDr6In/li2PBrZSn96obldY0XWSspFPbm0JFwMeQIUGJSjK4Ben3YtYHnOBSmFzm1MpS IbEmMcZ4jxydd23K9HPlAo9W9E4FczlNqMyK+CogTqeQdayJAmqtim32hXarTBJsxRTd wtim09yuf3jNEgYKrr/oTWnV96lkKXeqLkrwArYPact34WEHambQhlwRn0kIynavyKdE pkJw== X-Gm-Message-State: AOAM531JODqPJG28slQz3So4flTF/c8QIu6YIcUD6P/V/8zRJLtHmKut RGApOEpzmgTmmNIgAo5pyPfr6wlJbIU= X-Google-Smtp-Source: ABdhPJyxZCjxoEIVUgilnVXY8by2cx3giDhaBXf0+zVEXHLXpt0XoVwtZdfTwdELETK4BLwSWc03/w== X-Received: by 2002:a0c:b59f:: with SMTP id g31mr15029297qve.28.1613854489590; Sat, 20 Feb 2021 12:54:49 -0800 (PST) Received: from localhost.localdomain ([181.23.89.132]) by smtp.gmail.com with ESMTPSA id n4sm8204953qtl.77.2021.02.20.12.54.48 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 20 Feb 2021 12:54:49 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Sat, 20 Feb 2021 17:53:27 -0300 Message-Id: <20210220205327.11515-1-jamrial@gmail.com> X-Mailer: git-send-email 2.30.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [RFC][PATCH] avcodec: add a get_enc_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 --- As suggested by Anton, here's get_buffer() for encoders. This way, users of the new encode API can still provide their own buffers, like they could with the old API, now that it's being removed. The initial implementation of the default callback uses the existing method of simply calling av_new_packet() for it. In the future, a buffer pool could be used instead. Is AV_GET_ENC_BUFFER_FLAG_REF useful here? Is there an encoder that keeps a reference to a previous packet around? Alternative names for the callback field and public default callback function are welcome, hence it being RFC. libavcodec/avcodec.h | 42 ++++++++++++++++++++++++++++++++++ libavcodec/codec.h | 8 ++++--- libavcodec/encode.c | 54 +++++++++++++++++++++++++++++++++++++++++++- libavcodec/encode.h | 7 ++++++ libavcodec/options.c | 1 + 5 files changed, 108 insertions(+), 4 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 7dbf083a24..5b4a731e9f 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_ENC_BUFFER_FLAG_REF (1 << 0) + struct AVCodecInternal; /** @@ -2346,6 +2351,36 @@ 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 (may by zero) + * 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_enc_buffer() must call + * avcodec_default_get_enc_buffer() instead of providing a buffer allocated by + * some other means. + * + * If AV_GET_ENC_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. + * + * @see avcodec_default_get_enc_buffer() + * + * - encoding: Set by libavcodec, user can override. + * - decoding: unused + */ + int (*get_enc_buffer)(struct AVCodecContext *s, AVPacket *pkt, int flags); } AVCodecContext; #if FF_API_CODEC_GET_SET @@ -2920,6 +2955,13 @@ void avsubtitle_free(AVSubtitle *sub); */ int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); +/** + * The default callback for AVCodecContext.get_enc_buffer(). It is made public so + * it can be called by custom get_enc_buffer() implementations for encoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_enc_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..c3460e82ac 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_enc_buffer() for allocating buffers and + * supports custom allocators. + * If not set, it might not use get_buffer() or get_enc_buffer() at all, or + * use operations that assume the buffer was allocated by + * avcodec_default_get_buffer2 or avcodec_default_get_enc_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..f464ad66b2 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_enc_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_enc_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_enc_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_enc_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_enc_buffer()\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + ret = 0; +fail: + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "get_enc_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..93fc30db43 100644 --- a/libavcodec/encode.h +++ b/libavcodec/encode.h @@ -36,4 +36,11 @@ */ int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame); +/** + * Get a buffer for a packet. This is a wrapper around + * AVCodecContext.get_enc_buffer() and should be used instead calling get_encbuffer() + * directly. + */ +int ff_get_enc_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..c32d603d0c 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -129,6 +129,7 @@ static int init_context_defaults(AVCodecContext *s, const AVCodec *codec) s->framerate = (AVRational){ 0, 1 }; s->pkt_timebase = (AVRational){ 0, 1 }; s->get_buffer2 = avcodec_default_get_buffer2; + s->get_enc_buffer = avcodec_default_get_enc_buffer; s->get_format = avcodec_default_get_format; s->execute = avcodec_default_execute; s->execute2 = avcodec_default_execute2;