From 67d13ae2f682191e745cd25cfe9f888d965d506c Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:38:15 -0400 Subject: [PATCH] add comments --- server/src/enum.ts | 6 +++- server/src/repositories/media.repository.ts | 33 +++++++++++++-------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/server/src/enum.ts b/server/src/enum.ts index 67d62e8f12..a65e0aa40e 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -662,17 +662,21 @@ export enum ColorMatrix { } /** H.264 `profile_idc` values. */ +// H.264 has a few profiles that have the same value but different names, included so lookup by name works +// eslint-disable @typescript-eslint/no-duplicate-enum-values export enum H264Profile { ConstrainedBaseline = 66, - // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values Baseline = 66, Main = 77, Extended = 88, + ConstrainedHigh = 100, + ProgressiveHigh = 100, High = 100, High10 = 110, High422 = 122, High444Predictive = 244, } +// eslint-enable @typescript-eslint/no-duplicate-enum-values /** HEVC `profile_idc` values. */ export enum HevcProfile { diff --git a/server/src/repositories/media.repository.ts b/server/src/repositories/media.repository.ts index e0365c62dc..dd88368306 100644 --- a/server/src/repositories/media.repository.ts +++ b/server/src/repositories/media.repository.ts @@ -348,6 +348,7 @@ export class MediaRepository { if (Number.isNaN(pts) || Number.isNaN(duration)) { continue; } + // Discarded packets don't contribute to packet count, but still contribute to video duration totalDuration += duration; if (flags[1] !== 'D') { packetCount++; @@ -356,6 +357,9 @@ export class MediaRepository { if (flags[0] === 'K') { keyframePts.push(pts); keyframeAccDuration.push(totalDuration); + // VFR content can have variable duration keyframes, + // so we need to track their duration separately for accurate segment boundaries. + // Non-keyframes are accounted for in totalDuration. keyframeOwnDuration.push(duration); } } @@ -364,22 +368,10 @@ export class MediaRepository { return null; } - postDiscard.sort((a, b) => a.pts - b.pts); - const firstPts = postDiscard[0].pts; - const slotsPerTick = packetCount / formatDuration / timeBase; - let outputFrames = 0; - let nextPts = 0; - for (const pkt of postDiscard) { - const delta = (pkt.pts - firstPts) * slotsPerTick - nextPts + pkt.duration * slotsPerTick; - const nb = delta < -1.1 ? 0 : delta > 1.1 ? Math.round(delta) : 1; - outputFrames += nb; - nextPts += nb; - } - return { totalDuration, packetCount, - outputFrames, + outputFrames: this.cfrOutputFrames(postDiscard, packetCount / formatDuration / timeBase), keyframePts, keyframeAccDuration, keyframeOwnDuration, @@ -526,4 +518,19 @@ export class MediaRepository { } return this.parseInt(b.bit_rate) - this.parseInt(a.bit_rate); } + + private cfrOutputFrames(packets: { pts: number; duration: number }[], slotsPerTick: number) { + // Packets may be out of PTS order due to B-frames + packets.sort((a, b) => a.pts - b.pts); + const firstPts = packets[0].pts; + let outputFrames = 0; + let nextPts = 0; + for (const pkt of packets) { + const delta = (pkt.pts - firstPts) * slotsPerTick - nextPts + pkt.duration * slotsPerTick; + const nb = delta < -1.1 ? 0 : delta > 1.1 ? Math.round(delta) : 1; + outputFrames += nb; + nextPts += nb; + } + return outputFrames; + } }