mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
build(spf): build26 from 45504a2b
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
import { SEGMENT_TIME_EPSILON } from "../types/index.js";
|
||||
//#region src/media/buffer/forward-buffer.ts
|
||||
/**
|
||||
* Forward Buffer Strategy (Simple)
|
||||
*
|
||||
* Determines which segments to load for forward buffer management.
|
||||
* V1 uses simple fixed-duration strategy (buffer N seconds ahead).
|
||||
*/
|
||||
/**
|
||||
* Merge intervals into sorted, disjoint ranges; touching or overlapping ranges
|
||||
* (gap ≤ `epsilon`) are joined. Empty/inverted ranges are dropped.
|
||||
*/
|
||||
function mergeTimeRanges(ranges, epsilon = SEGMENT_TIME_EPSILON) {
|
||||
const sorted = ranges.filter((r) => r.end > r.start).sort((a, b) => a.start - b.start);
|
||||
const merged = [];
|
||||
for (const r of sorted) {
|
||||
const last = merged[merged.length - 1];
|
||||
if (last && r.start <= last.end + epsilon) last.end = Math.max(last.end, r.end);
|
||||
else merged.push({
|
||||
start: r.start,
|
||||
end: r.end
|
||||
});
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
/**
|
||||
* Whether `[start, end)` is fully covered by the union of `merged` ranges,
|
||||
* tolerating `epsilon` of overhang at each edge. `merged` must be disjoint and
|
||||
* sorted (as returned by `mergeTimeRanges`), so full coverage means a single
|
||||
* merged range contains the interval.
|
||||
*/
|
||||
function isTimeRangeCovered(start, end, merged, epsilon = SEGMENT_TIME_EPSILON) {
|
||||
return merged.some((r) => r.start <= start + epsilon && r.end >= end - epsilon);
|
||||
}
|
||||
/**
|
||||
* Default forward buffer configuration.
|
||||
*/
|
||||
const DEFAULT_FORWARD_BUFFER_CONFIG = { bufferDuration: 30 };
|
||||
/**
|
||||
* Get segments that need to be loaded for forward buffer.
|
||||
*
|
||||
* Determines which segments to load to maintain target buffer duration.
|
||||
* Handles discontiguous buffering (gaps after seeks).
|
||||
*
|
||||
* Algorithm:
|
||||
* 1. Calculate target time: currentTime + bufferDuration
|
||||
* 2. Find all segments in range [currentTime, targetTime)
|
||||
* 3. Filter out segments already buffered at that time position
|
||||
* 4. Return segments to load (fills gaps + extends to target)
|
||||
*
|
||||
* @param segments - All available segments from playlist
|
||||
* @param bufferedSegments - Segments already buffered (ordered by startTime)
|
||||
* @param currentTime - Current playback position in seconds
|
||||
* @param config - Optional forward buffer configuration
|
||||
* @returns Array of segments to load (empty if buffer is sufficient)
|
||||
*
|
||||
* @example
|
||||
* // After seek: buffered [0-12, 18-30], playing at 7s
|
||||
* const toLoad = getSegmentsToLoad(segments, buffered, 7, { bufferDuration: 24 });
|
||||
* // Returns [seg-12, seg-30] (fills gap, extends to target 31s)
|
||||
*/
|
||||
/**
|
||||
* Calculate the start time from which to flush forward buffer content.
|
||||
*
|
||||
* Content that starts at or beyond `currentTime + bufferDuration` is no
|
||||
* longer needed for the current playback position and should be removed
|
||||
* from the SourceBuffer. This prevents unbounded accumulation of scattered
|
||||
* SourceBuffer content after seeks, which can cause QuotaExceededError on
|
||||
* long-form content.
|
||||
*
|
||||
* Returns `Infinity` when nothing needs flushing (no buffered segments
|
||||
* exist beyond the threshold).
|
||||
*
|
||||
* @param bufferedSegments - Segments currently tracked in the buffer model
|
||||
* @param currentTime - Current playback position in seconds
|
||||
* @param config - Optional forward buffer configuration
|
||||
* @returns Start time to flush from (flush range: [flushStart, Infinity)),
|
||||
* or Infinity if no flush is needed
|
||||
*
|
||||
* @example
|
||||
* // Playing at 0s, buffered [0,6,12,18,24,30,36], bufferDuration=30
|
||||
* const flushStart = calculateForwardFlushPoint(segments, 0);
|
||||
* // Returns 30 — flush [30, Infinity), keep [0, 30)
|
||||
*/
|
||||
function calculateForwardFlushPoint(bufferedSegments, currentTime, config = DEFAULT_FORWARD_BUFFER_CONFIG) {
|
||||
if (bufferedSegments.length === 0) return Infinity;
|
||||
const threshold = currentTime + config.bufferDuration;
|
||||
const beyond = bufferedSegments.filter((seg) => seg.startTime >= threshold);
|
||||
if (beyond.length === 0) return Infinity;
|
||||
return Math.min(...beyond.map((seg) => seg.startTime));
|
||||
}
|
||||
/**
|
||||
* Find the start time of the segment containing `currentTime` (or the last
|
||||
* segment if `currentTime` is past the end). Returns `undefined` when
|
||||
* `currentTime` is undefined or when no segment matches.
|
||||
*
|
||||
* Used to detect "meaningful currentTime change" — two times that map to the
|
||||
* same segment start aren't a load-trigger; crossing a segment boundary is.
|
||||
*/
|
||||
function segmentStartForTime(currentTime, segments) {
|
||||
if (currentTime == null) return void 0;
|
||||
return segments?.find(({ startTime, duration }, i, all) => currentTime >= startTime && (currentTime < startTime + duration || i === all.length - 1))?.startTime;
|
||||
}
|
||||
function getSegmentsToLoad(segments, bufferedSegments, currentTime, config = DEFAULT_FORWARD_BUFFER_CONFIG) {
|
||||
if (segments.length === 0) return [];
|
||||
const targetTime = currentTime + config.bufferDuration;
|
||||
const bufferedStartTimes = new Set(bufferedSegments.map((seg) => seg.startTime));
|
||||
return segments.filter((seg, i) => {
|
||||
const segmentEnd = seg.startTime + seg.duration;
|
||||
const overlapsPlayhead = i === segments.length - 1 || segmentEnd > currentTime;
|
||||
const isInRange = seg.startTime < targetTime && overlapsPlayhead;
|
||||
const isNotBuffered = !bufferedStartTimes.has(seg.startTime);
|
||||
return isInRange && isNotBuffered;
|
||||
});
|
||||
}
|
||||
//#endregion
|
||||
export { DEFAULT_FORWARD_BUFFER_CONFIG, calculateForwardFlushPoint, getSegmentsToLoad, isTimeRangeCovered, mergeTimeRanges, segmentStartForTime };
|
||||
|
||||
//# sourceMappingURL=forward-buffer.js.map
|
||||
Reference in New Issue
Block a user