Skip to content

Commit

Permalink
Use PTS differences for _Duration props
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
arch1t3cht committed Feb 16, 2025
1 parent eef4d1d commit 6e90a1f
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 13 deletions.
3 changes: 1 addition & 2 deletions src/avisynth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); });
Expand Down
28 changes: 20 additions & 8 deletions src/synthshared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
#include "synthshared.h"
#include "VSHelper4.h"

void SetSynthFrameProperties(const std::unique_ptr<BestVideoFrame> &Src, const BSVideoProperties &VP, bool RFF, bool TFF, const std::function<void(const char *, int64_t)> &mapSetInt, const std::function<void(const char *, double)> &mapSetFloat, const std::function<void(const char *, const char *, int, bool)> &mapSetData) {
#include <libavutil/avutil.h>

void SetSynthFrameProperties(int n, const std::unique_ptr<BestVideoFrame> &Src, const BestVideoSource &VS, bool RFF, bool TFF, const std::function<void(const char *, int64_t)> &mapSetInt, const std::function<void(const char *, double)> &mapSetFloat, const std::function<void(const char *, const char *, int, bool)> &mapSetData) {
const BSVideoProperties VP = VS.GetVideoProperties();

// Set AR variables
if (VP.SAR.Num > 0 && VP.SAR.Den > 0) {
mapSetInt("_SARNum", VP.SAR.Num);
Expand Down Expand Up @@ -49,14 +53,22 @@ void SetSynthFrameProperties(const std::unique_ptr<BestVideoFrame> &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);
Expand Down
2 changes: 1 addition & 1 deletion src/synthshared.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
#include <functional>
#include <cstdint>

void SetSynthFrameProperties(const std::unique_ptr<BestVideoFrame> &Src, const BSVideoProperties &VP, bool RFF, bool TFF, const std::function<void(const char *, int64_t)> &mapSetInt, const std::function<void(const char *, double)> &mapSetFloat, const std::function<void(const char *, const char *, int, bool)> &mapSetData);
void SetSynthFrameProperties(int n, const std::unique_ptr<BestVideoFrame> &Src, const BestVideoSource &VS, bool RFF, bool TFF, const std::function<void(const char *, int64_t)> &mapSetInt, const std::function<void(const char *, double)> &mapSetFloat, const std::function<void(const char *, const char *, int, bool)> &mapSetData);

#endif
3 changes: 1 addition & 2 deletions src/vapoursynth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); });
Expand Down

0 comments on commit 6e90a1f

Please sign in to comment.