mirror of
https://github.com/kerberos-io/agent.git
synced 2026-08-23 15:08:32 +00:00
Track keyframe gap to prevent flush cascades
Add LastKeyframeGapMs to MP4 state and update fragment-flush logic to consider the previous keyframe gap before forcing a fragment boundary. Previously any unexpectedly short keyframe gap (< MinNormalGOPMs) would force a flush, which could cascade on streams that legitimately emit short GOPs. Now we only force a flush when the current gap is short and the prior gap was healthy (or unset), and we record the current gap for future checks. Also refactor the check to use a local gap variable and preserve the existing log message.
This commit is contained in:
@@ -66,6 +66,7 @@ type MP4 struct {
|
||||
FragmentStartRawPTS uint64 // Raw PTS for timing when to flush fragments
|
||||
FragmentStartDTS uint64 // Accumulated VideoTotalDuration at fragment start (matches tfdt)
|
||||
LastKeyframeRawPTS uint64 // Raw PTS of the most recently seen keyframe (in any fragment)
|
||||
LastKeyframeGapMs uint64 // Gap (ms) between the previous two consecutive keyframes
|
||||
MoofBoxes int64 // Number of moof boxes in the file
|
||||
MoofBoxSizes []int64 // Sizes of each moof box
|
||||
SegmentDurations []uint64 // Duration of each segment in timescale units
|
||||
@@ -326,13 +327,23 @@ func (mp4 *MP4) AddSampleToTrack(trackID uint32, isKeyframe bool, data []byte, p
|
||||
// fragment with a "media corruption" error because the inner IDR resets
|
||||
// frame_num/POC inside what they expect to be a single GOP. Force a
|
||||
// fragment boundary whenever two consecutive keyframes arrive much
|
||||
// closer than a normal GOP (here: < 500 ms apart). This isolates the
|
||||
// seam IDR into its own fragment so each fragment stays a clean GOP.
|
||||
if !shouldFlush && trackID == uint32(mp4.VideoTrack) && mp4.Start &&
|
||||
mp4.LastKeyframeRawPTS > 0 && pts > mp4.LastKeyframeRawPTS &&
|
||||
pts-mp4.LastKeyframeRawPTS < MinNormalGOPMs {
|
||||
log.Log.Warning(fmt.Sprintf("mp4.AddSampleToTrack(): forcing fragment flush at unexpectedly close keyframe (gap=%d ms, fragment elapsed=%d ms) - likely upstream loop/restart discontinuity", pts-mp4.LastKeyframeRawPTS, elapsed))
|
||||
shouldFlush = true
|
||||
// closer than a normal GOP.
|
||||
//
|
||||
// We only flag this as a seam when it is a *sudden* anomaly: the
|
||||
// previous keyframe gap must have been healthy (>= MinNormalGOPMs).
|
||||
// This avoids false positives on cameras that legitimately emit
|
||||
// short-interval IDRs (short GOP, motion-triggered recovery IDRs,
|
||||
// all-intra streams) where every keyframe would otherwise be flagged
|
||||
// in a cascade, producing many tiny fragments and log spam.
|
||||
if trackID == uint32(mp4.VideoTrack) && mp4.Start &&
|
||||
mp4.LastKeyframeRawPTS > 0 && pts > mp4.LastKeyframeRawPTS {
|
||||
gap := pts - mp4.LastKeyframeRawPTS
|
||||
if !shouldFlush && gap < MinNormalGOPMs &&
|
||||
(mp4.LastKeyframeGapMs == 0 || mp4.LastKeyframeGapMs >= MinNormalGOPMs) {
|
||||
log.Log.Warning(fmt.Sprintf("mp4.AddSampleToTrack(): forcing fragment flush at unexpectedly close keyframe (gap=%d ms, fragment elapsed=%d ms) - likely upstream loop/restart discontinuity", gap, elapsed))
|
||||
shouldFlush = true
|
||||
}
|
||||
mp4.LastKeyframeGapMs = gap
|
||||
}
|
||||
if trackID == uint32(mp4.VideoTrack) {
|
||||
mp4.LastKeyframeRawPTS = pts
|
||||
|
||||
Reference in New Issue
Block a user