mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
avcodec/nvenc: handle frame durations and AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE
This commit is contained in:
parent
d341895a08
commit
868af7d7a4
@ -962,6 +962,10 @@ static av_cold int nvenc_recalc_surfaces(AVCodecContext *avctx)
|
||||
ctx->nb_surfaces = FFMAX(1, FFMIN(MAX_REGISTERED_FRAMES, ctx->nb_surfaces));
|
||||
ctx->async_depth = FFMIN(ctx->async_depth, ctx->nb_surfaces - 1);
|
||||
|
||||
// Output in the worst case will only start when the surface buffer is completely full.
|
||||
// Hence we need to keep at least the max amount of surfaces plus the max reorder delay around.
|
||||
ctx->frame_data_array_nb = ctx->nb_surfaces + ctx->encode_config.frameIntervalP - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1750,6 +1754,10 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx)
|
||||
if (!ctx->surfaces)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ctx->frame_data_array = av_calloc(ctx->frame_data_array_nb, sizeof(*ctx->frame_data_array));
|
||||
if (!ctx->frame_data_array)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ctx->timestamp_list = av_fifo_alloc2(ctx->nb_surfaces, sizeof(int64_t), 0);
|
||||
if (!ctx->timestamp_list)
|
||||
return AVERROR(ENOMEM);
|
||||
@ -1840,6 +1848,12 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
|
||||
av_fifo_freep2(&ctx->output_surface_queue);
|
||||
av_fifo_freep2(&ctx->unused_surface_queue);
|
||||
|
||||
if (ctx->frame_data_array) {
|
||||
for (i = 0; i < ctx->nb_surfaces; i++)
|
||||
av_buffer_unref(&ctx->frame_data_array[i].frame_opaque_ref);
|
||||
av_freep(&ctx->frame_data_array);
|
||||
}
|
||||
|
||||
if (ctx->surfaces && (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11)) {
|
||||
for (i = 0; i < ctx->nb_registered_frames; i++) {
|
||||
if (ctx->registered_frames[i].mapped)
|
||||
@ -2211,6 +2225,65 @@ static int nvenc_set_timestamp(AVCodecContext *avctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvenc_store_frame_data(AVCodecContext *avctx, NV_ENC_PIC_PARAMS *pic_params, const AVFrame *frame)
|
||||
{
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
int res = 0;
|
||||
|
||||
int idx = ctx->frame_data_array_pos;
|
||||
NvencFrameData *frame_data = &ctx->frame_data_array[idx];
|
||||
|
||||
// in case the encoder got reconfigured, there might be leftovers
|
||||
av_buffer_unref(&frame_data->frame_opaque_ref);
|
||||
|
||||
if (frame && frame->opaque_ref && avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
|
||||
frame_data->frame_opaque_ref = av_buffer_ref(frame->opaque_ref);
|
||||
if (!frame_data->frame_opaque_ref)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
frame_data->duration = frame->duration;
|
||||
frame_data->frame_opaque = frame->opaque;
|
||||
|
||||
#if FF_API_REORDERED_OPAQUE
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
frame_data->reordered_opaque = frame->reordered_opaque;
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
ctx->frame_data_array_pos = (ctx->frame_data_array_pos + 1) % ctx->frame_data_array_nb;
|
||||
pic_params->inputDuration = idx;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int nvenc_retrieve_frame_data(AVCodecContext *avctx, NV_ENC_LOCK_BITSTREAM *lock_params, AVPacket *pkt)
|
||||
{
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
int res = 0;
|
||||
|
||||
int idx = lock_params->outputDuration;
|
||||
NvencFrameData *frame_data = &ctx->frame_data_array[idx];
|
||||
|
||||
pkt->duration = frame_data->duration;
|
||||
|
||||
#if FF_API_REORDERED_OPAQUE
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
avctx->reordered_opaque = frame_data->reordered_opaque;
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
|
||||
pkt->opaque = frame_data->frame_opaque;
|
||||
pkt->opaque_ref = frame_data->frame_opaque_ref;
|
||||
frame_data->frame_opaque_ref = NULL;
|
||||
}
|
||||
|
||||
av_buffer_unref(&frame_data->frame_opaque_ref);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSurface *tmpoutsurf)
|
||||
{
|
||||
NvencContext *ctx = avctx->priv_data;
|
||||
@ -2297,6 +2370,10 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
|
||||
if (res < 0)
|
||||
goto error2;
|
||||
|
||||
res = nvenc_retrieve_frame_data(avctx, &lock_params, pkt);
|
||||
if (res < 0)
|
||||
goto error2;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@ -2592,6 +2669,10 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
|
||||
sei_count = res;
|
||||
}
|
||||
|
||||
res = nvenc_store_frame_data(avctx, &pic_params, frame);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
nvenc_codec_specific_pic_params(avctx, &pic_params, ctx->sei_data, sei_count);
|
||||
} else {
|
||||
pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
|
||||
|
@ -31,6 +31,7 @@ typedef void ID3D11Device;
|
||||
#include <ffnvcodec/nvEncodeAPI.h>
|
||||
|
||||
#include "compat/cuda/dynlink_loader.h"
|
||||
#include "libavutil/buffer.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "hwconfig.h"
|
||||
@ -90,6 +91,18 @@ typedef struct NvencSurface
|
||||
NV_ENC_BUFFER_FORMAT format;
|
||||
} NvencSurface;
|
||||
|
||||
typedef struct NvencFrameData
|
||||
{
|
||||
int64_t duration;
|
||||
|
||||
#if FF_API_REORDERED_OPAQUE
|
||||
int64_t reordered_opaque;
|
||||
#endif
|
||||
|
||||
void *frame_opaque;
|
||||
AVBufferRef *frame_opaque_ref;
|
||||
} NvencFrameData;
|
||||
|
||||
typedef struct NvencDynLoadFunctions
|
||||
{
|
||||
CudaFunctions *cuda_dl;
|
||||
@ -168,6 +181,10 @@ typedef struct NvencContext
|
||||
int nb_surfaces;
|
||||
NvencSurface *surfaces;
|
||||
|
||||
NvencFrameData *frame_data_array;
|
||||
int frame_data_array_nb;
|
||||
int frame_data_array_pos;
|
||||
|
||||
AVFifo *unused_surface_queue;
|
||||
AVFifo *output_surface_queue;
|
||||
AVFifo *output_surface_ready_queue;
|
||||
|
@ -181,7 +181,8 @@ const FFCodec ff_av1_nvenc_encoder = {
|
||||
.defaults = defaults,
|
||||
.p.pix_fmts = ff_nvenc_pix_fmts,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1,
|
||||
AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 |
|
||||
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
|
||||
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
|
||||
FF_CODEC_CAP_INIT_CLEANUP,
|
||||
.p.wrapper_name = "nvenc",
|
||||
|
@ -232,7 +232,8 @@ const FFCodec ff_h264_nvenc_encoder = {
|
||||
.p.priv_class = &h264_nvenc_class,
|
||||
.defaults = defaults,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1,
|
||||
AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 |
|
||||
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
|
||||
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
|
||||
FF_CODEC_CAP_INIT_CLEANUP,
|
||||
.p.pix_fmts = ff_nvenc_pix_fmts,
|
||||
|
@ -214,7 +214,8 @@ const FFCodec ff_hevc_nvenc_encoder = {
|
||||
.defaults = defaults,
|
||||
.p.pix_fmts = ff_nvenc_pix_fmts,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1,
|
||||
AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 |
|
||||
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
|
||||
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
|
||||
FF_CODEC_CAP_INIT_CLEANUP,
|
||||
.p.wrapper_name = "nvenc",
|
||||
|
Loading…
x
Reference in New Issue
Block a user