[FFmpeg-devel] avcodec/nvenc: migrate to new encode API
Commit Message
Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
---
libavcodec/nvenc.c | 65 ++++++++++++++++++++++++++++++++++++++++---------
libavcodec/nvenc.h | 6 +++++
libavcodec/nvenc_h264.c | 6 +++++
libavcodec/nvenc_hevc.c | 4 +++
4 files changed, 70 insertions(+), 11 deletions(-)
Comments
On Sat, 2 Sep 2017 21:27:03 +0200
Timo Rothenpieler <timo@rothenpieler.org> wrote:
> Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
> ---
> libavcodec/nvenc.c | 65
> ++++++++++++++++++++++++++++++++++++++++---------
> libavcodec/nvenc.h | 6 +++++ libavcodec/nvenc_h264.c | 6 +++++
> libavcodec/nvenc_hevc.c | 4 +++
> 4 files changed, 70 insertions(+), 11 deletions(-)
>
> diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
> index 744e5e0e01..b54cb1275b 100644
> --- a/libavcodec/nvenc.c
> +++ b/libavcodec/nvenc.c
> @@ -1807,8 +1807,7 @@ static int output_ready(AVCodecContext *avctx,
> int flush) return (nb_ready > 0) && (nb_ready + nb_pending >=
> ctx->async_depth); }
>
> -int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> - const AVFrame *frame, int *got_packet)
> +int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> {
> NVENCSTATUS nv_status;
> CUresult cu_res;
> @@ -1823,12 +1822,16 @@ int ff_nvenc_encode_frame(AVCodecContext
> *avctx, AVPacket *pkt, NV_ENC_PIC_PARAMS pic_params = { 0 };
> pic_params.version = NV_ENC_PIC_PARAMS_VER;
>
> + if (!ctx->cu_context || !ctx->nvencoder)
> + return AVERROR(EINVAL);
> +
> + if (ctx->encoder_flushing)
> + return AVERROR_EOF;
> +
> if (frame) {
> inSurf = get_free_frame(ctx);
> - if (!inSurf) {
> - av_log(avctx, AV_LOG_ERROR, "No free surfaces\n");
> - return AVERROR_BUG;
> - }
> + if (!inSurf)
> + return AVERROR(EAGAIN);
>
> cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);
> if (cu_res != CUDA_SUCCESS) {
> @@ -1876,6 +1878,7 @@ int ff_nvenc_encode_frame(AVCodecContext
> *avctx, AVPacket *pkt, nvenc_codec_specific_pic_params(avctx,
> &pic_params); } else {
> pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
> + ctx->encoder_flushing = 1;
> }
>
> cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);
> @@ -1914,7 +1917,23 @@ int ff_nvenc_encode_frame(AVCodecContext
> *avctx, AVPacket *pkt, }
> }
>
> - if (output_ready(avctx, !frame)) {
> + return 0;
> +}
> +
> +int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
> +{
> + CUresult cu_res;
> + CUcontext dummy;
> + NvencSurface *tmpoutsurf;
You can remove tmpoutsurf in ff_nvenc_send_frame
> + int res;
> +
> + NvencContext *ctx = avctx->priv_data;
> + NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
> +
> + if (!ctx->cu_context || !ctx->nvencoder)
> + return AVERROR(EINVAL);
> +
> + if (output_ready(avctx, ctx->encoder_flushing)) {
> av_fifo_generic_read(ctx->output_surface_ready_queue,
> &tmpoutsurf, sizeof(tmpoutsurf), NULL);
> cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);
> @@ -1935,10 +1954,34 @@ int ff_nvenc_encode_frame(AVCodecContext
> *avctx, AVPacket *pkt, return res;
>
> av_fifo_generic_write(ctx->unused_surface_queue,
> &tmpoutsurf, sizeof(tmpoutsurf), NULL); -
> - *got_packet = 1;
> + } else if (ctx->encoder_flushing) {
> + return AVERROR_EOF;
> } else {
> + return AVERROR(EAGAIN);
> + }
> +
> + return 0;
> +}
> +
> +int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> + const AVFrame *frame, int *got_packet)
> +{
> + 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;
> diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
> index 2c682275da..afb93cc22c 100644
> --- a/libavcodec/nvenc.h
> +++ b/libavcodec/nvenc.h
> @@ -116,6 +116,8 @@ typedef struct NvencContext
> AVFifoBuffer *output_surface_ready_queue;
> AVFifoBuffer *timestamp_list;
>
> + int encoder_flushing;
> +
> struct {
> CUdeviceptr ptr;
> NV_ENC_REGISTERED_PTR regptr;
> @@ -169,6 +171,10 @@ 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);
>
> diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
> index 9adbe9f909..c3b4bac749 100644
> --- a/libavcodec/nvenc_h264.c
> +++ b/libavcodec/nvenc_h264.c
> @@ -164,6 +164,8 @@ 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,
> .priv_data_size = sizeof(NvencContext),
> @@ -190,6 +192,8 @@ 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,
> .priv_data_size = sizeof(NvencContext),
> @@ -216,6 +220,8 @@ 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,
> .priv_data_size = sizeof(NvencContext),
> diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
> index 81da9d222d..89e8c3e53a 100644
> --- a/libavcodec/nvenc_hevc.c
> +++ b/libavcodec/nvenc_hevc.c
> @@ -153,6 +153,8 @@ 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),
> @@ -178,6 +180,8 @@ 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,
> .priv_data_size = sizeof(NvencContext),
Otherwise looks good.
--phil
>> +int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
>> +{
>> + CUresult cu_res;
>> + CUcontext dummy;
>> + NvencSurface *tmpoutsurf;
>
> You can remove tmpoutsurf in ff_nvenc_send_frame
But it's used in it? At the very end, to move the frames between queues.
On Wed, 6 Sep 2017 18:14:17 +0200
Timo Rothenpieler <timo@rothenpieler.org> wrote:
> >> +int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
> >> +{
> >> + CUresult cu_res;
> >> + CUcontext dummy;
> >> + NvencSurface *tmpoutsurf;
> >
> > You can remove tmpoutsurf in ff_nvenc_send_frame
>
> But it's used in it? At the very end, to move the frames between
> queues.
>
Yes, I mis-read that. Ship it.
--phil
Am 06.09.2017 um 23:07 schrieb Philip Langdale:
> On Wed, 6 Sep 2017 18:14:17 +0200
> Timo Rothenpieler <timo@rothenpieler.org> wrote:
>
>>>> +int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
>>>> +{
>>>> + CUresult cu_res;
>>>> + CUcontext dummy;
>>>> + NvencSurface *tmpoutsurf;
>>>
>>> You can remove tmpoutsurf in ff_nvenc_send_frame
>>
>> But it's used in it? At the very end, to move the frames between
>> queues.
>>
>
> Yes, I mis-read that. Ship it.
applied
@@ -1807,8 +1807,7 @@ static int output_ready(AVCodecContext *avctx, int flush)
return (nb_ready > 0) && (nb_ready + nb_pending >= ctx->async_depth);
}
-int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *frame, int *got_packet)
+int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
{
NVENCSTATUS nv_status;
CUresult cu_res;
@@ -1823,12 +1822,16 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
NV_ENC_PIC_PARAMS pic_params = { 0 };
pic_params.version = NV_ENC_PIC_PARAMS_VER;
+ if (!ctx->cu_context || !ctx->nvencoder)
+ return AVERROR(EINVAL);
+
+ if (ctx->encoder_flushing)
+ return AVERROR_EOF;
+
if (frame) {
inSurf = get_free_frame(ctx);
- if (!inSurf) {
- av_log(avctx, AV_LOG_ERROR, "No free surfaces\n");
- return AVERROR_BUG;
- }
+ if (!inSurf)
+ return AVERROR(EAGAIN);
cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);
if (cu_res != CUDA_SUCCESS) {
@@ -1876,6 +1878,7 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
nvenc_codec_specific_pic_params(avctx, &pic_params);
} else {
pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
+ ctx->encoder_flushing = 1;
}
cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);
@@ -1914,7 +1917,23 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
}
- if (output_ready(avctx, !frame)) {
+ return 0;
+}
+
+int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
+{
+ CUresult cu_res;
+ CUcontext dummy;
+ NvencSurface *tmpoutsurf;
+ int res;
+
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+
+ if (!ctx->cu_context || !ctx->nvencoder)
+ return AVERROR(EINVAL);
+
+ if (output_ready(avctx, ctx->encoder_flushing)) {
av_fifo_generic_read(ctx->output_surface_ready_queue, &tmpoutsurf, sizeof(tmpoutsurf), NULL);
cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);
@@ -1935,10 +1954,34 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return res;
av_fifo_generic_write(ctx->unused_surface_queue, &tmpoutsurf, sizeof(tmpoutsurf), NULL);
-
- *got_packet = 1;
+ } else if (ctx->encoder_flushing) {
+ return AVERROR_EOF;
} else {
+ return AVERROR(EAGAIN);
+ }
+
+ return 0;
+}
+
+int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ 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;
@@ -116,6 +116,8 @@ typedef struct NvencContext
AVFifoBuffer *output_surface_ready_queue;
AVFifoBuffer *timestamp_list;
+ int encoder_flushing;
+
struct {
CUdeviceptr ptr;
NV_ENC_REGISTERED_PTR regptr;
@@ -169,6 +171,10 @@ 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);
@@ -164,6 +164,8 @@ 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,
.priv_data_size = sizeof(NvencContext),
@@ -190,6 +192,8 @@ 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,
.priv_data_size = sizeof(NvencContext),
@@ -216,6 +220,8 @@ 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,
.priv_data_size = sizeof(NvencContext),
@@ -153,6 +153,8 @@ 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),
@@ -178,6 +180,8 @@ 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,
.priv_data_size = sizeof(NvencContext),