#include "libavutil/avassert.h"
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
+#include "encode.h"
#include "internal.h"
+#include "packet_internal.h"
#define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, dl_fn->cuda_dl, x)
AV_PIX_FMT_NONE
};
+const AVCodecHWConfigInternal *ff_nvenc_hw_configs[] = {
+ HW_CONFIG_ENCODER_FRAMES(CUDA, CUDA),
+ HW_CONFIG_ENCODER_DEVICE(NONE, CUDA),
+#if CONFIG_D3D11VA
+ HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA),
+ HW_CONFIG_ENCODER_DEVICE(NONE, D3D11VA),
+#endif
+ NULL,
+};
+
#define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \
pix_fmt == AV_PIX_FMT_P016 || \
pix_fmt == AV_PIX_FMT_YUV444P16)
if (ctx->zerolatency)
ctx->encode_config.rcParams.zeroReorderDelay = 1;
- if (ctx->quality)
- {
+ if (ctx->quality) {
//convert from float to fixed point 8.8
int tmp_quality = (int)(ctx->quality * 256.0f);
ctx->encode_config.rcParams.targetQuality = (uint8_t)(tmp_quality >> 8);
ctx->encode_config.rcParams.targetQualityLSB = (uint8_t)(tmp_quality & 0xff);
+
+ av_log(avctx, AV_LOG_VERBOSE, "CQ(%d) mode enabled.\n", tmp_quality);
+
+ //CQ mode shall discard avg bitrate & honor max bitrate;
+ ctx->encode_config.rcParams.averageBitRate = avctx->bit_rate = 0;
+ ctx->encode_config.rcParams.maxBitRate = avctx->rc_max_rate;
}
}
ctx->init_encode_params.darHeight = dh;
ctx->init_encode_params.darWidth = dw;
- ctx->init_encode_params.frameRateNum = avctx->time_base.den;
- ctx->init_encode_params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
+ if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
+ ctx->init_encode_params.frameRateNum = avctx->framerate.num;
+ ctx->init_encode_params.frameRateDen = avctx->framerate.den;
+ } else {
+ ctx->init_encode_params.frameRateNum = avctx->time_base.den;
+ ctx->init_encode_params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
+ }
ctx->init_encode_params.enableEncodeAsync = 0;
ctx->init_encode_params.enablePTD = 1;
ctx->encode_config.gopLength = 1;
}
- ctx->initial_pts[0] = AV_NOPTS_VALUE;
- ctx->initial_pts[1] = AV_NOPTS_VALUE;
-
nvenc_recalc_surfaces(avctx);
nvenc_setup_rate_control(avctx);
av_freep(&ctx->surfaces);
ctx->nb_surfaces = 0;
+ av_frame_free(&ctx->frame);
+
if (ctx->nvencoder) {
p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
ctx->data_pix_fmt = avctx->pix_fmt;
}
+ ctx->frame = av_frame_alloc();
+ if (!ctx->frame)
+ return AVERROR(ENOMEM);
+
if ((ret = nvenc_load_libraries(avctx)) < 0)
return ret;
NvencContext *ctx = avctx->priv_data;
pkt->pts = params->outputTimeStamp;
-
- /* generate the first dts by linearly extrapolating the
- * first two pts values to the past */
- if (avctx->max_b_frames > 0 && !ctx->first_packet_output &&
- ctx->initial_pts[1] != AV_NOPTS_VALUE) {
- int64_t ts0 = ctx->initial_pts[0], ts1 = ctx->initial_pts[1];
- int64_t delta;
-
- if ((ts0 < 0 && ts1 > INT64_MAX + ts0) ||
- (ts0 > 0 && ts1 < INT64_MIN + ts0))
- return AVERROR(ERANGE);
- delta = ts1 - ts0;
-
- if ((delta < 0 && ts0 > INT64_MAX + delta) ||
- (delta > 0 && ts0 < INT64_MIN + delta))
- return AVERROR(ERANGE);
- pkt->dts = ts0 - delta;
-
- ctx->first_packet_output = 1;
- return 0;
- }
-
pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list);
+ pkt->dts -= FFMAX(avctx->max_b_frames, 0) * FFMIN(avctx->ticks_per_frame, 1);
+
return 0;
}
goto error;
}
- if (res = ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes,0)) {
+ res = av_new_packet(pkt, lock_params.bitstreamSizeInBytes);
+
+ if (res < 0) {
p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
goto error;
}
NvencContext *ctx = avctx->priv_data;
int nb_ready, nb_pending;
- /* when B-frames are enabled, we wait for two initial timestamps to
- * calculate the first dts */
- if (!flush && avctx->max_b_frames > 0 &&
- (ctx->initial_pts[0] == AV_NOPTS_VALUE || ctx->initial_pts[1] == AV_NOPTS_VALUE))
- return 0;
-
nb_ready = av_fifo_size(ctx->output_surface_ready_queue) / sizeof(NvencSurface*);
nb_pending = av_fifo_size(ctx->output_surface_queue) / sizeof(NvencSurface*);
if (flush)
}
}
-int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
+static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
{
NVENCSTATUS nv_status;
NvencSurface *tmp_out_surf, *in_surf;
if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder)
return AVERROR(EINVAL);
- if (ctx->encoder_flushing) {
- if (avctx->internal->draining)
- return AVERROR_EOF;
-
- ctx->encoder_flushing = 0;
- ctx->first_packet_output = 0;
- ctx->initial_pts[0] = AV_NOPTS_VALUE;
- ctx->initial_pts[1] = AV_NOPTS_VALUE;
- av_fifo_reset(ctx->timestamp_list);
- }
-
- if (frame) {
+ if (frame && frame->buf[0]) {
in_surf = get_free_frame(ctx);
if (!in_surf)
return AVERROR(EAGAIN);
nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data);
} else {
pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
- ctx->encoder_flushing = 1;
}
res = nvenc_push_context(avctx);
nv_status != NV_ENC_ERR_NEED_MORE_INPUT)
return nvenc_print_error(avctx, nv_status, "EncodePicture failed!");
- if (frame) {
+ if (frame && frame->buf[0]) {
av_fifo_generic_write(ctx->output_surface_queue, &in_surf, sizeof(in_surf), NULL);
timestamp_queue_enqueue(ctx->timestamp_list, frame->pts);
-
- if (ctx->initial_pts[0] == AV_NOPTS_VALUE)
- ctx->initial_pts[0] = frame->pts;
- else if (ctx->initial_pts[1] == AV_NOPTS_VALUE)
- ctx->initial_pts[1] = frame->pts;
}
/* all the pending buffers are now ready for output */
NvencContext *ctx = avctx->priv_data;
+ AVFrame *frame = ctx->frame;
+
if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder)
return AVERROR(EINVAL);
- if (output_ready(avctx, ctx->encoder_flushing)) {
+ if (!frame->buf[0]) {
+ res = ff_encode_get_frame(avctx, frame);
+ if (res < 0 && res != AVERROR_EOF)
+ return res;
+ }
+
+ res = nvenc_send_frame(avctx, frame);
+ if (res < 0) {
+ if (res != AVERROR(EAGAIN))
+ return res;
+ } else
+ av_frame_unref(frame);
+
+ if (output_ready(avctx, avctx->internal->draining)) {
av_fifo_generic_read(ctx->output_surface_ready_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
res = nvenc_push_context(avctx);
return res;
av_fifo_generic_write(ctx->unused_surface_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
- } else if (ctx->encoder_flushing) {
+ } else if (avctx->internal->draining) {
return AVERROR_EOF;
} else {
return AVERROR(EAGAIN);
return 0;
}
-int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *frame, int *got_packet)
+av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx)
{
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;
+ nvenc_send_frame(avctx, NULL);
+ av_fifo_reset(ctx->timestamp_list);
}