视频处理,说难不难,说简单也不简单。尤其是在C#生态里,真正上手搞转码、裁剪、合并,核心就那几个坎儿,迈过去了,后面的路就顺了。今天咱们就把这些关键点掰开揉碎了聊一聊,省得你走弯路。

用 FFmpeg.AutoGen 调用 FFmpeg 做转码,别碰 ffmpeg.exe 进程启动
直接调用命令行 ffmpeg.exe,听起来很方便对吧?但Windows下的权限问题、路径里带空格导致的参数逃逸、编码参数传错、甚至进程僵死,这些坑会在你批量处理时一个接一个地冒出来,让你突然卡住甚至崩溃。C#里更稳的做法,是拥抱 FFmpeg.AutoGen——它是FFmpeg官方C API的.NET绑定,把FFmpeg编译成DLL静态链接进来。好处是内存可控、没有子进程、还能直接在IDE里断点调试,出了问题一眼就能定位。
实操上有几个关键点得注意:
- 从NuGet安装
FFmpeg.AutoGen后,记得手动把对应平台的a vcodec-*.dll等文件复制到bin/Debug下,x64和x86版本要匹配好。 - 初始化时,
ffmpeg.a vdevice_register_all()和ffmpeg.a vformat_network_init()这俩是必调用的,不然打开网络流或某些封装格式时会直接失败。 - 解码时别直接拿
A VPacket里的时间戳就用——得先用a v_frame_get_best_effort_timestamp()校准一下,否则裁剪精度偏差可能达到几百毫秒,这可不是小误差。 - 转码完成后,别忘了调用
a v_packet_unref()释放资源,不然内存泄漏起来比用Process.Start启动子进程还隐蔽,排查起来更头疼。
Accord.Video.FFMPEG 只能读帧,不能写视频
这个包名字里虽然带着FFMPEG,但底层它只负责解封装和解码,输出的是 Bitmap 或 double[][] 这种帧数据。所有“写回视频”的操作,都得你自己搭编码器链路。很多人以为调了 VideoFileReader.ReadVideoFrame() 之后,接个 VideoFileWriter.WriteVideoFrame() 就能保存,结果发现后者根本不存在——Accord.Video.FFMPEG 压根儿没提供编码能力。
常见错误现象:
- 试图用
VideoFileWriter写MP4文件,结果报错:System.NotImplementedException: The method or operation is not implemented. - 用
Accord.Imaging.Filters处理完帧,却卡在“怎么存回去”这一步上,最后只能被迫切回FFmpeg命令行。
那么,替代方案有哪些?
- 推荐用
FFmpeg.AutoGen自己写编码循环,控制力最强,也最灵活。 - 或者改用
OpenCvSharp的Cv2.VideoWriter,它支持X264编码,但需要提前编译带FFMPEG支持的OpenCV。
裁剪视频用 -ss 和 -t,但顺序和关键帧决定快慢
命令行里写 ffmpeg -i in.mp4 -ss 00:01:30 -t 10 -c copy out.mp4 看起来高效,但实际行为完全取决于 -ss 放的位置。放在 -i 前面是“先seek再解封装”,速度快但精度差;放在 -i 后面是“解完再丢帧”,精度高但速度慢。C#调用时如果没显式控制位置,很可能默认走慢路,导致性能瓶颈。
实操要点:
- 硬切(不重编码)必须把
-ss放在-i前面,而且要确保起始时间落在关键帧上,否则输出会黑屏或花屏。 - 想精确到帧?那只能重编码:把
-ss放在-i后面,再加上-a void_negative_ts make_zero防止PTS错乱。 - 在
FFmpeg.AutoGen里,对应的逻辑是调用a v_seek_frame()后检查返回值,如果返回不是0,说明没找到关键帧,需要手动向前找。
合并多个视频,别用 concat 协议拼文件名字符串
网上教程常教你在C#里拼 "file 'a.mp4'\nfile 'b.mp4'" 写进临时txt,再传给 -f concat。这在路径含中文、空格或特殊符号时必炸,错误信息通常是 Invalid data found when processing input 或 No such file or directory,排查起来很痛苦。
安全的做法:
- 所有输入路径先用
Uri.EscapeDataString()编码,再写入concat文件。 - 或者干脆绕过concat协议,用
a vformat_open_input()逐个打开,把每个流的A VStream.time_base对齐后,再mux到同一个A VFormatContext里。 - 音视频流的时间基(
time_base)不一致,会导致合并后音画不同步,必须统一转成1/1000这类常用值,再用a v_rescale_q()做转换。
最麻烦的不是代码逻辑,而是不同来源视频的 A VCodecParameters.codec_tag 不兼容——比如一个H.264是 a vc1,另一个是 a vc3,合并时FFmpeg会静默失败,日志里只留下一句 Could not write header,这才是真正考验经验的地方。