使用FFmpeg WASM烧录.ass字幕至.mp4无显示求助
FFmpeg WASM烧录ASS字幕不显示的问题排查与修复
使用FFmpeg WASM将ASS格式字幕烧录到MP4视频后,输出视频未显示字幕,怀疑是字体问题,附上代码与ASS文件内容:
原代码
import { FFmpeg } from "@ffmpeg/ffmpeg" import { fetchFile } from "@ffmpeg/util" import { createClientComponentClient } from "@supabase/auth-helpers-nextjs" export async function burnSubtitles(inputVideo: string, inputSubtitles: string, session: any, videoFileName: string) { const ffmpeg = new FFmpeg() const supabase = createClientComponentClient() try { console.log("Loading FFmpeg...") await ffmpeg.load({ coreURL: "https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.js", log: true, }) console.log("FFmpeg Loaded!") // Fetch video and subtitle files console.log("Fetching video and subtitle files...") const videoFile = await fetchFile(inputVideo) const subtitleFile = await fetchFile(inputSubtitles) console.log("Writing files to FFmpeg virtual filesystem...") await ffmpeg.writeFile("input.mp4", videoFile) await ffmpeg.writeFile("subtitles.ass", subtitleFile) console.log("Running FFmpeg command...") await ffmpeg.exec([ "-i", "input.mp4", "-vf", "subtitles=subtitles.ass", "-c:v", "libx264", "-preset", "fast", "-crf", "23", "-c:a", "aac", "-b:a", "128k", "output.mp4", ]) console.log("FFmpeg processing completed!") // Get the output file console.log("Reading output file...") const outputData = await ffmpeg.readFile("output.mp4") // Generate file paths const processedFile = videoFileName ? `${videoFileName.split(".")[0]}.mp4` : `${Date.now()}.mp4` const processedFilePath = `processed/${session.user.id}/${processedFile}` console.log("Uploading processed video to Supabase...") // Upload the processed video to Supabase const { error } = await supabase.storage .from("processed") .upload(processedFilePath, new Blob([outputData.buffer], { type: "video/mp4" }), { upsert: true }) if (error) { throw new Error(`Failed to upload processed video: ${error.message}`) } // Get the public URL of the uploaded video const { data: { publicUrl }, } = supabase.storage.from("processed").getPublicUrl(processedFilePath) console.log("Subtitled video uploaded successfully:", publicUrl) return { success: true, videoUrl: publicUrl, } } catch (error) { console.error("Error in FFmpeg processing:", error) return { success: false, error: "Processing failed", } } finally { ffmpeg.terminate() } }
ASS字幕文件内容
[Script Info] ScriptType: v4.00+ PlayResX: 1920 PlayResY: 1080 ScaledBorderAndShadow: yes [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,Arial,16,&HFFFFFF,&H000000FF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,2,2,2,30,30,360,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,00:00:00.00,00:00:01.11,Default,,0,0,360,,{\fad(300,0)\t(0,350,\fscx80\fscy80)\t(350,600,\fscx100\fscy100)\shad2}THIS IS A TEST, Dialogue: 0,00:00:01.11,00:00:02.22,Default,,0,0,360,,{\fad(300,0)\t(0,350,\fscx80\fscy80)\t(350,600,\fscx100\fscy100)\shad2}SUBTITLE
问题排查与修复
1. 字体缺失是核心原因
FFmpeg WASM运行在浏览器沙箱中,没有访问系统字体的权限,ASS字幕指定的Arial字体无法被加载,直接导致字幕渲染失败。需要手动将字体文件写入FFmpeg虚拟文件系统,并在滤镜中明确指定字体路径。
修复步骤:
- 准备Arial字体文件(如
arial.ttf),确保可通过前端路径访问 - 在代码中添加字体文件的读取与写入:
// 新增:加载字体文件 const fontFile = await fetchFile("/path/to/arial.ttf"); // 替换为实际字体文件路径 await ffmpeg.writeFile("arial.ttf", fontFile); - 修改FFmpeg命令的滤镜参数,指定字体文件:
await ffmpeg.exec([ "-i", "input.mp4", "-vf", "subtitles=subtitles.ass:fontfile=arial.ttf", "-c:v", "libx264", "-preset", "fast", "-crf", "23", "-c:a", "aac", "-b:a", "128k", "output.mp4" ]);
2. 验证分辨率匹配
ASS字幕设置的PlayResX:1920、PlayResY:1080需要和输入视频的分辨率一致,否则字幕可能被缩放至不可见或超出画面范围。如果视频分辨率不同,建议调整ASS文件的PlayRes参数,或者在滤镜中添加缩放适配(如scale=1920:1080)。
3. 检查FFmpeg日志
由于开启了log: true,可以查看浏览器控制台中的FFmpeg日志,确认是否有字体加载失败、字幕解析错误等提示,快速定位问题。
4. 优化ASS字幕格式
- 删除对话行末尾的多余逗号(如
THIS IS A TEST,改为THIS IS A TEST),避免潜在解析问题 - 确认时间码范围在视频时长内,确保字幕有机会被显示
内容的提问来源于stack exchange,提问作者Diyan Todorov
相关产品推荐
相关产品推荐

