> On Aug 7, 2024, at 18:18, Andreas Rheinhardt <andreas.rheinha...@outlook.com> > wrote: > > Zhao Zhili: >> From: Zhao Zhili <zhiliz...@tencent.com> >> >> Before the patch, the method to generate DTS only works with >> timebase equal to 1/fps. With timebase like 1/1000 >> >> ./ffmpeg -i foo.mp4 -an -c:v h264_nvenc -enc_time_base 1/1000 bar.mp4 >> >> pts 0 dts -3 >> pts 160 dts 37 >> pts 80 dts 77 >> pts 40 dts 117 <-- invalid >> pts 120 dts 157 >> pts 320 dts 197 >> pts 240 dts 237 >> pts 200 dts 277 <-- invalid >> pts 280 dts 317 <-- invalid >> >> The generated DTS can be larger than PTS, since it only reorder the >> input PTS and minus the number of frame delay, which doesn't take >> timebase into account. It should minus the "time" of frame delay. >> >> 9a245bd trying to fix the issue, but the implementation is incomplete, >> which only use time_base.num. Then it got reverted by ac7c265b33b. >> >> After this patch: >> >> pts 0 dts -120 >> pts 160 dts -80 >> pts 80 dts -40 >> pts 40 dts 0 >> pts 120 dts 40 >> pts 320 dts 80 >> pts 240 dts 120 >> pts 200 dts 160 >> pts 280 dts 200 > > It looks like you only have two reorder frames here, so shouldn't the > first dts be -80?
But NVENC doesn’t provide the reorder delay value. I have added a comment without changing the method to guess a maximum reorder delay. Maybe we can do better by parse the maximum reorder delay from VPS/SPS/PPS, it’s not the patch supposed to do. I do hope Nvidia to fix their SDK issues than workaround in FFmpeg. >> + >> + // This can be more than necessary, but we don't know the real reorder >> delay. >> + delay = FFMAX(ctx->encode_config.frameIntervalP - 1, 0); > >> --- >> libavcodec/nvenc.c | 62 ++++++++++++++++++++++++++++++++++++++-------- >> libavcodec/nvenc.h | 3 +++ >> 2 files changed, 55 insertions(+), 10 deletions(-) >> >> diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c >> index ab92395ed6..34448462f0 100644 >> --- a/libavcodec/nvenc.c >> +++ b/libavcodec/nvenc.c >> @@ -1893,7 +1893,8 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext >> *avctx) >> if (!ctx->frame_data_array) >> return AVERROR(ENOMEM); >> >> - ctx->timestamp_list = av_fifo_alloc2(ctx->nb_surfaces, sizeof(int64_t), >> 0); >> + ctx->timestamp_list = av_fifo_alloc2(ctx->nb_surfaces + >> ctx->encode_config.frameIntervalP, >> + sizeof(int64_t), 0); >> if (!ctx->timestamp_list) >> return AVERROR(ENOMEM); >> >> @@ -2347,26 +2348,65 @@ static inline int64_t timestamp_queue_dequeue(AVFifo >> *queue) >> return timestamp; >> } >> >> +static inline int64_t timestamp_queue_peek(AVFifo *queue, size_t index) >> +{ >> + int64_t timestamp = AV_NOPTS_VALUE; >> + av_fifo_peek(queue, ×tamp, 1, index); >> + >> + return timestamp; >> +} >> + >> static int nvenc_set_timestamp(AVCodecContext *avctx, >> NV_ENC_LOCK_BITSTREAM *params, >> AVPacket *pkt) >> { >> NvencContext *ctx = avctx->priv_data; >> + int delay; >> + int64_t delay_time; >> >> pkt->pts = params->outputTimeStamp; >> >> - if (avctx->codec_descriptor->props & AV_CODEC_PROP_REORDER) { >> -FF_DISABLE_DEPRECATION_WARNINGS >> - pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list) - >> -#if FF_API_TICKS_PER_FRAME >> - FFMAX(avctx->ticks_per_frame, 1) * >> -#endif >> - FFMAX(ctx->encode_config.frameIntervalP - 1, 0); >> -FF_ENABLE_DEPRECATION_WARNINGS >> - } else { >> + if (!(avctx->codec_descriptor->props & AV_CODEC_PROP_REORDER)) { >> pkt->dts = pkt->pts; >> + return 0; >> + } >> + >> + // This can be more than necessary, but we don't know the real reorder >> delay. >> + delay = FFMAX(ctx->encode_config.frameIntervalP - 1, 0); >> + if (ctx->output_frame_num >= delay) { >> + pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list); >> + ctx->output_frame_num++; >> + return 0; >> } >> >> + delay_time = ctx->initial_delay_time; >> + if (!delay_time) { >> + int64_t t1, t2, t3; >> + t1 = timestamp_queue_peek(ctx->timestamp_list, delay); >> + t2 = timestamp_queue_peek(ctx->timestamp_list, 0); >> + t3 = (delay > 1) ? timestamp_queue_peek(ctx->timestamp_list, 1) : >> t1; >> + >> + if (t1 != AV_NOPTS_VALUE) { >> + delay_time = t1 - t2; >> + } else if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { >> + delay_time = av_rescale_q(delay, (AVRational) >> {avctx->framerate.den, avctx->framerate.num}, >> + avctx->time_base); >> + } else if (t3 != AV_NOPTS_VALUE) { >> + delay_time = delay * (t3 - t2); >> + } else { >> + delay_time = delay; >> + } >> + ctx->initial_delay_time = delay_time; >> + } >> + >> + /* The following method is simple, but doesn't guarantee monotonic with >> VFR >> + * when delay_time isn't accurate (that is, t1 == AV_NOPTS_VALUE) >> + * >> + * dts = timestamp_queue_peek(ctx->timestamp_list, >> ctx->output_frame_num) - delay_time >> + */ >> + pkt->dts = timestamp_queue_peek(ctx->timestamp_list, 0) - delay_time * >> (delay - ctx->output_frame_num) / delay; >> + ctx->output_frame_num++; >> + >> return 0; >> } >> >> @@ -2902,4 +2942,6 @@ av_cold void ff_nvenc_encode_flush(AVCodecContext >> *avctx) >> >> nvenc_send_frame(avctx, NULL); >> av_fifo_reset2(ctx->timestamp_list); >> + ctx->output_frame_num = 0; >> + ctx->initial_delay_time = 0; >> } >> diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h >> index 09de00badc..dc7fe41951 100644 >> --- a/libavcodec/nvenc.h >> +++ b/libavcodec/nvenc.h >> @@ -206,6 +206,9 @@ typedef struct NvencContext >> AVFifo *output_surface_queue; >> AVFifo *output_surface_ready_queue; >> AVFifo *timestamp_list; >> + // This is for DTS calculating, reset after flush >> + int64_t output_frame_num; >> + int64_t initial_delay_time; >> >> NV_ENC_SEI_PAYLOAD *sei_data; >> int sei_data_size; > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".