aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorJames Almer <jamrial@gmail.com>2020-06-09 18:31:32 -0300
committerJames Almer <jamrial@gmail.com>2020-06-18 17:11:37 -0300
commit827d6fe73d2f5472c1c2128eb14fab6a4db29032 (patch)
tree7bc2bdec4590e7b4adb268e34007e42b857d2967 /libavcodec
parent71f19bf5e31ec4039ef0f9e22b157657c57e2cb9 (diff)
downloadffmpeg-827d6fe73d2f5472c1c2128eb14fab6a4db29032.tar.gz
avcodec/encode: restructure the core encoding code
This commit follows the same logic as 061a0c14bb, but for the encode API: The new public encoding API will no longer be a wrapper around the old deprecated one, and the internal API used by the encoders now consists of a single receive_packet() callback that pulls frames as required. amf encoders adapted by James Almer librav1e encoder adapted by James Almer nvidia encoders adapted by James Almer MediaFoundation encoders adapted by James Almer vaapi encoders adapted by Linjie Fu v4l2_m2m encoders adapted by Andriy Gelman Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/amfenc.c43
-rw-r--r--libavcodec/amfenc.h2
-rw-r--r--libavcodec/amfenc_h264.c1
-rw-r--r--libavcodec/amfenc_hevc.c1
-rw-r--r--libavcodec/codec.h10
-rw-r--r--libavcodec/encode.c286
-rw-r--r--libavcodec/encode.h39
-rw-r--r--libavcodec/internal.h7
-rw-r--r--libavcodec/librav1e.c51
-rw-r--r--libavcodec/mfenc.c58
-rw-r--r--libavcodec/nvenc.c72
-rw-r--r--libavcodec/nvenc.h9
-rw-r--r--libavcodec/nvenc_h264.c6
-rw-r--r--libavcodec/nvenc_hevc.c4
-rw-r--r--libavcodec/utils.c10
-rw-r--r--libavcodec/v4l2_m2m.c8
-rw-r--r--libavcodec/v4l2_m2m.h3
-rw-r--r--libavcodec/v4l2_m2m_enc.c15
-rw-r--r--libavcodec/vaapi_encode.c27
-rw-r--r--libavcodec/vaapi_encode.h3
-rw-r--r--libavcodec/vaapi_encode_h264.c1
-rw-r--r--libavcodec/vaapi_encode_h265.c1
-rw-r--r--libavcodec/vaapi_encode_mjpeg.c1
-rw-r--r--libavcodec/vaapi_encode_mpeg2.c1
-rw-r--r--libavcodec/vaapi_encode_vp8.c1
-rw-r--r--libavcodec/vaapi_encode_vp9.c1
-rw-r--r--libavcodec/version.h2
27 files changed, 443 insertions, 220 deletions
diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 876fddd2b6..da0652943d 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -33,6 +33,7 @@
#include "libavutil/time.h"
#include "amfenc.h"
+#include "encode.h"
#include "internal.h"
#if CONFIG_D3D11VA
@@ -588,17 +589,27 @@ static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffe
frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
}
-int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
{
AmfContext *ctx = avctx->priv_data;
AMFSurface *surface;
AMF_RESULT res;
int ret;
+ AMF_RESULT res_query;
+ AMFData *data = NULL;
+ AVFrame *frame = ctx->delayed_frame;
+ int block_and_wait;
if (!ctx->encoder)
return AVERROR(EINVAL);
- if (!frame) { // submit drain
+ if (!frame->buf[0]) {
+ ret = ff_encode_get_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+ }
+
+ if (!frame->buf[0]) { // submit drain
if (!ctx->eof) { // submit drain one time only
if (ctx->delayed_surface != NULL) {
ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
@@ -613,15 +624,10 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res);
}
}
- } else{
- return AVERROR_EOF;
}
- } else { // submit frame
+ } else if (!ctx->delayed_surface) { // submit frame
int hw_surface = 0;
- if (ctx->delayed_surface != NULL) {
- return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit
- }
// prepare surface from frame
switch (frame->format) {
#if CONFIG_D3D11VA
@@ -693,38 +699,23 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
break;
}
-
// submit surface
res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
if (res == AMF_INPUT_FULL) { // handle full queue
//store surface for later submission
ctx->delayed_surface = surface;
- if (surface->pVtbl->GetMemoryType(surface) == AMF_MEMORY_DX11) {
- av_frame_ref(ctx->delayed_frame, frame);
- }
} else {
+ int64_t pts = frame->pts;
surface->pVtbl->Release(surface);
AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
- if ((ret = timestamp_queue_enqueue(avctx, frame->pts)) < 0) {
+ av_frame_unref(frame);
+ if ((ret = timestamp_queue_enqueue(avctx, pts)) < 0) {
return ret;
}
-
}
}
- return 0;
-}
-int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
-{
- int ret;
- AMF_RESULT res;
- AMF_RESULT res_query;
- AmfContext *ctx = avctx->priv_data;
- AMFData *data = NULL;
- int block_and_wait;
- if (!ctx->encoder)
- return AVERROR(EINVAL);
do {
block_and_wait = 0;
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index b1361842bd..80658c6b2a 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -129,8 +129,6 @@ int ff_amf_encode_close(AVCodecContext *avctx);
/**
* Ecoding one frame - common function for all AMF encoders
*/
-
-int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame);
int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
/**
diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c
index 7f2817f115..7a8029f3b7 100644
--- a/libavcodec/amfenc_h264.c
+++ b/libavcodec/amfenc_h264.c
@@ -383,7 +383,6 @@ AVCodec ff_h264_amf_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.init = amf_encode_init_h264,
- .send_frame = ff_amf_send_frame,
.receive_packet = ff_amf_receive_packet,
.close = ff_amf_encode_close,
.priv_data_size = sizeof(AmfContext),
diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c
index 77e57d2461..8b2302f2af 100644
--- a/libavcodec/amfenc_hevc.c
+++ b/libavcodec/amfenc_hevc.c
@@ -313,7 +313,6 @@ AVCodec ff_hevc_amf_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_HEVC,
.init = amf_encode_init_hevc,
- .send_frame = ff_amf_send_frame,
.receive_packet = ff_amf_receive_packet,
.close = ff_amf_encode_close,
.priv_data_size = sizeof(AmfContext),
diff --git a/libavcodec/codec.h b/libavcodec/codec.h
index 1fda619ee7..713774a632 100644
--- a/libavcodec/codec.h
+++ b/libavcodec/codec.h
@@ -282,14 +282,10 @@ typedef struct AVCodec {
int (*decode)(struct AVCodecContext *, void *outdata, int *outdata_size, struct AVPacket *avpkt);
int (*close)(struct AVCodecContext *);
/**
- * Encode API with decoupled packet/frame dataflow. The API is the
- * same as the avcodec_ prefixed APIs (avcodec_send_frame() etc.), except
- * that:
- * - never called if the codec is closed or the wrong type,
- * - if AV_CODEC_CAP_DELAY is not set, drain frames are never sent,
- * - only one drain frame is ever passed down,
+ * Encode API with decoupled frame/packet dataflow. This function is called
+ * to get one output packet. It should call ff_encode_get_frame() to obtain
+ * input data.
*/
- int (*send_frame)(struct AVCodecContext *avctx, const struct AVFrame *frame);
int (*receive_packet)(struct AVCodecContext *avctx, struct AVPacket *avpkt);
/**
diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index b1784ed050..83602ca45b 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -26,6 +26,7 @@
#include "libavutil/samplefmt.h"
#include "avcodec.h"
+#include "encode.h"
#include "frame_thread_encoder.h"
#include "internal.h"
@@ -73,14 +74,10 @@ int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64
/**
* Pad last frame with silence.
*/
-static int pad_last_frame(AVCodecContext *s, AVFrame **dst, const AVFrame *src)
+static int pad_last_frame(AVCodecContext *s, AVFrame *frame, const AVFrame *src)
{
- AVFrame *frame = NULL;
int ret;
- if (!(frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
-
frame->format = src->format;
frame->channel_layout = src->channel_layout;
frame->channels = src->channels;
@@ -101,12 +98,10 @@ static int pad_last_frame(AVCodecContext *s, AVFrame **dst, const AVFrame *src)
s->channels, s->sample_fmt)) < 0)
goto fail;
- *dst = frame;
-
return 0;
fail:
- av_frame_free(&frame);
+ av_frame_unref(frame);
return ret;
}
@@ -177,7 +172,11 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
}
if (frame->nb_samples < avctx->frame_size) {
- ret = pad_last_frame(avctx, &padded_frame, frame);
+ if (!(padded_frame = av_frame_alloc())) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ ret = pad_last_frame(avctx, padded_frame, frame);
if (ret < 0)
goto end;
@@ -358,101 +357,252 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
return ret;
}
-static int do_encode(AVCodecContext *avctx, const AVFrame *frame, int *got_packet)
+int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+ AVCodecInternal *avci = avctx->internal;
+
+ if (avci->draining)
+ return AVERROR_EOF;
+
+ if (!avci->buffer_frame->buf[0])
+ return AVERROR(EAGAIN);
+
+ av_frame_move_ref(frame, avci->buffer_frame);
+
+ return 0;
+}
+
+static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt)
{
+ AVCodecInternal *avci = avctx->internal;
+ EncodeSimpleContext *es = &avci->es;
+ AVFrame *frame = es->in_frame;
+ int got_packet;
int ret;
- *got_packet = 0;
- av_packet_unref(avctx->internal->buffer_pkt);
- avctx->internal->buffer_pkt_valid = 0;
+ if (avci->draining_done)
+ return AVERROR_EOF;
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
- ret = avcodec_encode_video2(avctx, avctx->internal->buffer_pkt,
- frame, got_packet);
- } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
- ret = avcodec_encode_audio2(avctx, avctx->internal->buffer_pkt,
- frame, got_packet);
- } else {
- ret = AVERROR(EINVAL);
+ if (!frame->buf[0] && !avci->draining) {
+ av_frame_unref(frame);
+ ret = ff_encode_get_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+ }
+
+ if (!frame->buf[0]) {
+ if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY ||
+ (avci->frame_thread_encoder && avctx->active_thread_type & FF_THREAD_FRAME)))
+ return AVERROR_EOF;
+
+ // Flushing is signaled with a NULL frame
+ frame = NULL;
+ }
+
+ got_packet = 0;
+
+ av_assert0(avctx->codec->encode2);
+
+ if (CONFIG_FRAME_THREAD_ENCODER &&
+ avci->frame_thread_encoder && (avctx->active_thread_type & FF_THREAD_FRAME))
+ ret = ff_thread_video_encode_frame(avctx, avpkt, frame, &got_packet);
+ else {
+ ret = avctx->codec->encode2(avctx, avpkt, frame, &got_packet);
+ if (avctx->codec->type == AVMEDIA_TYPE_VIDEO && !ret && got_packet &&
+ !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
+ avpkt->pts = avpkt->dts = frame->pts;
}
- if (ret >= 0 && *got_packet) {
+ av_assert0(ret <= 0);
+
+ emms_c();
+
+ if (!ret && got_packet) {
+ if (avpkt->data) {
+ ret = av_packet_make_refcounted(avpkt);
+ if (ret < 0)
+ goto end;
+ }
+
+ if (frame && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) {
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ if (avpkt->pts == AV_NOPTS_VALUE)
+ avpkt->pts = frame->pts;
+ if (!avpkt->duration)
+ avpkt->duration = ff_samples_to_time_base(avctx,
+ frame->nb_samples);
+ }
+ }
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ /* NOTE: if we add any audio encoders which output non-keyframe packets,
+ * this needs to be moved to the encoders, but for now we can do it
+ * here to simplify things */
+ avpkt->flags |= AV_PKT_FLAG_KEY;
+ avpkt->dts = avpkt->pts;
+ }
+ }
+
+ if (avci->draining && !got_packet)
+ avci->draining_done = 1;
+
+end:
+ if (ret < 0 || !got_packet)
+ av_packet_unref(avpkt);
+
+ if (frame) {
+ if (!ret)
+ avctx->frame_number++;
+ av_frame_unref(frame);
+ }
+
+ if (got_packet)
// Encoders must always return ref-counted buffers.
// Side-data only packets have no data and can be not ref-counted.
- av_assert0(!avctx->internal->buffer_pkt->data || avctx->internal->buffer_pkt->buf);
- avctx->internal->buffer_pkt_valid = 1;
- ret = 0;
- } else {
- av_packet_unref(avctx->internal->buffer_pkt);
+ av_assert0(!avpkt->data || avpkt->buf);
+
+ return ret;
+}
+
+static int encode_simple_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
+{
+ int ret;
+
+ while (!avpkt->data && !avpkt->side_data) {
+ ret = encode_simple_internal(avctx, avpkt);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int encode_receive_packet_internal(AVCodecContext *avctx, AVPacket *avpkt)
+{
+ AVCodecInternal *avci = avctx->internal;
+ int ret;
+
+ if (avci->draining_done)
+ return AVERROR_EOF;
+
+ av_assert0(!avpkt->data && !avpkt->side_data);
+
+ if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
+ if ((avctx->flags & AV_CODEC_FLAG_PASS1) && avctx->stats_out)
+ avctx->stats_out[0] = '\0';
+ if (av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx))
+ return AVERROR(EINVAL);
}
+ if (avctx->codec->receive_packet) {
+ ret = avctx->codec->receive_packet(avctx, avpkt);
+ if (!ret)
+ // Encoders must always return ref-counted buffers.
+ // Side-data only packets have no data and can be not ref-counted.
+ av_assert0(!avpkt->data || avpkt->buf);
+ } else
+ ret = encode_simple_receive_packet(avctx, avpkt);
+
+ if (ret == AVERROR_EOF)
+ avci->draining_done = 1;
+
return ret;
}
+static int encode_send_frame_internal(AVCodecContext *avctx, const AVFrame *src)
+{
+ AVCodecInternal *avci = avctx->internal;
+ AVFrame *dst = avci->buffer_frame;
+ int ret;
+
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ /* extract audio service type metadata */
+ AVFrameSideData *sd = av_frame_get_side_data(src, AV_FRAME_DATA_AUDIO_SERVICE_TYPE);
+ if (sd && sd->size >= sizeof(enum AVAudioServiceType))
+ avctx->audio_service_type = *(enum AVAudioServiceType*)sd->data;
+
+ /* check for valid frame size */
+ if (avctx->codec->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME) {
+ if (src->nb_samples > avctx->frame_size) {
+ av_log(avctx, AV_LOG_ERROR, "more samples than frame size\n");
+ return AVERROR(EINVAL);
+ }
+ } else if (!(avctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) {
+ /* if we already got an undersized frame, that must have been the last */
+ if (avctx->internal->last_audio_frame) {
+ av_log(avctx, AV_LOG_ERROR, "frame_size (%d) was not respected for a non-last frame\n", avctx->frame_size);
+ return AVERROR(EINVAL);
+ }
+
+ if (src->nb_samples < avctx->frame_size) {
+ ret = pad_last_frame(avctx, dst, src);
+ if (ret < 0)
+ return ret;
+
+ avctx->internal->last_audio_frame = 1;
+ } else if (src->nb_samples > avctx->frame_size) {
+ av_log(avctx, AV_LOG_ERROR, "nb_samples (%d) != frame_size (%d)\n", src->nb_samples, avctx->frame_size);
+ return AVERROR(EINVAL);
+ }
+ }
+ }
+
+ if (!dst->data[0]) {
+ ret = av_frame_ref(dst, src);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int attribute_align_arg avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
{
+ AVCodecInternal *avci = avctx->internal;
+ int ret;
+
if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
return AVERROR(EINVAL);
- if (avctx->internal->draining)
+ if (avci->draining)
return AVERROR_EOF;
- if (!frame) {
- avctx->internal->draining = 1;
+ if (avci->buffer_frame->data[0])
+ return AVERROR(EAGAIN);
- if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
- return 0;
+ if (!frame) {
+ avci->draining = 1;
+ } else {
+ ret = encode_send_frame_internal(avctx, frame);
+ if (ret < 0)
+ return ret;
}
- if (avctx->codec->send_frame)
- return avctx->codec->send_frame(avctx, frame);
-
- // Emulation via old API. Do it here instead of avcodec_receive_packet, because:
- // 1. if the AVFrame is not refcounted, the copying will be much more
- // expensive than copying the packet data
- // 2. assume few users use non-refcounted AVPackets, so usually no copy is
- // needed
-
- if (avctx->internal->buffer_pkt_valid)
- return AVERROR(EAGAIN);
+ if (!avci->buffer_pkt->data && !avci->buffer_pkt->side_data) {
+ ret = encode_receive_packet_internal(avctx, avci->buffer_pkt);
+ if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ return ret;
+ }
- return do_encode(avctx, frame, &(int){0});
+ return 0;
}
int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
{
+ AVCodecInternal *avci = avctx->internal;
+ int ret;
+
av_packet_unref(avpkt);
if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
return AVERROR(EINVAL);
- if (avctx->codec->receive_packet) {
- int ret;
- if (avctx->internal->draining && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
- return AVERROR_EOF;
- ret = avctx->codec->receive_packet(avctx, avpkt);
- if (!ret)
- // Encoders must always return ref-counted buffers.
- // Side-data only packets have no data and can be not ref-counted.
- av_assert0(!avpkt->data || avpkt->buf);
- return ret;
- }
-
- // Emulation via old API.
-
- if (!avctx->internal->buffer_pkt_valid) {
- int got_packet;
- int ret;
- if (!avctx->internal->draining)
- return AVERROR(EAGAIN);
- ret = do_encode(avctx, NULL, &got_packet);
+ if (avci->buffer_pkt->data || avci->buffer_pkt->side_data) {
+ av_packet_move_ref(avpkt, avci->buffer_pkt);
+ } else {
+ ret = encode_receive_packet_internal(avctx, avpkt);
if (ret < 0)
return ret;
- if (ret >= 0 && !got_packet)
- return AVERROR_EOF;
}
- av_packet_move_ref(avpkt, avctx->internal->buffer_pkt);
- avctx->internal->buffer_pkt_valid = 0;
return 0;
}
diff --git a/libavcodec/encode.h b/libavcodec/encode.h
new file mode 100644
index 0000000000..dfa9cb2d97
--- /dev/null
+++ b/libavcodec/encode.h
@@ -0,0 +1,39 @@
+/*
+ * generic encoding-related code
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_ENCODE_H
+#define AVCODEC_ENCODE_H
+
+#include "libavutil/frame.h"
+
+#include "avcodec.h"
+
+/**
+ * Called by encoders to get the next frame for encoding.
+ *
+ * @param frame An empty frame to be filled with data.
+ * @return 0 if a new reference has been successfully written to frame
+ * AVERROR(EAGAIN) if no data is currently available
+ * AVERROR_EOF if end of stream has been reached, so no more data
+ * will be available
+ */
+int ff_encode_get_frame(AVCodecContext *avctx, AVFrame *frame);
+
+#endif /* AVCODEC_ENCODE_H */
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 0a72a0e372..78f0e444fa 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -113,6 +113,10 @@ typedef struct DecodeSimpleContext {
AVFrame *out_frame;
} DecodeSimpleContext;
+typedef struct EncodeSimpleContext {
+ AVFrame *in_frame;
+} EncodeSimpleContext;
+
typedef struct AVCodecInternal {
/**
* Whether the parent AVCodecContext is a copy of the context which had
@@ -151,6 +155,8 @@ typedef struct AVCodecInternal {
void *frame_thread_encoder;
+ EncodeSimpleContext es;
+
/**
* Number of audio samples to skip at the start of the next decoded frame
*/
@@ -170,7 +176,6 @@ typedef struct AVCodecInternal {
* buffers for using new encode/decode API through legacy API
*/
AVPacket *buffer_pkt;
- int buffer_pkt_valid; // encoding: packet without data can be valid
AVFrame *buffer_frame;
int draining_done;
int compat_decode_warned;
diff --git a/libavcodec/librav1e.c b/libavcodec/librav1e.c
index 6f9b4cce4c..e9b82a724a 100644
--- a/libavcodec/librav1e.c
+++ b/libavcodec/librav1e.c
@@ -30,12 +30,15 @@
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
+#include "encode.h"
#include "internal.h"
typedef struct librav1eContext {
const AVClass *class;
RaContext *ctx;
+ AVFrame *frame;
+ RaFrame *rframe;
AVBSFContext *bsf;
uint8_t *pass_data;
@@ -165,7 +168,12 @@ static av_cold int librav1e_encode_close(AVCodecContext *avctx)
rav1e_context_unref(ctx->ctx);
ctx->ctx = NULL;
}
+ if (ctx->rframe) {
+ rav1e_frame_unref(ctx->rframe);
+ ctx->rframe = NULL;
+ }
+ av_frame_free(&ctx->frame);
av_bsf_free(&ctx->bsf);
av_freep(&ctx->pass_data);
@@ -180,6 +188,10 @@ static av_cold int librav1e_encode_init(AVCodecContext *avctx)
int rret;
int ret = 0;
+ ctx->frame = av_frame_alloc();
+ if (!ctx->frame)
+ return AVERROR(ENOMEM);
+
cfg = rav1e_config_default();
if (!cfg) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate rav1e config.\n");
@@ -416,18 +428,27 @@ end:
return ret;
}
-static int librav1e_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+static int librav1e_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
{
librav1eContext *ctx = avctx->priv_data;
- RaFrame *rframe = NULL;
+ RaFrame *rframe = ctx->rframe;
+ RaPacket *rpkt = NULL;
int ret;
- if (frame) {
+ if (!rframe) {
+ AVFrame *frame = ctx->frame;
+
+ ret = ff_encode_get_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+
+ if (frame->buf[0]) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
rframe = rav1e_frame_new(ctx->ctx);
if (!rframe) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate new rav1e frame.\n");
+ av_frame_unref(frame);
return AVERROR(ENOMEM);
}
@@ -438,17 +459,23 @@ static int librav1e_send_frame(AVCodecContext *avctx, const AVFrame *frame)
(frame->height >> shift) * frame->linesize[i],
frame->linesize[i], bytes);
}
+ av_frame_unref(frame);
+ }
}
ret = rav1e_send_frame(ctx->ctx, rframe);
if (rframe)
+ if (ret == RA_ENCODER_STATUS_ENOUGH_DATA) {
+ ctx->rframe = rframe; /* Queue is full. Store the RaFrame to retry next call */
+ } else {
rav1e_frame_unref(rframe); /* No need to unref if flushing. */
+ ctx->rframe = NULL;
+ }
switch (ret) {
case RA_ENCODER_STATUS_SUCCESS:
- break;
case RA_ENCODER_STATUS_ENOUGH_DATA:
- return AVERROR(EAGAIN);
+ break;
case RA_ENCODER_STATUS_FAILURE:
av_log(avctx, AV_LOG_ERROR, "Could not send frame: %s\n", rav1e_status_to_str(ret));
return AVERROR_EXTERNAL;
@@ -457,15 +484,6 @@ static int librav1e_send_frame(AVCodecContext *avctx, const AVFrame *frame)
return AVERROR_UNKNOWN;
}
- return 0;
-}
-
-static int librav1e_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
-{
- librav1eContext *ctx = avctx->priv_data;
- RaPacket *rpkt = NULL;
- int ret;
-
retry:
if (avctx->flags & AV_CODEC_FLAG_PASS1) {
@@ -490,9 +508,7 @@ retry:
}
return AVERROR_EOF;
case RA_ENCODER_STATUS_ENCODED:
- if (avctx->internal->draining)
- goto retry;
- return AVERROR(EAGAIN);
+ goto retry;
case RA_ENCODER_STATUS_NEED_MORE_DATA:
if (avctx->internal->draining) {
av_log(avctx, AV_LOG_ERROR, "Unexpected error when receiving packet after EOF.\n");
@@ -592,7 +608,6 @@ AVCodec ff_librav1e_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_AV1,
.init = librav1e_encode_init,
- .send_frame = librav1e_send_frame,
.receive_packet = librav1e_receive_packet,
.close = librav1e_encode_close,
.priv_data_size = sizeof(librav1eContext),
diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c
index ee3c164e69..7fdc7af330 100644
--- a/libavcodec/mfenc.c
+++ b/libavcodec/mfenc.c
@@ -22,6 +22,7 @@
#define _WIN32_WINNT 0x0602
#endif
+#include "encode.h"
#include "mf_utils.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
@@ -30,6 +31,7 @@
typedef struct MFContext {
AVClass *av_class;
+ AVFrame *frame;
int is_video, is_audio;
GUID main_subtype;
IMFTransform *mft;
@@ -398,26 +400,6 @@ static int mf_send_sample(AVCodecContext *avctx, IMFSample *sample)
return 0;
}
-static int mf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
-{
- MFContext *c = avctx->priv_data;
- int ret;
- IMFSample *sample = NULL;
- if (frame) {
- sample = mf_avframe_to_sample(avctx, frame);
- if (!sample)
- return AVERROR(ENOMEM);
- if (c->is_video && c->codec_api) {
- if (frame->pict_type == AV_PICTURE_TYPE_I || !c->sample_sent)
- ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncVideoForceKeyFrame, FF_VAL_VT_UI4(1));
- }
- }
- ret = mf_send_sample(avctx, sample);
- if (sample)
- IMFSample_Release(sample);
- return ret;
-}
-
static int mf_receive_sample(AVCodecContext *avctx, IMFSample **out_sample)
{
MFContext *c = avctx->priv_data;
@@ -500,9 +482,36 @@ static int mf_receive_sample(AVCodecContext *avctx, IMFSample **out_sample)
static int mf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
{
- IMFSample *sample;
+ MFContext *c = avctx->priv_data;
+ IMFSample *sample = NULL;
int ret;
+ if (!c->frame->buf[0]) {
+ ret = ff_encode_get_frame(avctx, c->frame);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+ }
+
+ if (c->frame->buf[0]) {
+ sample = mf_avframe_to_sample(avctx, c->frame);
+ if (!sample) {
+ av_frame_unref(c->frame);
+ return AVERROR(ENOMEM);
+ }
+ if (c->is_video && c->codec_api) {
+ if (c->frame->pict_type == AV_PICTURE_TYPE_I || !c->sample_sent)
+ ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncVideoForceKeyFrame, FF_VAL_VT_UI4(1));
+ }
+ }
+
+ ret = mf_send_sample(avctx, sample);
+ if (sample)
+ IMFSample_Release(sample);
+ if (ret != AVERROR(EAGAIN))
+ av_frame_unref(c->frame);
+ if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ return ret;
+
ret = mf_receive_sample(avctx, &sample);
if (ret < 0)
return ret;
@@ -1034,6 +1043,10 @@ static int mf_init(AVCodecContext *avctx)
const CLSID *subtype = ff_codec_to_mf_subtype(avctx->codec_id);
int use_hw = 0;
+ c->frame = av_frame_alloc();
+ if (!c->frame)
+ return AVERROR(ENOMEM);
+
c->is_audio = avctx->codec_type == AVMEDIA_TYPE_AUDIO;
c->is_video = !c->is_audio;
c->reorder_delay = AV_NOPTS_VALUE;
@@ -1122,6 +1135,8 @@ static int mf_close(AVCodecContext *avctx)
ff_free_mf(&c->mft);
+ av_frame_free(&c->frame);
+
av_freep(&avctx->extradata);
avctx->extradata_size = 0;
@@ -1146,7 +1161,6 @@ static int mf_close(AVCodecContext *avctx)
.priv_data_size = sizeof(MFContext), \
.init = mf_init, \
.close = mf_close, \
- .send_frame = mf_send_frame, \
.receive_packet = mf_receive_packet, \
EXTRA \
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, \
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index e269c716a4..22c19f3597 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -30,6 +30,7 @@
#include "libavutil/avassert.h"
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
+#include "encode.h"
#include "internal.h"
#include "packet_internal.h"
@@ -1509,6 +1510,8 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
av_freep(&ctx->surfaces);
ctx->nb_surfaces = 0;
+ av_frame_free(&ctx->frame);
+
if (ctx->nvencoder) {
p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
@@ -1562,6 +1565,10 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx)
ctx->data_pix_fmt = avctx->pix_fmt;
}
+ ctx->frame = av_frame_alloc();
+ if (!ctx->frame)
+ return AVERROR(ENOMEM);
+
if ((ret = nvenc_load_libraries(avctx)) < 0)
return ret;
@@ -1879,9 +1886,7 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
goto error;
}
- res = pkt->data ?
- ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes, lock_params.bitstreamSizeInBytes) :
- av_new_packet(pkt, lock_params.bitstreamSizeInBytes);
+ res = av_new_packet(pkt, lock_params.bitstreamSizeInBytes);
if (res < 0) {
p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
@@ -2067,7 +2072,7 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
}
}
-int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
{
NVENCSTATUS nv_status;
NvencSurface *tmp_out_surf, *in_surf;
@@ -2085,15 +2090,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder)
return AVERROR(EINVAL);
- if (ctx->encoder_flushing) {
- if (avctx->internal->draining)
- return AVERROR_EOF;
-
- ctx->encoder_flushing = 0;
- av_fifo_reset(ctx->timestamp_list);
- }
-
- if (frame) {
+ if (frame && frame->buf[0]) {
in_surf = get_free_frame(ctx);
if (!in_surf)
return AVERROR(EAGAIN);
@@ -2153,7 +2150,6 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data);
} else {
pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
- ctx->encoder_flushing = 1;
}
res = nvenc_push_context(avctx);
@@ -2171,7 +2167,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
nv_status != NV_ENC_ERR_NEED_MORE_INPUT)
return nvenc_print_error(avctx, nv_status, "EncodePicture failed!");
- if (frame) {
+ if (frame && frame->buf[0]) {
av_fifo_generic_write(ctx->output_surface_queue, &in_surf, sizeof(in_surf), NULL);
timestamp_queue_enqueue(ctx->timestamp_list, frame->pts);
}
@@ -2194,10 +2190,25 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
NvencContext *ctx = avctx->priv_data;
+ AVFrame *frame = ctx->frame;
+
if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder)
return AVERROR(EINVAL);
- if (output_ready(avctx, ctx->encoder_flushing)) {
+ if (!frame->buf[0]) {
+ res = ff_encode_get_frame(avctx, frame);
+ if (res < 0 && res != AVERROR_EOF)
+ return res;
+ }
+
+ res = nvenc_send_frame(avctx, frame);
+ if (res < 0) {
+ if (res != AVERROR(EAGAIN))
+ return res;
+ } else
+ av_frame_unref(frame);
+
+ if (output_ready(avctx, avctx->internal->draining)) {
av_fifo_generic_read(ctx->output_surface_ready_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
res = nvenc_push_context(avctx);
@@ -2214,7 +2225,7 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
return res;
av_fifo_generic_write(ctx->unused_surface_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
- } else if (ctx->encoder_flushing) {
+ } else if (avctx->internal->draining) {
return AVERROR_EOF;
} else {
return AVERROR(EAGAIN);
@@ -2223,31 +2234,10 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
return 0;
}
-int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *frame, int *got_packet)
+av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx)
{
NvencContext *ctx = avctx->priv_data;
- int res;
-
- if (!ctx->encoder_flushing) {
- res = ff_nvenc_send_frame(avctx, frame);
- if (res < 0)
- return res;
- }
-
- res = ff_nvenc_receive_packet(avctx, pkt);
- if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
- *got_packet = 0;
- } else if (res < 0) {
- return res;
- } else {
- *got_packet = 1;
- }
- return 0;
-}
-
-av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx)
-{
- ff_nvenc_send_frame(avctx, NULL);
+ nvenc_send_frame(avctx, NULL);
+ av_fifo_reset(ctx->timestamp_list);
}
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index 7a415a4835..007721aa66 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -138,6 +138,8 @@ typedef struct NvencContext
CUstream cu_stream;
ID3D11Device *d3d11_device;
+ AVFrame *frame;
+
int nb_surfaces;
NvencSurface *surfaces;
@@ -146,8 +148,6 @@ typedef struct NvencContext
AVFifoBuffer *output_surface_ready_queue;
AVFifoBuffer *timestamp_list;
- int encoder_flushing;
-
struct {
void *ptr;
int ptr_index;
@@ -203,13 +203,8 @@ int ff_nvenc_encode_init(AVCodecContext *avctx);
int ff_nvenc_encode_close(AVCodecContext *avctx);
-int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame);
-
int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt);
-int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *frame, int *got_packet);
-
void ff_nvenc_encode_flush(AVCodecContext *avctx);
extern const enum AVPixelFormat ff_nvenc_pix_fmts[];
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index c877cf4a30..e973e9ee92 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -180,9 +180,7 @@ AVCodec ff_nvenc_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.init = nvenc_old_init,
- .send_frame = ff_nvenc_send_frame,
.receive_packet = ff_nvenc_receive_packet,
- .encode2 = ff_nvenc_encode_frame,
.close = ff_nvenc_encode_close,
.flush = ff_nvenc_encode_flush,
.priv_data_size = sizeof(NvencContext),
@@ -212,9 +210,7 @@ AVCodec ff_nvenc_h264_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.init = nvenc_old_init,
- .send_frame = ff_nvenc_send_frame,
.receive_packet = ff_nvenc_receive_packet,
- .encode2 = ff_nvenc_encode_frame,
.close = ff_nvenc_encode_close,
.flush = ff_nvenc_encode_flush,
.priv_data_size = sizeof(NvencContext),
@@ -244,9 +240,7 @@ AVCodec ff_h264_nvenc_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.init = ff_nvenc_encode_init,
- .send_frame = ff_nvenc_send_frame,
.receive_packet = ff_nvenc_receive_packet,
- .encode2 = ff_nvenc_encode_frame,
.close = ff_nvenc_encode_close,
.flush = ff_nvenc_encode_flush,
.priv_data_size = sizeof(NvencContext),
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index 7f12b56a46..434dc6679e 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -168,9 +168,7 @@ AVCodec ff_nvenc_hevc_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_HEVC,
.init = nvenc_old_init,
- .send_frame = ff_nvenc_send_frame,
.receive_packet = ff_nvenc_receive_packet,
- .encode2 = ff_nvenc_encode_frame,
.close = ff_nvenc_encode_close,
.priv_data_size = sizeof(NvencContext),
.priv_class = &nvenc_hevc_class,
@@ -198,9 +196,7 @@ AVCodec ff_hevc_nvenc_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_HEVC,
.init = ff_nvenc_encode_init,
- .send_frame = ff_nvenc_send_frame,
.receive_packet = ff_nvenc_receive_packet,
- .encode2 = ff_nvenc_encode_frame,
.close = ff_nvenc_encode_close,
.flush = ff_nvenc_encode_flush,
.priv_data_size = sizeof(NvencContext),
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index a9c69e30dd..0e256eabb1 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -93,7 +93,7 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size)
int av_codec_is_encoder(const AVCodec *codec)
{
- return codec && (codec->encode_sub || codec->encode2 ||codec->send_frame);
+ return codec && (codec->encode_sub || codec->encode2 || codec->receive_packet);
}
int av_codec_is_decoder(const AVCodec *codec)
@@ -587,11 +587,13 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
avci->compat_decode_frame = av_frame_alloc();
avci->buffer_frame = av_frame_alloc();
avci->buffer_pkt = av_packet_alloc();
+ avci->es.in_frame = av_frame_alloc();
avci->ds.in_pkt = av_packet_alloc();
avci->last_pkt_props = av_packet_alloc();
if (!avci->to_free || !avci->compat_decode_frame ||
!avci->buffer_frame || !avci->buffer_pkt ||
- !avci->ds.in_pkt || !avci->last_pkt_props) {
+ !avci->es.in_frame || !avci->ds.in_pkt ||
+ !avci->last_pkt_props) {
ret = AVERROR(ENOMEM);
goto free_and_end;
}
@@ -1045,6 +1047,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
av_packet_free(&avci->last_pkt_props);
av_packet_free(&avci->ds.in_pkt);
+ av_frame_free(&avci->es.in_frame);
av_bsf_free(&avci->bsf);
av_buffer_unref(&avci->pool);
@@ -1080,8 +1083,8 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
av_frame_unref(avci->buffer_frame);
av_frame_unref(avci->compat_decode_frame);
av_packet_unref(avci->buffer_pkt);
- avci->buffer_pkt_valid = 0;
+ av_frame_unref(avci->es.in_frame);
av_packet_unref(avci->ds.in_pkt);
if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
@@ -1143,6 +1146,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
av_packet_free(&avctx->internal->last_pkt_props);
av_packet_free(&avctx->internal->ds.in_pkt);
+ av_frame_free(&avctx->internal->es.in_frame);
av_buffer_unref(&avctx->internal->pool);
diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
index e48b3a8ccf..d8d872ea09 100644
--- a/libavcodec/v4l2_m2m.c
+++ b/libavcodec/v4l2_m2m.c
@@ -329,6 +329,7 @@ static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
sem_destroy(&s->refsync);
close(s->fd);
+ av_frame_free(&s->frame);
av_free(s);
}
@@ -415,5 +416,12 @@ int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
priv->context->self_ref = priv->context_ref;
priv->context->fd = -1;
+ priv->context->frame = av_frame_alloc();
+ if (!priv->context->frame) {
+ av_buffer_unref(&priv->context_ref);
+ *s = NULL; /* freed when unreferencing context_ref */
+ return AVERROR(ENOMEM);
+ }
+
return 0;
}
diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
index 456281f48c..b67b216331 100644
--- a/libavcodec/v4l2_m2m.h
+++ b/libavcodec/v4l2_m2m.h
@@ -58,6 +58,9 @@ typedef struct V4L2m2mContext {
int draining;
AVPacket buf_pkt;
+ /* Reference to a frame. Only used during encoding */
+ AVFrame *frame;
+
/* Reference to self; only valid while codec is active. */
AVBufferRef *self_ref;
diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
index 32321f392f..56df4286ad 100644
--- a/libavcodec/v4l2_m2m_enc.c
+++ b/libavcodec/v4l2_m2m_enc.c
@@ -24,6 +24,7 @@
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <search.h>
+#include "encode.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/internal.h"
#include "libavutil/pixdesc.h"
@@ -288,11 +289,24 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
V4L2Context *const capture = &s->capture;
V4L2Context *const output = &s->output;
+ AVFrame *frame = s->frame;
int ret;
if (s->draining)
goto dequeue;
+ ret = ff_encode_get_frame(avctx, frame);
+ if (ret < 0 && ret != AVERROR_EOF)
+ return ret;
+
+ if (ret == AVERROR_EOF)
+ frame = NULL;
+
+ ret = v4l2_send_frame(avctx, frame);
+ av_frame_unref(frame);
+ if (ret < 0)
+ return ret;
+
if (!output->streamon) {
ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON);
if (ret) {
@@ -411,7 +425,6 @@ static const AVCodecDefault v4l2_m2m_defaults[] = {
.priv_data_size = sizeof(V4L2m2mPriv), \
.priv_class = &v4l2_m2m_ ## NAME ##_enc_class, \
.init = v4l2_encode_init, \
- .send_frame = v4l2_send_frame, \
.receive_packet = v4l2_receive_packet, \
.close = v4l2_encode_close, \
.defaults = v4l2_m2m_defaults, \
diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index cb05ebd774..e39db20200 100644
--- a/libavcodec/vaapi_encode.c
+++ b/libavcodec/vaapi_encode.c
@@ -25,6 +25,7 @@
#include "libavutil/pixdesc.h"
#include "vaapi_encode.h"
+#include "encode.h"
#include "avcodec.h"
const AVCodecHWConfigInternal *ff_vaapi_encode_hw_configs[] = {
@@ -1043,7 +1044,7 @@ static int vaapi_encode_check_frame(AVCodecContext *avctx,
return 0;
}
-int ff_vaapi_encode_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+static int vaapi_encode_send_frame(AVCodecContext *avctx, AVFrame *frame)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
VAAPIEncodePicture *pic;
@@ -1066,9 +1067,6 @@ int ff_vaapi_encode_send_frame(AVCodecContext *avctx, const AVFrame *frame)
err = AVERROR(ENOMEM);
goto fail;
}
- err = av_frame_ref(pic->input_image, frame);
- if (err < 0)
- goto fail;
if (ctx->input_order == 0 || frame->pict_type == AV_PICTURE_TYPE_I)
pic->force_idr = 1;
@@ -1076,6 +1074,8 @@ int ff_vaapi_encode_send_frame(AVCodecContext *avctx, const AVFrame *frame)
pic->input_surface = (VASurfaceID)(uintptr_t)frame->data[3];
pic->pts = frame->pts;
+ av_frame_move_ref(pic->input_image, frame);
+
if (ctx->input_order == 0)
ctx->first_pts = pic->pts;
if (ctx->input_order == ctx->decode_delay)
@@ -1114,8 +1114,20 @@ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
VAAPIEncodePicture *pic;
+ AVFrame *frame = ctx->frame;
int err;
+ err = ff_encode_get_frame(avctx, frame);
+ if (err < 0 && err != AVERROR_EOF)
+ return err;
+
+ if (err == AVERROR_EOF)
+ frame = NULL;
+
+ err = vaapi_encode_send_frame(avctx, frame);
+ if (err < 0)
+ return err;
+
if (!ctx->pic_start) {
if (ctx->end_of_stream)
return AVERROR_EOF;
@@ -2214,6 +2226,11 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
VAStatus vas;
int err;
+ ctx->frame = av_frame_alloc();
+ if (!ctx->frame) {
+ return AVERROR(ENOMEM);
+ }
+
if (!avctx->hw_frames_ctx) {
av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is "
"required to associate the encoding device.\n");
@@ -2391,6 +2408,8 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
ctx->va_config = VA_INVALID_ID;
}
+ av_frame_free(&ctx->frame);
+
av_freep(&ctx->codec_sequence_params);
av_freep(&ctx->codec_picture_params);
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index 1329f6428f..85d2a8f616 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -328,6 +328,8 @@ typedef struct VAAPIEncodeContext {
// If the driver does not support ROI then warn the first time we
// encounter a frame with ROI side data.
int roi_warned;
+
+ AVFrame *frame;
} VAAPIEncodeContext;
enum {
@@ -419,7 +421,6 @@ typedef struct VAAPIEncodeType {
} VAAPIEncodeType;
-int ff_vaapi_encode_send_frame(AVCodecContext *avctx, const AVFrame *frame);
int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt);
int ff_vaapi_encode_init(AVCodecContext *avctx);
diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
index e195650ef7..b8d9c7b507 100644
--- a/libavcodec/vaapi_encode_h264.c
+++ b/libavcodec/vaapi_encode_h264.c
@@ -1351,7 +1351,6 @@ AVCodec ff_h264_vaapi_encoder = {
.id = AV_CODEC_ID_H264,
.priv_data_size = sizeof(VAAPIEncodeH264Context),
.init = &vaapi_encode_h264_init,
- .send_frame = &ff_vaapi_encode_send_frame,
.receive_packet = &ff_vaapi_encode_receive_packet,
.close = &vaapi_encode_h264_close,
.priv_class = &vaapi_encode_h264_class,
diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
index 92e0510911..c42d51592c 100644
--- a/libavcodec/vaapi_encode_h265.c
+++ b/libavcodec/vaapi_encode_h265.c
@@ -1287,7 +1287,6 @@ AVCodec ff_hevc_vaapi_encoder = {
.id = AV_CODEC_ID_HEVC,
.priv_data_size = sizeof(VAAPIEncodeH265Context),
.init = &vaapi_encode_h265_init,
- .send_frame = &ff_vaapi_encode_send_frame,
.receive_packet = &ff_vaapi_encode_receive_packet,
.close = &vaapi_encode_h265_close,
.priv_class = &vaapi_encode_h265_class,
diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c
index 9f9ed811a4..6974ab2cad 100644
--- a/libavcodec/vaapi_encode_mjpeg.c
+++ b/libavcodec/vaapi_encode_mjpeg.c
@@ -559,7 +559,6 @@ AVCodec ff_mjpeg_vaapi_encoder = {
.id = AV_CODEC_ID_MJPEG,
.priv_data_size = sizeof(VAAPIEncodeMJPEGContext),
.init = &vaapi_encode_mjpeg_init,
- .send_frame = &ff_vaapi_encode_send_frame,
.receive_packet = &ff_vaapi_encode_receive_packet,
.close = &vaapi_encode_mjpeg_close,
.priv_class = &vaapi_encode_mjpeg_class,
diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c
index 02c76552ef..1dcc84d75c 100644
--- a/libavcodec/vaapi_encode_mpeg2.c
+++ b/libavcodec/vaapi_encode_mpeg2.c
@@ -697,7 +697,6 @@ AVCodec ff_mpeg2_vaapi_encoder = {
.id = AV_CODEC_ID_MPEG2VIDEO,
.priv_data_size = sizeof(VAAPIEncodeMPEG2Context),
.init = &vaapi_encode_mpeg2_init,
- .send_frame = &ff_vaapi_encode_send_frame,
.receive_packet = &ff_vaapi_encode_receive_packet,
.close = &vaapi_encode_mpeg2_close,
.priv_class = &vaapi_encode_mpeg2_class,
diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c
index cff926baae..51039fa19a 100644
--- a/libavcodec/vaapi_encode_vp8.c
+++ b/libavcodec/vaapi_encode_vp8.c
@@ -252,7 +252,6 @@ AVCodec ff_vp8_vaapi_encoder = {
.id = AV_CODEC_ID_VP8,
.priv_data_size = sizeof(VAAPIEncodeVP8Context),
.init = &vaapi_encode_vp8_init,
- .send_frame = &ff_vaapi_encode_send_frame,
.receive_packet = &ff_vaapi_encode_receive_packet,
.close = &ff_vaapi_encode_close,
.priv_class = &vaapi_encode_vp8_class,
diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c
index 8514b85991..4f3b55ed2d 100644
--- a/libavcodec/vaapi_encode_vp9.c
+++ b/libavcodec/vaapi_encode_vp9.c
@@ -286,7 +286,6 @@ AVCodec ff_vp9_vaapi_encoder = {
.id = AV_CODEC_ID_VP9,
.priv_data_size = sizeof(VAAPIEncodeVP9Context),
.init = &vaapi_encode_vp9_init,
- .send_frame = &ff_vaapi_encode_send_frame,
.receive_packet = &ff_vaapi_encode_receive_packet,
.close = &ff_vaapi_encode_close,
.priv_class = &vaapi_encode_vp9_class,
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 60c0f2460d..03593026b3 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 58
-#define LIBAVCODEC_VERSION_MINOR 92
+#define LIBAVCODEC_VERSION_MINOR 93
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \