Message ID | 20170902192703.13955-1-timo@rothenpieler.org |
---|---|
State | Accepted |
Headers | show |
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
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),
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(-)