Load Time Improvements
This commit is contained in:
@@ -90,7 +90,7 @@ async function buildFFmpegArgs({ fps, useMusic, musicPath, inputFormat = 'jpeg',
|
|||||||
...(captureAtHigherFps ? ['-r', fps.toString()] : []),
|
...(captureAtHigherFps ? ['-r', fps.toString()] : []),
|
||||||
'-tune', 'zerolatency',
|
'-tune', 'zerolatency',
|
||||||
'-pix_fmt', 'yuv420p',
|
'-pix_fmt', 'yuv420p',
|
||||||
'-g', (fps * 2).toString(), // Keyframe every 2 seconds for 2s segments
|
'-g', fps.toString(), // Keyframe every 1 second for 1s segments
|
||||||
'-bf', '0', // No B-frames for lower latency
|
'-bf', '0', // No B-frames for lower latency
|
||||||
'-x264opts', 'nal-hrd=cbr:no-scenecut', // Constant bitrate, no scene detection
|
'-x264opts', 'nal-hrd=cbr:no-scenecut', // Constant bitrate, no scene detection
|
||||||
'-b:v', '2500k', // Target bitrate for stable encoding
|
'-b:v', '2500k', // Target bitrate for stable encoding
|
||||||
@@ -109,8 +109,8 @@ async function buildFFmpegArgs({ fps, useMusic, musicPath, inputFormat = 'jpeg',
|
|||||||
'-max_interleave_delta', '500000', // Increased for smoother transitions (500ms)
|
'-max_interleave_delta', '500000', // Increased for smoother transitions (500ms)
|
||||||
'-err_detect', 'ignore_err', // Continue on minor audio errors
|
'-err_detect', 'ignore_err', // Continue on minor audio errors
|
||||||
'-f', 'hls',
|
'-f', 'hls',
|
||||||
'-hls_time', '2', // 2-second segments for better buffering
|
'-hls_time', '1', // 1-second segments for faster startup
|
||||||
'-hls_list_size', '10', // Keep more segments in playlist for slower clients
|
'-hls_list_size', '3', // Minimal segments for faster startup
|
||||||
'-hls_flags', 'omit_endlist+program_date_time+independent_segments',
|
'-hls_flags', 'omit_endlist+program_date_time+independent_segments',
|
||||||
'-hls_segment_type', 'mpegts',
|
'-hls_segment_type', 'mpegts',
|
||||||
'-hls_start_number_source', 'epoch',
|
'-hls_start_number_source', 'epoch',
|
||||||
@@ -141,15 +141,15 @@ async function buildFFmpegArgs({ fps, useMusic, musicPath, inputFormat = 'jpeg',
|
|||||||
...(captureAtHigherFps ? ['-r', fps.toString()] : []),
|
...(captureAtHigherFps ? ['-r', fps.toString()] : []),
|
||||||
'-tune', 'zerolatency',
|
'-tune', 'zerolatency',
|
||||||
'-pix_fmt', 'yuv420p',
|
'-pix_fmt', 'yuv420p',
|
||||||
'-g', (fps * 2).toString(), // Keyframe every 2 seconds for 2s segments
|
'-g', fps.toString(), // Keyframe every 1 second for 1s segments
|
||||||
'-bf', '0',
|
'-bf', '0',
|
||||||
'-x264opts', 'nal-hrd=cbr:no-scenecut',
|
'-x264opts', 'nal-hrd=cbr:no-scenecut',
|
||||||
'-b:v', '2500k',
|
'-b:v', '2500k',
|
||||||
'-maxrate', '2500k',
|
'-maxrate', '2500k',
|
||||||
'-bufsize', '5000k',
|
'-bufsize', '5000k',
|
||||||
'-f', 'hls',
|
'-f', 'hls',
|
||||||
'-hls_time', '2', // 2-second segments for better buffering
|
'-hls_time', '1', // 1-second segments for faster startup
|
||||||
'-hls_list_size', '10', // Keep more segments in playlist for slower clients
|
'-hls_list_size', '3', // Minimal segments for faster startup
|
||||||
'-hls_flags', 'omit_endlist+program_date_time+independent_segments',
|
'-hls_flags', 'omit_endlist+program_date_time+independent_segments',
|
||||||
'-hls_segment_type', 'mpegts',
|
'-hls_segment_type', 'mpegts',
|
||||||
'-hls_start_number_source', 'epoch',
|
'-hls_start_number_source', 'epoch',
|
||||||
|
|||||||
@@ -34,12 +34,9 @@ async function setupPage(browser, { width, height }) {
|
|||||||
*/
|
*/
|
||||||
async function waitForPageFullyLoaded(page, url) {
|
async function waitForPageFullyLoaded(page, url) {
|
||||||
try {
|
try {
|
||||||
// Wait for DOM content and stylesheet to load
|
// Wait for DOM content to load - no artificial delay, stream starts immediately
|
||||||
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||||
|
|
||||||
// Wait a brief moment for stylesheet to apply
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Page load error:', err.message);
|
console.error('Page load error:', err.message);
|
||||||
|
|||||||
@@ -427,17 +427,24 @@ async function streamHandler(req, res, { useMusic = false, musicPath, lateGeocod
|
|||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
ffmpegProcess.kill('SIGTERM');
|
ffmpegProcess.kill('SIGTERM');
|
||||||
|
|
||||||
|
// Wait for FFmpeg to terminate before cleaning up playlist
|
||||||
|
const currentProcess = ffmpegProcess;
|
||||||
|
const currentPlaylistFile = playlistFile;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (ffmpegProcess && !ffmpegProcess.killed) {
|
if (currentProcess && !currentProcess.killed) {
|
||||||
ffmpegProcess.kill('SIGKILL');
|
currentProcess.kill('SIGKILL');
|
||||||
|
}
|
||||||
|
// Clean up per-stream playlist file after FFmpeg is terminated
|
||||||
|
if (currentPlaylistFile) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(currentPlaylistFile);
|
||||||
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
ffmpegProcess = null;
|
ffmpegProcess = null;
|
||||||
}
|
} else if (playlistFile) {
|
||||||
|
// FFmpeg already dead, safe to delete immediately
|
||||||
// Clean up per-stream playlist file (rotated copy, not the shared one)
|
|
||||||
if (playlistFile) {
|
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(playlistFile);
|
fs.unlinkSync(playlistFile);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
|
|||||||
Reference in New Issue
Block a user