perf: optimize video playback and encoding for better web streaming experience

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name 2026-01-31 20:54:25 +08:00
parent e861fc5203
commit b99b3e5718
2 changed files with 65 additions and 10 deletions

View File

@ -78,21 +78,44 @@ async function compressVideo(
const videoInfo = await getVideoInfo(inputPath);
const originalSize = (await readFile(inputPath)).length;
// 构建 FFmpeg 命令
// 构建 FFmpeg 命令 - 针对 Web 流式播放深度优化
// 使用 H.264 (libx264) 编码器 + AAC 音频
// -movflags +faststart 让视频可以边下载边播放
//
// 关键优化参数说明:
// -movflags +faststart: 将 moov atom 移到文件开头,支持边下载边播放
// -profile:v high: 使用 High Profile,更好的压缩率和兼容性
// -level 4.1: 兼容大多数设备的 Level
// -pix_fmt yuv420p: 确保最广泛的浏览器兼容性
// -tune film/animation: 根据内容优化(这里用 film 作为通用选择)
// -g 48: 关键帧间隔,约每2秒一个关键帧,优化 seek 体验
// -keyint_min 24: 最小关键帧间隔
// -sc_threshold 0: 禁用场景切换检测,保持稳定的关键帧间隔
// -bf 2: B帧数量,提高压缩率
// -b_strategy 2: B帧策略,动态选择
let scaleFilter = "";
if (videoInfo.width > targetWidth) {
scaleFilter = `-vf "scale=${targetWidth}:-2"`;
// 使用 lanczos 缩放算法,质量最好
scaleFilter = `-vf "scale=${targetWidth}:-2:flags=lanczos"`;
}
const ffmpegCmd = `ffmpeg -i "${inputPath}" \
-c:v libx264 \
-preset ${preset} \
-crf ${crf} \
-profile:v high \
-level 4.1 \
-pix_fmt yuv420p \
-g 48 \
-keyint_min 24 \
-sc_threshold 0 \
-bf 2 \
-b_strategy 2 \
${scaleFilter} \
-c:a aac \
-b:a ${audioBitrate} \
-ar 44100 \
-ac 2 \
-movflags +faststart \
-y \
"${outputPath}"`;

View File

@ -480,28 +480,60 @@ export function TopNavbar({
{/* 视频播放器 */}
<div className="relative w-full aspect-video bg-black rounded-lg overflow-hidden shadow-2xl">
{currentTutorialVideo.videoUrl.includes('youtube.com') || currentTutorialVideo.videoUrl.includes('youtu.be') ? (
// YouTube 嵌入
// YouTube 嵌入 - 启用自动播放和性能优化
<iframe
src={currentTutorialVideo.videoUrl.replace('watch?v=', 'embed/').replace('youtu.be/', 'youtube.com/embed/')}
src={`${currentTutorialVideo.videoUrl.replace('watch?v=', 'embed/').replace('youtu.be/', 'youtube.com/embed/')}?autoplay=1&rel=0&modestbranding=1`}
className="w-full h-full"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
loading="eager"
/>
) : currentTutorialVideo.videoUrl.includes('bilibili.com') ? (
// Bilibili 嵌入
<iframe
src={currentTutorialVideo.videoUrl.replace('www.bilibili.com/video/', 'player.bilibili.com/player.html?bvid=')}
src={`${currentTutorialVideo.videoUrl.replace('www.bilibili.com/video/', 'player.bilibili.com/player.html?bvid=')}&autoplay=1&high_quality=1`}
className="w-full h-full"
allowFullScreen
loading="eager"
/>
) : (
// 普通视频链接
// 高性能原生视频播放器
<video
src={currentTutorialVideo.videoUrl}
className="w-full h-full"
className="w-full h-full object-contain"
controls
autoPlay
/>
playsInline
preload="auto"
controlsList="nodownload"
disablePictureInPicture={false}
poster={currentTutorialVideo.coverUrl || undefined}
onLoadStart={(e) => {
// 优化:设置播放速率缓冲策略
const video = e.currentTarget;
if ('fastSeek' in video) {
video.fastSeek(0);
}
}}
onCanPlay={(e) => {
// 视频可以播放时自动开始
const video = e.currentTarget;
video.play().catch(() => {
// 自动播放被阻止时静音重试
video.muted = true;
video.play().catch(() => {});
});
}}
style={{
// 硬件加速
transform: 'translateZ(0)',
willChange: 'transform',
}}
>
{/* 提供多格式支持作为后备 */}
<source src={currentTutorialVideo.videoUrl} type="video/mp4" />
您的浏览器不支持视频播放
</video>
)}
</div>