diff --git a/Util/FFmpeg/FFmpegNativeEncoder.cs b/Util/FFmpeg/FFmpegNativeEncoder.cs index 70ec1d4..da8a20e 100644 --- a/Util/FFmpeg/FFmpegNativeEncoder.cs +++ b/Util/FFmpeg/FFmpegNativeEncoder.cs @@ -723,6 +723,16 @@ namespace ADOFAIRenderer.Util.FFmpeg if (ffmpeg.avcodec_parameters_from_context(_pVideoStream->codecpar, _pCodecContext) < 0) throw new Exception("Failed to copy codec parameters to stream."); + // Stream time base: unit of the timestamps stored in the container. + // Set to the codec time base (1 / framerate) so that every frame interval is a whole number of ticks. + // When it is left unset, the muxer uses 1/90000, in which the interval of rates such as + // 59.94 fps (1501.5 ticks), 23.976 fps (3753.75 ticks) or 165 fps (545.45 ticks) is not an integer, + // and the frame durations alternate between two values. + // The muxer may still adjust the value in avformat_write_header (e.g. mp4 scales it to at least 10000); + // packet timestamps are rescaled to the final value in SendFrameAndWritePackets. + // Reference: https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/mux.c (init_muxer: default 1/90000) + _pVideoStream->time_base = _pCodecContext->time_base; + // ── Step 4.5 (Optional): Initialize audio stream ── // If EncoderSettings.Audio is set, add audio stream. if (_settings.Audio.HasValue)