From 6e90a1f15d6a7df7bac585cde6b589db49a8dbe3 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. When the duration cannot be reliably computed from PTS values (like on the last frame or when frames have NOPTS), leave _Duration unset. That way, the caller can decide whether or how to guess values if necessary. --- src/avisynth.cpp | 3 +-- src/synthshared.cpp | 28 ++++++++++++++++++++-------- src/synthshared.h | 2 +- src/vapoursynth.cpp | 3 +-- 4 files changed, 23 insertions(+), 13 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..7c70add 100644 --- a/src/synthshared.cpp +++ b/src/synthshared.cpp @@ -21,7 +21,11 @@ #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) { +#include + +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,14 +53,22 @@ 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); - mapSetInt("_DurationNum", DurNum); - mapSetInt("_DurationDen", DurDen); + if (n < VP.NumFrames - 1) { + int64_t NextPTS = VS.GetFrameInfo(n + 1).PTS; + + // Leave _Duration unset when it can't be computed reliably, let callers decide + // whether or how to guess values. + if (Src->PTS != AV_NOPTS_VALUE && NextPTS != AV_NOPTS_VALUE && NextPTS > Src->PTS) { + int64_t DurNum = VP.TimeBase.Num; + int64_t DurDen = VP.TimeBase.Den; + + vsh::muldivRational(&DurNum, &DurDen, NextPTS - Src->PTS, 1); + mapSetInt("_DurationNum", DurNum); + mapSetInt("_DurationDen", DurDen); + } } + // FIXME Use Src->Duration or the track's duration for the last frame? + // These are how you'd compute the last frame's duration, but they're not always accurate. } mapSetInt("TopFieldFirst", TFF); 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); });