0.2.66 - End Credits improvements / Gateway: 0.1.47 - End credits redesign
This commit is contained in:
@@ -38,6 +38,27 @@ const (
|
||||
// primary guard against answering on noise, and it is set high because the cost of a
|
||||
// wrong marker is somebody losing the end of an episode.
|
||||
minSeparation = 0.18
|
||||
|
||||
// onsetFraction is how credit-like a frame has to be, relative to the established roll,
|
||||
// to count as already part of it.
|
||||
//
|
||||
// The split itself lands where the credits are *established*, because the sustain window
|
||||
// after it has to clear creditLikeFloor on average — and credits usually fade in, so the
|
||||
// first second or two of the fade scores below that floor and pushes the split forward.
|
||||
// Measured against real media the gap is two to three seconds, which is visible: the roll
|
||||
// has plainly begun before the picture moves.
|
||||
//
|
||||
// So the split is walked backwards through the fade to the first frame that is already
|
||||
// mostly credit-like. Two fifths is deliberately generous — this is looking for the start
|
||||
// of a ramp, not for more credits — and it is a fraction of the established level rather
|
||||
// than an absolute, because a roll over a bright background never reaches the same score
|
||||
// as one over black and would otherwise never be walked back at all.
|
||||
onsetFraction = 0.4
|
||||
|
||||
// onsetBackoffMs bounds that walk. A fade is a second or two; anything walking further is
|
||||
// no longer following one, and the bound is what stops a gradual dimming at the end of a
|
||||
// scene dragging the marker back into the programme.
|
||||
onsetBackoffMs = 4000
|
||||
)
|
||||
|
||||
// VisualDetector implements Detector over the ffmpeg sampler.
|
||||
@@ -195,7 +216,46 @@ func findTransition(frames []frameStats, interval time.Duration) (int, float64,
|
||||
}
|
||||
bestIndex, bestSeparation, found = split, separation, true
|
||||
}
|
||||
return bestIndex, bestSeparation, found
|
||||
if !found {
|
||||
return 0, 0, false
|
||||
}
|
||||
// The separation is reported for the split that earned it, never for the walked-back
|
||||
// frame: confidence is a statement about how clearly the transition was found, and
|
||||
// recomputing it over a fade would report the answer as weaker for having been improved.
|
||||
return backOffToOnset(scores, bestIndex, segmentMean(bestIndex, min(bestIndex+sustain, len(scores))), interval),
|
||||
bestSeparation, true
|
||||
}
|
||||
|
||||
// backOffToOnset walks a split backwards through the credits' fade-in.
|
||||
//
|
||||
// Pure, bounded, and it can only ever move the marker earlier — which is the direction that
|
||||
// needs the care, so both bounds matter: it stops at the first frame that is not already
|
||||
// mostly credit-like, and it never travels further than onsetBackoffMs. On a hard cut from
|
||||
// programme to credits the preceding frame scores near zero and the walk stops immediately,
|
||||
// which is correct: there is no fade to find and the split was already right.
|
||||
func backOffToOnset(scores []float64, split int, established float64, interval time.Duration) int {
|
||||
if split <= 0 || established <= 0 || interval <= 0 {
|
||||
return split
|
||||
}
|
||||
limit := int(float64(onsetBackoffMs) / float64(interval.Milliseconds()))
|
||||
if limit < 1 {
|
||||
// A sampling interval coarser than the whole allowance cannot resolve a fade at all.
|
||||
// The coarse pass is this case, and it is the one whose answer the fine pass replaces.
|
||||
return split
|
||||
}
|
||||
floor := onsetFraction * established
|
||||
earliest := split - limit
|
||||
if earliest < 0 {
|
||||
earliest = 0
|
||||
}
|
||||
onset := split
|
||||
for index := split - 1; index >= earliest; index-- {
|
||||
if scores[index] < floor {
|
||||
break
|
||||
}
|
||||
onset = index
|
||||
}
|
||||
return onset
|
||||
}
|
||||
|
||||
// visualConfidence maps separation onto a score.
|
||||
|
||||
Reference in New Issue
Block a user