From 546ea79024a0406fbe1fa1c7f4cc5aa9ae02fb72 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Sun, 9 Feb 2025 00:31:04 +0100 Subject: [PATCH] Use PTS differences for _Duration props frame->duration is often just computed from the track-wide frame rate and hence unreliable. For the last frame, where no following PTS is available, the logic just matches the previous frames's duration. In theory the track's duration could be referenced instead, but the current logic matches FFMS2. --- src/avisynth.cpp | 3 +-- src/synthshared.cpp | 16 +++++++++++++--- src/synthshared.h | 2 +- src/vapoursynth.cpp | 3 +-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/avisynth.cpp b/src/avisynth.cpp index 64e99d4..3925e21 100644 --- a/src/avisynth.cpp +++ b/src/avisynth.cpp @@ -255,10 +255,9 @@ class AvisynthVideoSource : public IClip { Env->ThrowError("BestVideoSource: %s", e.what()); } - const BSVideoProperties &VP = V->GetVideoProperties(); AVSMap *Props = Env->getFramePropsRW(Dst); - SetSynthFrameProperties(Src, VP, RFF, V->GetFrameIsTFF(n, RFF), + SetSynthFrameProperties(n, Src, *V, RFF, V->GetFrameIsTFF(n, RFF), [Props, Env](const char *Name, int64_t V) { Env->propSetInt(Props, Name, V, 1); }, [Props, Env](const char *Name, double V) { Env->propSetFloat(Props, Name, V, 1); }, [Props, Env](const char *Name, const char *V, int Size, bool Utf8) { Env->propSetData(Props, Name, V, Size, 1); }); diff --git a/src/synthshared.cpp b/src/synthshared.cpp index 852d92a..a4a28a6 100644 --- a/src/synthshared.cpp +++ b/src/synthshared.cpp @@ -21,7 +21,9 @@ #include "synthshared.h" #include "VSHelper4.h" -void SetSynthFrameProperties(const std::unique_ptr &Src, const BSVideoProperties &VP, bool RFF, bool TFF, const std::function &mapSetInt, const std::function &mapSetFloat, const std::function &mapSetData) { +void SetSynthFrameProperties(int n, const std::unique_ptr &Src, const BestVideoSource &VS, bool RFF, bool TFF, const std::function &mapSetInt, const std::function &mapSetFloat, const std::function &mapSetData) { + const BSVideoProperties VP = VS.GetVideoProperties(); + // Set AR variables if (VP.SAR.Num > 0 && VP.SAR.Den > 0) { mapSetInt("_SARNum", VP.SAR.Num); @@ -49,11 +51,19 @@ void SetSynthFrameProperties(const std::unique_ptr &Src, const B mapSetInt("_FieldBased", FieldBased); mapSetInt("RepeatField", Src->RepeatPict); - // FIXME, use PTS difference between frames instead? if (Src->Duration > 0) { int64_t DurNum = VP.TimeBase.Num; int64_t DurDen = VP.TimeBase.Den; - vsh::muldivRational(&DurNum, &DurDen, Src->Duration, 1); + + int64_t Dur = Src->Duration; + if (n < VP.NumFrames - 1) { + Dur = VS.GetFrameInfo(n + 1).PTS - Src->PTS; + } else if (VP.NumFrames >= 2) { + // Assume the last frame has the same duration as the previous one, if the latter exists + Dur = Src->PTS - VS.GetFrameInfo(n - 1).PTS; + } + + vsh::muldivRational(&DurNum, &DurDen, Dur, 1); mapSetInt("_DurationNum", DurNum); mapSetInt("_DurationDen", DurDen); } diff --git a/src/synthshared.h b/src/synthshared.h index 15ac94b..5fc0107 100644 --- a/src/synthshared.h +++ b/src/synthshared.h @@ -26,6 +26,6 @@ #include #include -void SetSynthFrameProperties(const std::unique_ptr &Src, const BSVideoProperties &VP, bool RFF, bool TFF, const std::function &mapSetInt, const std::function &mapSetFloat, const std::function &mapSetData); +void SetSynthFrameProperties(int n, const std::unique_ptr &Src, const BestVideoSource &VS, bool RFF, bool TFF, const std::function &mapSetInt, const std::function &mapSetFloat, const std::function &mapSetData); #endif \ No newline at end of file diff --git a/src/vapoursynth.cpp b/src/vapoursynth.cpp index 6d3fafb..9b8b606 100644 --- a/src/vapoursynth.cpp +++ b/src/vapoursynth.cpp @@ -108,12 +108,11 @@ static const VSFrame *VS_CC BestVideoSourceGetFrame(int n, int ActivationReason, return nullptr; } - const BSVideoProperties &VP = D->V->GetVideoProperties(); VSMap *Props = vsapi->getFramePropertiesRW(Dst); if (AlphaDst) vsapi->mapConsumeFrame(Props, "_Alpha", AlphaDst, maAppend); - SetSynthFrameProperties(Src, VP, D->RFF, D->V->GetFrameIsTFF(n, D->RFF), + SetSynthFrameProperties(n, Src, *D->V, D->RFF, D->V->GetFrameIsTFF(n, D->RFF), [Props, vsapi](const char *Name, int64_t V) { vsapi->mapSetInt(Props, Name, V, maAppend); }, [Props, vsapi](const char *Name, double V) { vsapi->mapSetFloat(Props, Name, V, maAppend); }, [Props, vsapi](const char *Name, const char *V, int Size, bool Utf8) { vsapi->mapSetData(Props, Name, V, Size, Utf8 ? dtUtf8 : dtBinary, maAppend); });