[FFmpeg-devel] [PATCH v2] avcodec/nvenc: fix flushing for encoder-reuse
Jai Luthra
me at jailuthra.in
Fri Jul 16 20:23:46 EEST 2021
On Fri, Jul 16, 2021, at 10:06 PM, Timo Rothenpieler wrote:
-- snip --
> Can you explain the logic this follows some more? I'm quite confused
> what exactly changed, and how it broke this.
> How do you trigger a flush, if calling flush does nothing?
Since https://github.com/ffmpeg/ffmpeg/commit/3ea7057677 it was possible to flush nvenc buffers without sending a NULL frame like:
// trigger ff_nvenc_encode_flush which will send a NULL frame internally
// this doesn't set avctx->internal->draining
avcodec_flush_buffers(encoder)
// get remaining packets out of the buffer
while ... {
avcodec_receive_packet(encoder, &pkt)
}
// whenever next segment comes in, reuse encoder without closing & re-opening
avcodec_send_frame(encoder, frame)
But after the recent API changes [1] if someone tries to fetch packets after calling avcodec_flush_buffers() they won't receive any and hit EAGAIN.
As the user ran out of frames to encode, no frame is present at avctx->internal->buffer_frame - and avctx->internal->draining is unset because the user didn't want to send a NULL frame. So ff_encode_get_frame returns EAGAIN, which is what the user gets without these changes:
> > @@ -2384,8 +2390,11 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
> >
> > if (!frame->buf[0]) {
> > res = ff_encode_get_frame(avctx, frame);
> > - if (res < 0 && res != AVERROR_EOF)
> > + if (res == AVERROR_EOF || (ctx->encoder_flushing && res == AVERROR(EAGAIN))) {
> > + // flushing mode, continue to send packets
> > + } else if (res < 0) {
> > return res;
> > + }
> > }
----
> >
> > av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx)
> > {
> > - NvencContext *ctx = avctx->priv_data;
> > -
> > nvenc_send_frame(avctx, NULL);
> > - av_fifo_reset(ctx->timestamp_list);
> > }
>
> Is it really correct for this to do absolutely nothing now?
It's still sending the NULL frame internally - which will mark encoder_flushing as 1 here:
> > @@ -2335,6 +2340,7 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> > nvenc_codec_specific_pic_params(avctx, &pic_params, ctx->sei_data, sei_count);
> > } else {
> > pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
> > + ctx->encoder_flushing = 1;
We don't wanna cleanup ctx->timestamp_list until the user has retrieved all packets from the buffer after triggering a flush.
[1]: https://github.com/ffmpeg/ffmpeg/commit/827d6fe73d#diff-ba8b555333cbe9c4d768147d8a7abb152281257770aa314cc057a31f43460fec
More information about the ffmpeg-devel
mailing list