☰
一堆视频要发不同平台?用 ffmpeg + Python 批量转码、改分辨率并抽封面
2026/10/4 19:55:10 网站建设 项目流程

做内容的人迟早会遇到这个场景:同一段素材,要发 YouTube / B站(横屏 16:9 1080p)、又要剪竖版发抖音 / Reels / Shorts(9:16)、还得给微信压个小文件、甚至抽一张封面当缩略图。手动在剪辑软件里一个个另存太耗时间,而且参数容易前后不一致。

本文给一套本地可跑的批量方案:用 Python 遍历目录,按平台预设自动拼 ffmpeg 参数,批量完成转码、改分辨率比例、音频响度归一化、抽封面。读完你有一份脚本,丢个文件夹进去就能把整批素材按各平台规格出齐。

命令和脚本都按实测流程梳理过,配好 ffmpeg 就能复用;ffmpeg 没装的先去装一下并确认ffmpeg -version能跑。

一、先理清:转码到底在改什么

很多人把"格式转换"和"转码"混为一谈,结果文件没变小、画质还掉了。先记这张表:

概念是什么常见坑
容器(Container)文件外壳,mp4 / mkv / mov改容器不重编码(-c copy)最快,但平台可能不支持某些容器
视频编码(Codec)画面压缩方式,H.264 / H.265老设备不认 H.265;网页播放认 H.264 最稳
分辨率 / 比例1920x1080(16:9)、1080x1920(9:16)直接scale不改比例会拉伸变形
码率 / CRF画质与体积的平衡CRF 越小越清晰越大;固定码率易浪费或不够
音频AAC 最通用;响度要统一不同平台对响度(LUFS)有目标值,不统一观众要手动调音量

核心结论:横屏、竖屏、小文件是三套不同需求,不能只改个后缀。下面按需求分别给命令。

二、单条命令打底:最稳的 H.264 MP4

先有一条万金油命令,理解每个参数为什么在这:

ffmpeg-y-iinput.mp4\-c:vlibx264-crf23-presetmedium\-c:aaac-b:a192k\-movflags+faststart\output.mp4
  • -crf 23:恒定质量,18~28 之间调,越小越清晰体积越大(23 是性价比甜点)。
  • -preset medium:编码速度与压缩率的平衡,veryslow 更省体积但慢。
  • -c:a aac -b:a 192k:音频转 AAC,192k 足够人声。
  • -movflags +faststart:把索引移到文件头,网页边下边播不卡——发网络平台必加,否则首帧要等整段下完。

三、改分辨率与比例:横屏 / 竖屏都不拉伸

横屏 1080p(YouTube / B站)

ffmpeg-y-iinput.mp4-vf"scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2"-c:vlibx264-crf23-c:aaac-b:a192k-movflags+faststart out_1080p.mp4

force_original_aspect_ratio=decrease+pad是关键:先把画面等比缩到不超出 1920x1080,再用黑边补齐,避免非 16:9 素材被拉变形。

竖屏 9:16(抖音 / Reels / Shorts)

ffmpeg-y-iinput.mp4-vf"scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1"-c:vlibx264-crf24-c:aaac-b:a192k-movflags+faststart out_vertical.mp4

横屏源(1920x1080)经此会变成 1080x1920、上下补黑边的竖版,上传短视频平台不会被二次裁切。setsar=1修正采样宽高比,防止某些播放器比例错乱。

微信小文件(降分辨率 + 提 CRF)

ffmpeg-y-iinput.mp4-vf"scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2"-c:vlibx264-crf28-c:aaac-b:a128k-movflags+faststart out_small.mp4

CRF 提到 28、分辨率降到 720p,体积通常能砍掉一大半,适合聊天工具发送。

四、音频响度归一化:让整批声音一样大

不同设备录的素材音量参差,拼到一起观众要不停调音量。用loudnorm把响度拉到平台目标(如 YouTube 建议约 -14 LUFS)。单条最稳写法:

ffmpeg-y-iinput.mp4-af"loudnorm=I=-14:TP=-1.5:LRA=11"-c:vcopy out_norm.mp4

这条是单遍近似,足够日常。要更准就做两遍测量——第一遍只测不输:

ffmpeg-iinput.mp4-af"loudnorm=I=-14:TP=-1.5:LRA=11:print_format=json"-fnull -

从 stderr 里读Input Integrated / Input True Peak / Input LRA,再喂回第二遍的measured_I / measured_TP / measured_LRA,精度更高但脚本略长,批量时按需取舍。

五、抽封面 / 关键帧

发布前常要一张缩略图。用-ss放在-i前面做快速定位,抽第 3 秒一帧:

ffmpeg-y-ss00:00:03-iinput.mp4-frames:v1-q:v2cover.jpg

-q:v 2是 JPEG 质量(2~31,越小越好)。想批量抽每段的封面,把时间参数化即可。

六、批量脚本:一个文件夹按平台预设出齐

把上面拼成可复用脚本batch_transcode.py,核心是用「平台预设字典」驱动参数,避免每回手写命令:

importsubprocess,jsonfrompathlibimportPathfromconcurrent.futuresimportThreadPoolExecutor PRESETS={"youtube":{"scale":"1920:1080","crf":23,"ab":"192k","suffix":"_1080p"},"vertical":{"scale":"1080:1920","crf":24,"ab":"192k","suffix":"_vertical"},"wechat":{"scale":"1280:720","crf":28,"ab":"128k","suffix":"_small"},}defbuild_filter(scale:str)->str:return(f"scale={scale}:force_original_aspect_ratio=decrease,"f"pad={scale}:(ow-iw)/2:(oh-ih)/2,setsar=1")deftranscode(src:Path,dst:Path,p:dict):vf=build_filter(p["scale"])cmd=["ffmpeg","-y","-i",str(src),"-vf",vf,"-c:v","libx264","-crf",str(p["crf"]),"-c:a","aac","-b:a",p["ab"],"-movflags","+faststart",str(dst),]r=subprocess.run(cmd,capture_output=True,text=True)ifr.returncode!=0:print(f"[FAIL]{src.name}:{r.stderr[-300:]}")else:print(f"[OK]{dst.name}")defextract_cover(src:Path,cover:Path):subprocess.run(["ffmpeg","-y","-ss","00:00:03","-i",str(src),"-frames:v","1","-q:v","2",str(cover)],capture_output=True,)defrun(folder:str,platforms=("youtube","vertical","wechat")):base=Path(folder)out=base/"transcoded"out.mkdir(exist_ok=True)jobs=[]forfinbase.glob("*.mp4"):cover=out/f"{f.stem}_cover.jpg"jobs.append((extract_cover,(f,cover)))fornameinplatforms:p=PRESETS[name]dst=out/f"{f.stem}{p['suffix']}.mp4"jobs.append((transcode,(f,dst,p)))# 并发提速:ffmpeg 吃满单核,线程数≈CPU 核数最划算withThreadPoolExecutor(max_workers=4)asex:forfn,argsinjobs:ex.submit(fn,*args)if__name__=="__main__":run("D:/videos/inbox")# 改成你的素材目录

要点:

  • 预设集中管:分辨率、CRF、码率全在PRESETS里,新增平台(比如 B站)只是加一行字典。
  • force_original_aspect_ratio=decrease+pad:保证任何比例源都不拉伸。
  • 并发:ffmpeg 单任务基本只吃满一个核,max_workers=4左右能线性提速;机械盘别开太高,IO 会成瓶颈。
  • 失败不中断:returncode != 0只打印 stderr 尾部,跳过坏文件继续跑整批。

七、平台预设速查表

平台比例 / 分辨率建议 CRF音频备注
YouTube / B站16:9 · 1920x108023AAC 192k+faststart 必加
抖音 / Reels / Shorts9:16 · 1080x192024AAC 192k黑边补齐,别拉伸
微信 / 聊天发送16:9 · 1280x72028AAC 128k体积优先
播客音频版仅音轨—AAC 192k-vn丢掉画面

只想要音频版(比如把视频里的讲话单独出一条音频):

ffmpeg-y-iinput.mp4-vn-c:aaac-b:a192k out_audio.m4a

八、踩坑复盘

  • 竖屏被拉变形:直接scale=1080:1920会把 16:9 横屏硬拉成瘦长。务必配force_original_aspect_ratio=decrease+pad黑边补齐。
  • 网页首帧卡:忘了-movflags +faststart,mp4 索引在文件尾,浏览器得下完才播。发网络必加。
  • 音频播不了:某些平台对 mp3 音轨支持差,统一转aac最稳;老设备认 H.264 不认 H.265,默认用libx264。
  • 中文路径报错:ffmpeg 对含中文的路径偶发编码问题,脚本里用Path传str()基本能跑,实在不行把目录改成英文。
  • 旋转元数据:手机横拍竖持的素材可能带 rotate 标记,ffmpeg 不自动应用,加-metadata:s:v:0 rotate=0或在滤镜里transpose修正,否则画面歪。
  • HDR / 10bit 掉色:源是 HDR 时转 SDR 会发灰,需显式加format=yuv420p并考虑 tonemap 滤镜,否则颜色翻车。
  • CRF 不是越小越好:18 以下体积暴涨、肉眼难分;批量统一用 23~28 最省心。

九、自己写脚本 vs 直接用在线方案

场景推荐方案说明
固定风格、批量、可复现Python + ffmpeg 脚本一次写好反复跑,参数统一
临时一段视频想翻成多语言版在线一站式方案 AI Video Translator上传本地视频即可产出翻译 / 配音版
只发单一平台单条 ffmpeg 命令不必上脚本

如果你手头的视频不止要转码,还想要多语言字幕或配音版本,可以先用 AI Video Translator(aivideotranslator.ai)处理:它支持上传本地视频(MP4 / MOV / WebM 等,单个最长 60 分钟),在线免费、无需注册,上传后在编辑器里挑音色就能生成带 AI 配音的版本,免去了自己搭 ASR + 翻译 + TTS 管线的功夫。导出的 MP4 再按上面各平台规格批量转码,整套本地化发布流程就闭环了。

注:上一段提到的界面里有「AI Dubbing 300+ Voices」音色选择区,上传本地视频后可在编辑器按语言 / 性别 / 年龄 / 场景挑音色生成配音版(图见产品官网,本文不附链接)。

十、小结

视频多平台发布的本质就是按平台规格批量重组容器、编码、比例、响度:

  1. 用PRESETS字典把每平台的 scale / CRF / 码率固化,Python 遍历目录统一出片;
  2. 比例用force_original_aspect_ratio=decrease+pad黑边补齐,绝不硬拉;
  3. 音频loudnorm归一化到目标 LUFS,网页发布加-movflags +faststart;
  4. -ss前置快速抽封面,并发ThreadPoolExecutor提速整批。

最容易被卡住的是竖屏变形和漏加 faststart这两步——套用本文的build_filter和命令模板基本能规避。把脚本存成batch_transcode.py、改一下run("你的目录")就能开跑;先拿一两个文件试参数,确认画面比例和音量都对了再跑全批。

需要把视频翻成多语言字幕 / 配音版再发布的,官网见评论区。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询