c# 无法原生实现 hls 切片,必须调用 ffmpeg;最小可行命令为 ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f hls -hls_time 10 -hls_list_size 0 -hls_segmentfilename "chunk%03d.ts" output.m3u8。

用 FFmpeg 命令行切片,不是 C# 原生能干的事
C# 本身没有内置的 HLS 切片能力,System.IO 或 MediaFoundation 都不支持生成标准 .ts 片段和 .m3u8 清单。硬写解析 H.264/AVC 流、按 GOP 对齐切片、封装 MPEG-TS、生成带 #EXT-X-VERSION 和时间戳的 playlist,不仅工作量大,还极易产出非标准或播放失败的文件。
实际项目里,99% 的做法是调用外部工具——最可靠、最通用的是 ffmpeg。它支持完整 HLS 工作流,参数稳定,兼容主流播放器(如 iOS Safari、VLC、hls.js)。
- 必须确保目标机器已安装
ffmpeg,且在 PATH 中可执行;否则Process.Start("ffmpeg", ...)会直接抛FileNotFoundException - 不要尝试用
MemoryStream把视频喂给 ffmpeg stdin——TS 封装依赖随机访问和帧对齐,从管道输入常导致moov atom not found或切片时间错乱 - 输入视频最好已是 H.264 编码 + AAC 音频;若源为 MP4/MKV,ffmpeg 会自动转封装,但耗时增加,且可能引入音画不同步
关键 ffmpeg 参数组合:-f hls -hls_time -hls_list_size
生成合规 HLS 的核心不是“能不能切”,而是“切得是否被播放器接受”。以下是最小可行命令模板:
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f hls -hls_time 10 -hls_list_size 0 -hls_segment_filename "chunk_%03d.ts" output.m3u8
注意几个易错点:
-
-hls_time 10表示每个.ts片段约 10 秒——但实际长度受 GOP 影响,若关键帧间隔 >10s(如某些监控录像),ffmpeg 会拉长到下一个 I 帧,导致片段偏长;可加-force_key_frames "expr:gte(t,n_forced*10)"强制插关键帧 -
-hls_list_size 0表示不限制 playlist 中保留多少条#EXTINF记录;设为正数(如5)会滚动覆盖旧片段,适合直播场景,但点播应设为0 -
-hls_segment_filename路径需为相对或绝对路径,若含目录(如"./out/chunk_%03d.ts"),必须确保目录已存在,否则 ffmpeg 静默失败,只生成空.m3u8 - 默认生成的
.m3u8是 v3 版本(无#EXT-X-MAP),若需支持低版本 hls.js 或 Apple TV,可加-hls_version 4
从 C# 启动 ffmpeg 并捕获错误,别只看 ExitCode
Process.Start 调用 ffmpeg 后,仅检查 ExitCode == 0 不够——ffmpeg 在部分失败时仍返回 0(例如只生成了前几个 .ts 就卡住,但没报错)。真正可靠的判断依据是 stderr 输出和输出文件是否存在。
- 务必重定向
StandardError,并监听其中是否含"Error"、"failed"、"Invalid"等关键词;ffmpeg 错误通常不走 stdout - 切片完成后,检查
output.m3u8文件是否非空,且内容包含至少两条#EXTINF行;可用File.ReadAllLines快速验证 - 避免在 UI 线程同步等待 ffmpeg 结束——用
await Process.WaitForExitAsync()(.NET 6+)或Task.Run(() => process.WaitForExit()) - Windows 下若路径含中文或空格,
ffmpeg参数必须用双引号包裹,但 C# 传参时需手动加,例如:new string[] { "-i", $"\"{inputPath}\"", "-f", "hls", ... }
生成的 .m3u8 被拒载?先查 CORS 和 MIME 类型
即使切片完全正确,前端用 hls.js 加载时仍可能报 "failed to load manifest" 或黑屏。问题往往不在 C# 或 ffmpeg,而在服务端配置。
- HTTP 服务器必须返回
.m3u8的 MIME 类型为application/vnd.apple.mpegurl,而非text/plain;IIS、Nginx、Kestrel 默认都不认这个后缀 - 若静态文件由 ASP.NET Core 提供,需在
Program.cs中显式注册:services.Configure<staticfileoptions>(o => o.ServeUnknownFileTypes = true);</staticfileoptions>并在UseStaticFiles前加app.UseCors允许跨域(开发时常见坑) -
.ts文件也需正确 MIME:video/MP2T;某些 CDN 会强制改写,导致浏览器拒绝解析 - 用浏览器 DevTools 的 Network 面板直接打开
.m3u8URL,确认响应头含Content-Type: application/vnd.apple.mpegurl,且响应体是纯文本、每行无 BOM、无 HTML 标签
HLS 的麻烦从来不在切片本身,而在于整个交付链路里任意一环的隐式假设——比如你以为 ffmpeg 生成了标准文件,其实播放器只认特定 EXT-X-VERSION;你以为服务端配好了 MIME,其实 CDN 拦截重写了 header。动手前,先用 VLC 打开生成的 .m3u8,能播通,再往下一步走。










