简介:面向 Windows 平台音视频开发者的 FFmpeg 4.2.1 开发包,适合需要在 C/C++ 项目中集成音视频编解码、格式转换、剪辑裁剪与流媒体处理能力的学习者和工程师,用于补齐命令行工具之外的二次开发环境。压缩包共 166 个文件,约 112.42MB,其中 115 个 .h 头文件、23 个 .c 源文件构成主要开发与示例内容,另含 8 个 .lib、8 个 .a、8 个 .def 以及 makefile、readme 和少量说明文本,覆盖接口声明、导入库、静态库、模块导出与构建参考等用途。已有 535 人学习,说明该开发包在 Windows 音视频开发入门与实验场景中具有一定参考价值。读者可据此在本地搭建 FFmpeg 开发环境,结合头文件与库文件完成 avcodec、avformat 等模块的链接调用,并通过包内转码示例理解解码、编码与封装流程,为自定义播放、录制、转码等应用开发提供可直接复用的工程基础。
1. Windows ffmpeg 不是黑框:先把它当成一条可控的媒体流水线
Windows ffmpeg 这个组合词,第一次出现在搜索框里时,多数人想要的很具体:一个能在 Windows 上直接跑起来的 ffmpeg.exe,而不是一堆编译教程。Windowsffmpeg 连写检索的人,往往已经卡在第二个问题上——命令能跑,但参数、路径和批量脚本一上量就翻车。它本质上是一条本地媒体流水线:ffmpeg 负责转码与封装,ffprobe 负责把源文件和成品拆开看清楚。适合做课程素材整理、录屏压缩、音频提取、字幕封装和批量归档的人;不适合指望一条命令解决所有兼容问题的人。
2. 把 Windowsffmpeg 跑起来:目录、PATH 与最小验证
拿到 Windows 版运行目录,先别急着双击 exe。ffmpeg 在 Windows 上的使用体验,一半取决于可执行文件本身,另一半取决于终端能不能稳定找到它。很多人第一次翻车不是参数写错,而是ffmpeg命令指向了另一份旧构建,或者 PATH 里塞了带空格的临时目录。先把目录、PATH、验证三条链路走通,后面调 CRF 和批处理才有意义。
2.1 先认目录:bin 下三个 exe 各管什么
常见的 Windows 运行目录会把可执行文件放在bin下,核心是ffmpeg.exe、ffprobe.exe、ffplay.exe。ffmpeg做主转码、封装、抽取、滤镜;ffprobe只读分析,用来查编码、分辨率、帧率、像素格式、音轨和时长;ffplay是一个轻量播放器,适合快速确认文件能不能解码,不适合拿来做最终画质判断。把整个目录放到固定位置,比如D:\tools\ffmpeg,不要放在桌面、下载目录或同步盘目录里,路径越短越稳。
REM 进入解压后的工具目录,核对 bin 下三个可执行文件是否存在 dir /b D:\tools\ffmpeg\bin\ffmpeg.exe dir /b D:\tools\ffmpeg\bin\ffprobe.exe dir /b D:\tools\ffmpeg\bin\ffplay.exedir /b只输出文件名,适合快速确认路径有没有写错。三条命令分别检查主程序、分析程序和播放程序;只要有一条提示“找不到文件”,先别继续配 PATH,回到解压目录核对层级。常见错误是把bin上一级目录加进 PATH,结果终端里能看见文件夹,却找不到ffmpeg.exe。我一般会先把D:\tools\ffmpeg\bin这个完整路径复制出来,后面所有配置都围绕它走,避免一会儿用相对路径、一会儿用快捷方式。
2.2 PATH 的稳妥写法:别让 setx 把变量截断
Windows 找命令靠 PATH。把D:\tools\ffmpeg\bin追加到用户 PATH 后,新开的终端才能直接敲ffmpeg。不推荐直接setx PATH "%PATH%;...",这种写法会把当前展开后的 PATH 写回去,遇到系统变量、长路径或特殊字符时容易把原变量弄乱。更稳的做法是只改当前用户的 Path,先读出原值,再判断是否已经存在,最后追加。改完必须新开终端,旧终端不会自动刷新环境变量。
# 只修改当前用户 Path,避免把系统 Path 展开后写坏 $ffmpegBin = 'D:\tools\ffmpeg\bin' $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') if (-not $userPath) { $userPath = '' } $parts = $userPath -split ';' | Where-Object { $_ -ne '' } if ($parts -notcontains $ffmpegBin) { $newPath = ($parts + $ffmpegBin) -join ';' [Environment]::SetEnvironmentVariable('Path', $newPath, 'User') }这段脚本的关键点是User作用域:只影响当前用户,不需要管理员权限,也不会动系统级 PATH。-split ';'把原 Path 拆成条目,-notcontains防止重复追加;重复执行不会越加越长。改完后关掉所有 cmd 和 PowerShell 窗口,重新开一个,执行where ffmpeg。如果输出多条路径,说明机器上还有旧版本,PATH 顺序会让先命中的那份生效。遇到这种情况,要么删掉旧条目,要么在脚本里用完整路径调用,别让“命令能跑”掩盖“跑的不是同一份”。
提示:PATH 改完不生效,先检查终端是不是旧窗口,再检查用户变量和系统变量里是否各有一份 ffmpeg。
2.3 三条最小验证:版本、编码器、硬件加速
配置完成后不要直接上正式素材,先做三条验证。第一条看版本和构建信息,确认命令确实能启动;第二条看常用编码器是否存在,尤其是libx264、aac这类转码常用项;第三条看硬件加速能力,但只把它当参考,不代表硬件编码一定更快或画质更好。Windows 终端里findstr可以做简单过滤,PowerShell 里也可以用Select-String,核心是别靠猜。
REM 1. 确认当前命中的 ffmpeg 能启动 ffmpeg -hide_banner -version REM 2. 确认命令来自哪个路径,排查多版本冲突 where ffmpeg REM 3. 查常用编码器和硬件加速入口 ffmpeg -hide_banner -encoders | findstr /i "libx264 libx265 aac" ffmpeg -hide_banner -hwaccels-hide_banner只是压掉启动横幅,让输出更干净;-encoders列出当前构建支持的编码器,输出里没有libx264就说明这份构建不带该编码器,后面写-c:v libx264必然报Unknown encoder。-hwaccels列出可用的硬件加速方式,但“列出了”不等于“当前素材能稳定用”,还要看驱动、会话和编码器参数。where ffmpeg在多版本机器上特别有用:如果第一条命中C:\Windows\System32或某个旧工具目录,说明 PATH 顺序不对,此时用完整路径D:\tools\ffmpeg\bin\ffmpeg.exe先跑通,再回头清理 PATH。
2.4 第一次转码:用一条命令确认输入输出链路
验证命令都通过后,拿一个短素材做第一次转码。不要一上来就处理整季课程或几个小时的录屏,先用一个几十秒的文件确认输入路径、输出路径、编码器、音频编码和封装格式都能闭合。下面这条命令把 H.264 视频和 AAC 音频装进 MP4,像素格式固定为yuv420p,并加上faststart,方便播放器快速起播。
REM 第一次转码:输入输出必须分开,输出目录要提前存在 ffmpeg -hide_banner -i "D:\media\input.mp4" ^ -c:v libx264 -preset medium -crf 23 -pix_fmt yuv420p ^ -c:a aac -b:a 128k -movflags +faststart ^ "D:\media\output.mp4"-i后面是输入文件,路径带空格时一定加双引号;-c:v libx264指定视频编码器,-preset medium是速度与压缩率的折中,-crf 23是质量参数,数值越小越清晰、文件越大;-pix_fmt yuv420p提高播放器兼容性;-c:a aac -b:a 128k重新编码音频;-movflags +faststart把索引前置,适合网页播放和快速预览。命令跑完后不要只看“没有报错”,用ffprobe查一遍输出文件的编码、分辨率、时长和音轨。第一次转码的目标不是压到最小,而是确认整条链路可控。
3. 转码参数怎么落:CRF、码率、像素格式与音频的取舍
ffmpeg 的参数多,但真正影响日常交付的没那么多。视频侧主要是编码器、质量参数、预设、像素格式和帧率;音频侧主要是编码器、码率、采样率和声道;封装侧主要是 MP4 的faststart和音轨映射。参数不是越“高级”越好,先看源文件再定目标,比背一套万能命令更靠谱。下面按“读源、定质量、保兼容、试硬件”四步走。
3.1 先读源:用 ffprobe 决定目标参数
同一个 CRF 在不同源上体感差异很大。手机录屏、相机素材、屏幕录制、动画课件,纹理复杂度和噪声水平完全不同。先跑ffprobe把源文件的视频编码、分辨率、帧率、像素格式、码率、音轨和时长看清楚,再决定是降分辨率、降帧率,还是只换封装。不要拿 4K 竖屏素材直接套 1080p 横屏参数,也不要对已经是 AAC 128k 的音频反复重编码。
REM 读取源文件的关键流信息,先看清楚再定参数 ffprobe -v error ^ -show_entries stream=index,codec_type,codec_name,width,height,r_frame_rate,pix_fmt,bit_rate ^ -show_entries format=duration,bit_rate,format_name ^ -of default=noprint_wrappers=1 ^ "D:\media\input.mp4"-v error只保留错误级日志,输出更干净;-show_entries stream=...只看流级别字段,format=...看容器级时长和总码率;-of default=noprint_wrappers=1去掉多余包装,方便直接读。重点看三件事:源分辨率是否远高于目标、帧率是否虚高、音频是不是已经够用。如果源视频码率很低、分辨率也不高,硬压到更小码率只会把块效应放大;如果源音频已经是 AAC 128k,直接-c:a copy往往比重新编码更稳。
3.2 质量优先还是体积优先:CRF 与目标码率
日常归档我优先用 CRF,也就是固定质量、让码率浮动。CRF 18 到 28 是常见区间,18 接近 visually lossless,23 适合大多数课程和录屏,28 适合只要求能看清的预览文件。预设-preset控制编码速度和压缩效率,medium是默认折中,slow更慢但同质量下体积通常更小,veryfast适合临时预览。目标码率模式适合平台有码率上限或需要估算文件大小的场景,但要配合-maxrate和-bufsize,否则峰值会冲高。
REM 质量优先:CRF 20,适合保存课程主版本 ffmpeg -hide_banner -i "D:\media\input.mp4" ^ -c:v libx264 -preset slow -crf 20 ^ -c:a copy "D:\media\crf20.mp4" REM 体积优先:目标码率 2500k,限制峰值,适合有上限的交付 ffmpeg -hide_banner -i "D:\media\input.mp4" ^ -c:v libx264 -preset medium -b:v 2500k -maxrate 3000k -bufsize 5000k ^ -c:a aac -b:a 128k "D:\media\abr.mp4"第一条命令里-c:a copy表示音频不重编码,省时间也避免二次损失;第二条命令里-b:v是目标视频码率,-maxrate限制峰值,-bufsize控制码率缓冲窗口。码率模式不是越小越好,2500k 对 1080p 课程通常够用,对高动态游戏录屏就可能偏紧。判断标准不是命令是否成功,而是抽几个关键帧看文字边缘、暗部渐变和快速运动画面有没有明显块状。CRF 和码率没有绝对换算关系,同一份素材用 CRF 23 和 2500k 跑出来,体积和画质都可能不一样,必须拿样本对比。
| 场景 | 建议起点 | 注意点 |
|---|---|---|
| 课程录屏、PPT 讲解 | CRF 22-24,preset medium | 文字边缘容易糊,优先保分辨率 |
| 相机素材归档 | CRF 18-21,preset slow | 体积换质量,先跑短样本 |
| 平台上传预览 | 目标码率 1500k-2500k | 配合 maxrate,别只看平均码率 |
| 只求能看的粗剪 | CRF 26-28,preset veryfast | 不要拿它做最终交付 |
3.3 兼容性优先:像素格式、帧率和 faststart
很多“转码成功但播放器黑屏”的问题,不是编码器坏了,而是像素格式或封装索引不兼容。yuv420p是兼容性最稳的像素格式之一,尤其适合老播放器、网页播放和移动端。源文件如果是 10bit、4:2:2 或特殊色彩空间,直接转 H.264 8bit 时最好显式指定-pix_fmt yuv420p。缩放时用scale=1280:-2,高度用-2自动取偶数,避免height not divisible by 2。帧率不要随手改,源是 25 帧就保持 25,源是可变帧率先想清楚是否需要恒定帧率。
REM 兼容性版本:缩放到 1280 宽,高度自动偶数,固定像素格式 ffmpeg -hide_banner -i "D:\media\input.mp4" ^ -vf "scale=1280:-2:flags=lanczos" ^ -c:v libx264 -preset medium -crf 23 -pix_fmt yuv420p ^ -c:a aac -b:a 128k -ar 48000 -ac 2 ^ -movflags +faststart "D:\media\compatible.mp4"-vf "scale=1280:-2:flags=lanczos"里1280是目标宽度,-2表示按比例算高度并取偶数,lanczos是缩放算法,文字和线条较多的素材通常比默认双线性更干净。-ar 48000 -ac 2把音频统一到 48kHz 双声道,适合大多数播放环境;如果源是单声道讲解,强行上双声道不会增加信息,但能减少某些平台的不兼容。-movflags +faststart对 MP4 很重要,它把索引放到文件头,网络播放和拖动进度条更顺。兼容性参数不追求极限压缩,追求的是“拿出去就能放”。
3.4 硬件编码不是一键加速:先做样本对比
Windows 上常见硬件编码器包括h264_qsv、h264_amf、h264_nvenc这类标识,具体支持哪几个,以-encoders输出为准。硬件编码的优点是速度快,缺点是同码率下画质和文件大小不一定优于软件编码,参数名也不一样:软件编码用-crf,硬件编码可能用-global_quality、-cq或-qp,不能直接照搬。正确做法是先截取 10 秒样本,用同一段源分别跑软件编码和硬件编码,比较体积、画质和耗时,再决定批量任务用哪条路线。
REM 先看当前构建支持哪些硬件编码器 ffmpeg -hide_banner -encoders | findstr /i "h264_qsv h264_amf h264_nvenc" REM 截 10 秒做样本,硬件编码参数以实际编码器为准 ffmpeg -hide_banner -t 10 -i "D:\media\input.mp4" ^ -c:v h264_qsv -global_quality 23 ^ -c:a copy "D:\media\sample_qsv.mp4"-t 10放在-i前面表示只读前 10 秒,适合快速试参数;-global_quality 23是某些硬件编码器的质量参数,换到别的编码器可能不认,报错时先查该编码器的帮助。硬件编码初始化失败常见原因包括驱动不匹配、当前会话没有可用硬件、分辨率或像素格式不支持。遇到这类问题不要死磕,先用libx264把任务跑完,再拿小样本回头试硬件路线。批量任务里混用硬件和软件编码,最好在文件名或日志里标清楚,否则后面复盘时根本分不清哪批文件是哪种参数出来的。
4. 批量与管道:把 Windowsffmpeg 塞进文件夹、脚本和日志
单个文件转码只是起点,真正耗时间的是成批素材。Windows 上批量跑 ffmpeg,核心不是写多复杂的脚本,而是处理三件事:文件名里的空格和中文、循环里的变量转义、失败后别把半成品当成品。cmd 批处理和 PowerShell 都能做,前者短平快,后者对路径和退出码更稳。先写最小循环,再补日志和临时文件,别一上来就堆一堆重试逻辑。
4.1 cmd 批处理:最小可用循环与 %% 转义
cmd 批处理适合放在固定文件夹里双击运行。注意在.bat文件里,循环变量要写%%F,在命令行交互窗口里才写%F。%%~fF取完整路径,%%~nF取不带扩展名的文件名,%%~nxF取带扩展名的文件名。输入目录和输出目录分开,输出目录不存在先创建,失败时把文件名追加到failed.txt,不要只让窗口一闪而过。
@echo off setlocal enabledelayedexpansion set "IN_DIR=D:\media\raw" set "OUT_DIR=D:\media\out" if not exist "%OUT_DIR%" mkdir "%OUT_DIR%" for %%F in ("%IN_DIR%\*.mov") do ( echo [RUN] %%~nxF ffmpeg -hide_banner -y -i "%%~fF" ^ -c:v libx264 -preset medium -crf 23 -pix_fmt yuv420p ^ -c:a aac -b:a 128k "%OUT_DIR%\%%~nF.mp4" if errorlevel 1 echo [FAIL] %%~nxF>>"%OUT_DIR%\failed.txt" ) endlocalset "IN_DIR=..."用引号包住赋值,避免路径末尾空格进入变量;for %%F in ("%IN_DIR%\*.mov")只匹配 mov 文件;%%~fF和%%~nF是批处理扩展语法,分别拿全路径和主文件名。-y表示覆盖已存在输出,批量任务里要谨慎,最好配合后面的临时文件方案。if errorlevel 1判断上一条命令是否非零退出,失败才写清单。这个脚本没有处理子目录,也没有跳过已完成文件,适合第一轮跑通;一旦素材量大,就要加日志和跳过逻辑。
4.2 PowerShell:空格、中文路径和退出码
PowerShell 对路径的处理比 cmd 稳,尤其是文件名带空格、中文、方括号时。关键点是使用-LiteralPath避免通配符解释,使用&调用外部程序,使用$LASTEXITCODE判断 ffmpeg 是否成功。Get-ChildItem拿到的是文件对象,$_.FullName和$_.BaseName比手工拼字符串可靠。输出文件已存在时先跳过,避免重复跑同一批任务。
$inDir = 'D:\media\raw' $outDir = 'D:\media\out' New-Item -ItemType Directory -Force -Path $outDir | Out-Null Get-ChildItem -LiteralPath $inDir -Filter *.mov -File | ForEach-Object { $dst = Join-Path $outDir ($_.BaseName + '.mp4') if (Test-Path -LiteralPath $dst) { Write-Host "[SKIP] $($_.Name)" return } & ffmpeg -hide_banner -y -i $_.FullName ` -c:v libx264 -preset medium -crf 23 -pix_fmt yuv420p ` -c:a aac -b:a 128k $dst if ($LASTEXITCODE -ne 0) { Add-Content -LiteralPath (Join-Path $outDir 'failed.txt') -Value $_.FullName } }-LiteralPath让方括号、星号这类字符按字面处理;Join-Path拼输出路径,避免手工加反斜杠;& ffmpeg是显式调用外部命令,参数里的$_.FullName即使带空格也会作为一个参数传入。$LASTEXITCODE -ne 0是判断失败的关键,PowerShell 不会因为外部程序报错就自动抛异常。return在ForEach-Object脚本块里表示跳过当前项,不是退出整个脚本。这个版本仍然会覆盖已存在文件之前先跳过,适合补跑;如果要做“强制重跑”,把Test-Path那段去掉即可。
4.3 进度、日志与失败重试:让批次可复盘
批量转码最怕“跑到一半断了,不知道断在哪”。ffmpeg 默认把进度打在 stderr 上,窗口一关就没了。可以用-progress pipe:1把结构化进度输出到 stdout,用-nostats关掉默认进度条,再把 stderr 重定向到日志文件。日志文件名按输入文件命名,失败时能直接定位。重试不要无限循环,设 2 到 3 次,每次失败后等两秒,仍然失败就写清单,别让一个坏文件拖住整批。
REM 结构化进度输出到 stdout,错误日志单独落到文件 ffmpeg -hide_banner -nostats -progress pipe:1 -loglevel warning ^ -i "D:\media\raw\demo.mov" ^ -c:v libx264 -preset medium -crf 23 -pix_fmt yuv420p ^ -c:a aac -b:a 128k "D:\media\out\demo.mp4" ^ 2>"D:\media\logs\demo.log"-progress pipe:1输出的是一行行key=value,比如out_time_ms、speed、progress,适合被脚本读取;-nostats关掉默认的实时统计;-loglevel warning只保留警告和错误,减少日志体积;2>把 stderr 写到日志文件。日志目录要提前存在,否则重定向会失败。批量脚本里可以把demo换成循环变量,但要注意 cmd 的变量延迟展开,必要时用!而不是%。失败重试的逻辑建议放在外层,不要塞进 ffmpeg 参数里,ffmpeg 本身不负责重试。
4.4 输入输出分离:临时目录与命名规则
批量任务最危险的写法是直接输出到最终目录,并且用-y覆盖。一旦编码中途失败,最终目录里可能留下一个打不开的半成品,后面的人以为任务已经完成。稳妥做法是先写到临时目录,文件名带.part.mp4之类的标记,退出码为 0 再移动到最终目录。输入目录只读,输出目录分层,日志目录单独放,命名规则固定为“主文件名 + 参数标识”,后面排查时一眼能看出是哪条命令跑出来的。
set "IN_FILE=D:\media\raw\demo.mov" set "TMP_OUT=D:\media\tmp\demo.part.mp4" set "FINAL_OUT=D:\media\out\demo.mp4" ffmpeg -hide_banner -y -i "%IN_FILE%" ^ -c:v libx264 -preset medium -crf 23 -pix_fmt yuv420p ^ -c:a aac -b:a 128k "%TMP_OUT%" if not errorlevel 1 move /y "%TMP_OUT%" "%FINAL_OUT%"临时文件放在单独目录,失败时不会污染最终交付目录;if not errorlevel 1表示上一条命令成功才移动。move /y会覆盖同名成品,所以最终目录的命名规则要能区分版本,比如加_crf23或_compatible后缀。临时目录最好定期清理,否则失败任务会越积越多。这个模式看起来多了一步,但它能避免“文件存在但内容是坏的”这种最难排查的情况。
5. 避坑与排查:Windows 上 ffmpeg 最常见的五类翻车
ffmpeg 的报错通常很长,真正有用的信息往往在最后十几行。Windows 上还有一批平台特有的坑:PATH 多版本、路径空格、文件占用、编码器缺失、批处理继续覆盖。下面五类问题按“现象、原因、解决”拆开写,遇到报错先对号入座,再去看完整日志。
5.1 现象:命令找不到,或者跑的不是同一份 ffmpeg
现象是终端提示'ffmpeg' 不是内部或外部命令,或者明明改了参数,输出却和预期不一样。原因通常有两个:PATH 没配到bin目录,或者机器上有多份 ffmpeg,终端命中了旧的那份。另一个隐蔽原因是改完 PATH 没开新终端,旧窗口还拿着旧环境变量。解决时先where ffmpeg看命中路径,再用完整路径D:\tools\ffmpeg\bin\ffmpeg.exe -version跑一次,确认这份构建本身正常。如果 PATH 里有多个条目,把固定工具目录放到前面,或者干脆在脚本里写完整路径。不要用setx反复追加,容易把用户 Path 越写越乱;改完用[Environment]::GetEnvironmentVariable('Path','User')读回来核对。
5.2 现象:Unknown encoder,或者硬件编码初始化失败
现象是Unknown encoder 'libx264',或者指定h264_qsv、h264_amf、h264_nvenc后提示初始化失败。前者说明当前构建不带这个编码器,-encoders输出里查不到就不要硬写;后者多半是驱动、会话或参数不匹配。解决顺序是:先ffmpeg -hide_banner -encoders确认编码器存在,再用libx264跑软件编码排除素材问题,最后拿 10 秒样本试硬件编码。硬件编码的参数名不统一,-crf不一定适用,报错时看完整日志里是“编码器未找到”还是“初始化设备失败”。批量任务里不要把硬件编码当默认路线,除非样本对比证明它在你当前机器上稳定且画质可接受。
5.3 现象:中文、空格路径报错,或者输出文件被占用
现象是Could not open file、No such file or directory,但文件明明存在;或者转码到一半提示写入失败。原因通常是路径没加引号、PowerShell 没使用-LiteralPath、输出文件正被播放器或同步盘占用。Windows 路径里的空格、方括号、中文都可能触发解析问题。解决时输入输出路径统一加双引号,PowerShell 用-LiteralPath,批处理用"%%~fF"这种扩展语法。输出文件被占用时先关掉播放器、预览窗口和同步盘客户端,再重跑。路径过长也会失败,尽量把工作目录放在短路径下,比如D:\media\work,不要层层嵌套到桌面深处。
5.4 现象:转码成功但播放器黑屏、无声音或花屏
现象是命令退出码为 0,文件也能生成,但播放器黑屏、只有声音没有画面、或者画面花屏。常见原因是像素格式不兼容、音轨没有映射、源文件本身是可变帧率或损坏。解决时先ffprobe查输出文件的视频流和音频流是否存在,再显式加-pix_fmt yuv420p,多音轨素材用-map 0:v:0 -map 0:a?明确选流。黑屏还要看是不是只转了封面图或字幕流;无声音要确认-c:a没写错,或者源文件本来就没有音频。花屏可能是源文件损坏或解码失败,先拿原文件在其他播放器里确认,再决定是否重新转码。不要只看“转完了”,一定抽帧和试播。
5.5 现象:批处理中途失败,却继续覆盖成品
现象是批量脚本跑完后,有的文件大小正常,有的只有几 KB,有的干脆打不开;重跑一遍又把好文件覆盖了。原因是脚本用了-y直接写最终目录,却没有判断errorlevel或$LASTEXITCODE。解决方法是先写临时文件,成功后再移动;失败文件写入failed.txt,不要自动删除;重跑时先跳过已存在的成品。cmd 里用if errorlevel 1,PowerShell 里用$LASTEXITCODE -ne 0。如果任务很长,给日志目录按日期分文件夹,别让所有日志堆在一个文件里。批量任务的可复盘性,比单条命令跑得快更重要。
6. 进阶验证与交付:用 ffprobe 做闭环,别只看“转完了”
转码命令返回 0 只说明进程正常结束,不说明文件适合交付。我现在的习惯是每个成品都跑一遍ffprobe,看编码、分辨率、像素格式、帧率、时长和文件大小是否符合预期,再抽一帧关键画面确认没有黑屏或花屏。下面这条命令适合做交付前检查,输出干净,关键字段一眼能看完。
REM 交付前检查:看视频流关键字段和容器时长、大小 ffprobe -v error -select_streams v:0 ^ -show_entries stream=codec_name,width,height,pix_fmt,r_frame_rate,duration ^ -show_entries format=duration,size ^ -of default=noprint_wrappers=1 ^ "D:\media\out\demo.mp4"-select_streams v:0只看第一条视频流,避免多流输出干扰;stream=...检查编码、宽高、像素格式、帧率和流时长;format=...检查容器总时长和文件大小。如果pix_fmt不是yuv420p,而交付环境又是老播放器,就回头补-pix_fmt yuv420p;如果流时长和容器时长差得离谱,检查是不是音轨或字幕流拖长。再抽一帧:
ffmpeg -hide_banner -ss 00:00:05 -i "D:\media\out\demo.mp4" -frames:v 1 -y "D:\media\out\check.png"-ss放在-i前是快速定位,-frames:v 1只取一帧,-y覆盖旧检查图。抽帧图不用精修,只看画面有没有黑屏、比例有没有变形、文字边缘是否可读。从那以后我每次批量交付前都强制走一遍ffprobe加抽帧,不再凭“命令没报错”下结论;这份 Windows ffmpeg 运行目录也一样,先把bin、PATH、ffprobe三件事核对清楚,再谈压缩率和速度。希望帮到你。
本文还有配套的精品资源,点击获取