diff mbox

[FFmpeg-devel] avcodec/nvenc: migrate to new encode API

Message ID 20170902192703.13955-1-timo@rothenpieler.org
State New
Headers show

Commit Message

Timo Rothenpieler Sept. 2, 2017, 7:27 p.m. UTC
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

Philip Langdale Sept. 6, 2017, 3:14 p.m. UTC | #1
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
Timo Rothenpieler Sept. 6, 2017, 4:14 p.m. UTC | #2
>> +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.
Philip Langdale Sept. 6, 2017, 9:07 p.m. UTC | #3
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
Timo Rothenpieler Sept. 7, 2017, 10:41 a.m. UTC | #4
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
diff mbox

Patch

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;
+    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),