Use GPUVideoSource for hardware-accelerated video decoding
- CIDVideoSource now uses GPUVideoSource when GPU is available - Enables CUDA hardware decoding for video sources - Should significantly improve rendering performance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -112,21 +112,22 @@
|
|||||||
function initHls() {
|
function initHls() {
|
||||||
if (Hls.isSupported()) {
|
if (Hls.isSupported()) {
|
||||||
hls = new Hls({
|
hls = new Hls({
|
||||||
// Stability over low latency - buffer more for smoother playback
|
// Stay far behind live edge - rendering is slow (~0.1x speed)
|
||||||
liveSyncDurationCount: 4, // Stay 4 segments behind live edge
|
// 10 segments = 40s of buffer before catching up
|
||||||
liveMaxLatencyDurationCount: 8, // Max 8 segments behind
|
liveSyncDurationCount: 10, // Stay 10 segments behind live edge
|
||||||
|
liveMaxLatencyDurationCount: 20, // Allow up to 20 segments behind
|
||||||
liveDurationInfinity: true, // Treat as infinite live stream
|
liveDurationInfinity: true, // Treat as infinite live stream
|
||||||
|
|
||||||
// Large buffers to absorb rendering speed variations
|
// Large buffers to absorb rendering speed variations
|
||||||
maxBufferLength: 60, // Buffer up to 60s ahead
|
maxBufferLength: 120, // Buffer up to 120s ahead
|
||||||
maxMaxBufferLength: 120, // Allow even more if needed
|
maxMaxBufferLength: 180, // Allow even more if needed
|
||||||
maxBufferSize: 60 * 1024 * 1024, // 60MB buffer
|
maxBufferSize: 100 * 1024 * 1024, // 100MB buffer
|
||||||
maxBufferHole: 0.5, // Tolerate small gaps
|
maxBufferHole: 0.5, // Tolerate small gaps
|
||||||
|
|
||||||
// Back buffer for smooth seeking
|
// Back buffer for smooth seeking
|
||||||
backBufferLength: 30,
|
backBufferLength: 60,
|
||||||
|
|
||||||
// Playlist reload settings
|
// Playlist reload settings - check frequently for new segments
|
||||||
manifestLoadingTimeOut: 10000,
|
manifestLoadingTimeOut: 10000,
|
||||||
manifestLoadingMaxRetry: 4,
|
manifestLoadingMaxRetry: 4,
|
||||||
levelLoadingTimeOut: 10000,
|
levelLoadingTimeOut: 10000,
|
||||||
@@ -202,9 +203,21 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle video stalls
|
// Handle video stalls - check if we've caught up to live edge
|
||||||
video.addEventListener('waiting', function() {
|
video.addEventListener('waiting', function() {
|
||||||
statusEl.textContent = 'Buffering...';
|
// Check if we're near the live edge (within 2 segments)
|
||||||
|
if (hls && hls.liveSyncPosition) {
|
||||||
|
const liveEdge = hls.liveSyncPosition;
|
||||||
|
const currentTime = video.currentTime;
|
||||||
|
const behindLive = liveEdge - currentTime;
|
||||||
|
if (behindLive < 8) { // Less than 2 segments behind
|
||||||
|
statusEl.textContent = 'Waiting for rendering...';
|
||||||
|
} else {
|
||||||
|
statusEl.textContent = 'Buffering...';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
statusEl.textContent = 'Buffering...';
|
||||||
|
}
|
||||||
statusEl.classList.remove('text-green-400');
|
statusEl.classList.remove('text-green-400');
|
||||||
statusEl.classList.add('text-yellow-400');
|
statusEl.classList.add('text-yellow-400');
|
||||||
});
|
});
|
||||||
@@ -215,6 +228,24 @@
|
|||||||
statusEl.classList.add('text-green-400');
|
statusEl.classList.add('text-green-400');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Periodic check for catching up to live edge
|
||||||
|
setInterval(function() {
|
||||||
|
if (hls && !video.paused && hls.levels && hls.levels.length > 0) {
|
||||||
|
const buffered = video.buffered;
|
||||||
|
if (buffered.length > 0) {
|
||||||
|
const bufferEnd = buffered.end(buffered.length - 1);
|
||||||
|
const currentTime = video.currentTime;
|
||||||
|
const bufferAhead = bufferEnd - currentTime;
|
||||||
|
// If less than 4 seconds buffered, show warning
|
||||||
|
if (bufferAhead < 4) {
|
||||||
|
statusEl.textContent = 'Waiting for rendering...';
|
||||||
|
statusEl.classList.remove('text-green-400');
|
||||||
|
statusEl.classList.add('text-yellow-400');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
hls.loadSource(hlsUrl);
|
hls.loadSource(hlsUrl);
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
|
|||||||
@@ -134,9 +134,18 @@ class CIDVideoSource:
|
|||||||
raise ValueError(f"Could not resolve video source '{self.cid}' for actor_id={self.actor_id}")
|
raise ValueError(f"Could not resolve video source '{self.cid}' for actor_id={self.actor_id}")
|
||||||
|
|
||||||
logger.info(f"CIDVideoSource._ensure_source: resolved to path={path}")
|
logger.info(f"CIDVideoSource._ensure_source: resolved to path={path}")
|
||||||
# Import from primitives where VideoSource is defined
|
# Use GPU-accelerated video source if available
|
||||||
from sexp_effects.primitive_libs.streaming import VideoSource
|
try:
|
||||||
self._source = VideoSource(str(path), self.fps)
|
from sexp_effects.primitive_libs.streaming_gpu import GPUVideoSource, GPU_AVAILABLE
|
||||||
|
if GPU_AVAILABLE:
|
||||||
|
logger.info(f"CIDVideoSource: using GPUVideoSource for {path}")
|
||||||
|
self._source = GPUVideoSource(str(path), self.fps, prefer_gpu=True)
|
||||||
|
else:
|
||||||
|
raise ImportError("GPU not available")
|
||||||
|
except (ImportError, Exception) as e:
|
||||||
|
logger.info(f"CIDVideoSource: falling back to CPU VideoSource ({e})")
|
||||||
|
from sexp_effects.primitive_libs.streaming import VideoSource
|
||||||
|
self._source = VideoSource(str(path), self.fps)
|
||||||
|
|
||||||
def read_at(self, t: float):
|
def read_at(self, t: float):
|
||||||
self._ensure_source()
|
self._ensure_source()
|
||||||
|
|||||||
Reference in New Issue
Block a user