ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AI+FFmpeg实战:自制轻量录屏工具全解析

2026/9/10 23:03:56 拓冰建站 浏览量
AI+FFmpeg实战:自制轻量录屏工具全解析 十几年前我第一次折腾录屏用的是各种破解版录屏软件当时觉得能录个屏幕已经挺了不起。后来付费软件越做越重启动慢、广告多、导出一段视频还要看会员脸色我实在忍不了。加上我本来干的就是技术这行手里又有AI和FFmpeg这两件趁手工具于是花了一个周末从零折腾出一个适合自己工作流的桌面录屏工具。这个过程对我触动很大原来一个日常需求只要把需求拆细、把AI当同事用、把FFmpeg当发动机完全可以从“买工具”变成“造工具”而且最后的成品比那些商业软件更贴合我的用法。这篇博文会把整个项目从头到尾拆开讲为什么动手、怎么选方案、FFmpeg录制屏幕的核心参数怎么配、AI辅助编程的过程能到什么程度、遇到了哪些坑以及最后成品和付费软件的真实对比。无论你是想找一个轻量录屏方案的最终用户还是想学AI辅助开发的技术爱好者应该都能从这里拿走点能直接用的东西。1. 项目从“为什么”开始付费软件逼我动手1.1 用着难受的录屏软件先说背景。我日常要给内部团队录产品演示视频、给别人讲代码逻辑偶尔还要录线上会议的存档。需求看上去很简单把屏幕画面和声音一起录下来导出成mp4画质清晰、文件别太大。市面上不是没有工具。免费方案要么有录制时长限制、要么带个甩不掉的水印要么帧率低到拖动鼠标都有残影。付费方案确实专业但一年几百块的订阅费换来一堆我根本用不到的剪辑、字幕、在线分享功能。最让我烦躁的是那些软件为了“全家桶”体验强制让我注册账号、登录、上传云空间一个本地录制功能搞成了联网服务。我试着回归到最简单的思路录屏的本质不就是“连续截屏 编码成视频”吗这事操作系统本身就能干为什么非要套一层商业软件1.2 为什么选了“AI FFmpeg”这条路我评估过几条技术路线。第一条是直接用系统API比如Windows的Graphics Capture API或者macOS的ScreenCaptureKit。这条路最底层、最可控但开发量也最大要处理设备枚举、帧格式转换、编码器对接、音频采集、时序同步一个人没有几周时间很难做出顺手的东西。第二条是用现成的Python库比如mss、Pillow加上imageio靠“循环截屏喂给编码器”来实现。这个方案代码量少但性能是硬伤。屏幕一复杂CPU占用飙升录出来的视频明显卡顿因为Python层做图像搬运和编码的效率比原生方案差太多。第三条就是我最终选的路用FFmpeg做底层的采集和编码引擎代码只负责拼命令、管流程、做交互界面。FFmpeg是几十年的开源项目全平台支持屏幕采集、音频采集、编码、封装全都内置好了命令行的设计也足够稳定。我负责的只是把它包装成一个适合自己用的图形工具。那AI在这个项目里扮演什么角色坦白讲AI不是让我“不用懂技术”它更像一个随叫随到的老同事。我不熟悉的FFmpeg参数它帮我解释我不想从头写的GUI骨架代码它帮我搭我遇到报错信息一头雾水的时候它帮我把错误拆开、定位问题。我负责把关方案、验证结果、做技术决策它负责把“我知道大概怎么做”变成“立刻能跑的代码”。1.3 项目目标与技术边界动手之前我给这个工具划定了明确的目标和边界避免做成一个收不了尾的大坑。核心需求是四个全屏或选区录制系统声音 麦克风声音同步录制暂停、继续、停止自动编码为H.264的mp4文件画质和体积可控不做的功能也提前想清楚了不做视频剪辑、不做网络推流、不做花哨样式的水印、不做账号系统。所有功能都围绕“本地快速录制并导出”展开。技术选型上我锁定Python做GUI和应用逻辑因为AI辅助写Python代码的成熟度最高而且PySide6做出来的界面跨平台、观感也好。底层完全交给FFmpeg命令行进程不引入官方开发库。这样好处很明显FFmpeg的升级、格式支持扩展都不需要改动我的代码只要命令参数正确就能持续受益。2. 吃透核心技术FFmpeg录屏是怎么一回事2.1 FFmpeg录屏的底层输入方式FFmpeg不是一个“录屏软件”它是一个多媒体处理框架。想让它录屏关键是理解“输入设备”和“输出文件”这两个概念。在Windows上录制屏幕通常用的是gdigrab输入设备。这个名字的意思是GDIGraphics Device Interface抓取也就是Windows图形系统提供的一个经典屏幕捕获接口。最常用的命令长这样ffmpeg -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 1920x1080 -i desktop -c:v libx264 -preset ultrafast -crf 28 output.mp4把这条命令拆开看-f gdigrab告诉FFmpeg使用GDI抓屏作为输入。-framerate 30采集帧率。30帧是通用值录PPT演示足够如果是游戏画面建议60帧。-offset_x 0 -offset_y 0画面偏移量定位录制的起点。-video_size 1920x1080录制区域的尺寸。-i desktop输入名字用desktop表示整个桌面如果指定窗口句柄也能只录某个窗口。-c:v libx264视频编码器用H.264兼容性最好的格式。-preset ultrafast编码速度优先牺牲一点压缩率换低CPU占用。-crf 28质量参数数值越小画质越好、文件越大。如果是macOS输入设备就不一样了要用avfoundationffmpeg -f avfoundation -framerate 30 -i 1:none -c:v libx264 output.mp4其中1是屏幕设备编号可以用ffmpeg -f avfoundation -list_devices true -i 查看。Linux则通常是X11的x11grabffmpeg -f x11grab -framerate 30 -video_size 1920x1080 -i :0.0 -c:v libx264 output.mp4我用的是Windows系统所以下面的详解都以gdigrab为主。这个方案有个潜在限制是GDI抓屏在某些高刷新率或高分辨率场景下性能一般但对办公、教学、演示这类场景完全够用。如果以后有更高性能需求Windows还有dxgi、ddagrab等更底层的方案FFmpeg都支持。2.2 音频采集与同步最容易翻车的部分画面搞定之后声音才是真正的考验。录屏没有声音等于白录但Windows的音频采集历史包袱特别重。FFmpeg在Windows上录制音频用的是dshow设备全称DirectShow。想录系统内部播放的声音得先找到对应的音频设备。我的做法是先枚举一遍设备。ffmpeg -list_devices true -f dshow -i dummy这条命令会列出当前机器上所有DirectShow输入设备。通常会有麦克风Microphone、扬声器设备还有“立体声混音”Stereo Mix。立体声混音是声卡提供的回环设备可以把正在播放的声音“绕回”到输入端。录系统声音一般就是靠它。真正稳定跑通的音频命令是分两条输入来做的ffmpeg -f gdigrab -framerate 30 -i desktop ^ -f dshow -i audio麦克风阵列 ^ -f dshow -i audio立体声混音 ^ -filter_complex [1:a][2:a]amixinputs2:durationlongest[aout] ^ -map 0:v -map [aout] ^ -c:v libx264 -preset ultrafast -crf 28 -c:a aac -b:a 192k output.mp4这里用了-filter_complex把两路音频混在一起再用-map把视频流和混音后的音频流写进最终文件。如果不想混麦克风只要系统声音那就只保留立体声混音那一路能少一层麻烦。但这里有个大坑不是每台电脑的声卡驱动都暴露了“立体声混音”设备。很多笔记本的板载声卡驱动干脆屏蔽了这个选项。后来的Windows版本有一个更现代的方案叫WGCWindows Graphics Capture它配合音频会话API可以捕捉到具体某个应用的声音但那需要写WinRT代码不是纯FFmpeg命令行能解决的。所以我的工具里做了两手准备检测到立体声混音就直接用检测不到就提示用户去声音设置里手动启用或者退回“只录麦克风”模式。2.3 编码参数怎么取舍体积、画质、性能的三角关系音频视频都搞定后编码参数决定了最终文件质量和体积。这里没有完美方案只有取舍。我最早图省事直接-preset ultrafast不打crf参数默认用默认质量。结果录了一个30分钟的会议生成的mp4高达4GB。后来加了-crf 28同样的内容体积降到1.2GB肉眼几乎看不出画质差异但CPU消耗也确实上升了一些。FFmpeg的H.264编码有两大控制维度-preset编码速度。越快的presetCPU占用越低、压缩效率越差越慢的preset压缩率越好、生成文件越小但编码时CPU会拉满。-crf恒定质量因子。数值范围通常是0到51越小质量越高。视频界有个常用结论CRF 18视觉上有损但难以察觉CRF 23是默认质量CRF 28就能明显减小体积适合录屏这种画面变化不大的场景。录屏内容的特点是变化区域少、静止区域多这类画面非常适合H.264的高效压缩。我实测下来office操作类录制用-preset veryfast -crf 28能兼顾CPU占用和文件体积。游戏类画面变化大CRF可以降到20preset也用fast不过那时候CPU占用也会明显上来。一个我后来才注意到的参数是-g也就是关键帧间隔。默认值通常太大导致拖动进度条时画面要卡很久才能出图。我在命令里显式加了-g 60让每60帧一个关键帧2秒一个回放体验好了很多。2.4 为什么不直接调FFmpeg库而走命令行开发过程中有朋友问我你都写代码了为什么不直接用FFmpeg的C库或者Python的封装这样更底层、性能更好我确实试过Python的ffmpeg-python这个库它本质上是帮你拼接命令行参数的语法糖并不是真正的库绑定。我也看过av( PyAV )这种真正的绑定库它能直接操作帧、编解码上下文能力确实强但学习曲线陡峭而且录屏这种场景里命令行的灵活性已经完全够用。核心原因是命令行FFmpeg是一个成熟的“外部引擎”它已经替我把设备枚举、帧抓取、编码、封装这些脏活都做了。我只需要管理进程生命周期、解析它的输出日志、动态拼接参数即可。这样我的代码量大幅减少核心逻辑也更不容易出错。真要哪一天FFmpeg更新了一个更好的录屏设备我只要改命令模板不用重新开发编码层。不过用命令行有一个必须注意的点FFmpeg的启动和停止不是即时的。启动要等编码器初始化正常停止要发q命令给它它会优雅地把已编码文件写完。千万不能用简单粗暴的方式杀进程否则极大概率得到损坏的视频文件。后面我专门设计了一套信号处理逻辑来应对这个问题。3. AI从“玩具”到“生产力”我是怎么用它写代码的3.1 让AI先搭骨架用对话拆需求很多人用AI写代码的姿势是直接把需求丢过去“帮我写个录屏软件”。AI确实能吐出来几百行代码但往往是一个玩具级的demo离可用差很远。我的做法是把需求拆成对话回合让AI逐步产出模块。第一轮我只让它搭GUI框架一个窗口三个按钮开始、暂停、停止一个显示状态的文本框一个用于选保存路径的控件。这一轮的目的是验证整个项目的基础结构能不能跑起来同时确认它用的库在虚拟环境里已经装好。第二轮我丢给它一个具体的FFmpeg命令模板让它把命令封装成一个handlers类负责启动子进程、按需发送控制信号、读取输出。AI一开始给我写的代码里有一个明显的隐患它直接用subprocess.Popen启动ffmpeg后就立刻进入阻塞循环导致GUI界面卡死。后来我让它改成用子线程跑进程再加上QTimer或信号槽机制把状态回传给界面这个问题才解决。第三轮处理暂停与恢复。这一轮AI给出的第一版方案不理想它试图往一个正在进行中的ffmpeg进程发送复杂的滤镜指令这在命令行场景下行不通。我否掉了这个方案改成“分片录制后合并”。AI做出来的分片合并逻辑总体可靠时间复杂度也低。它写完后我发现一个bug合并用的concat协议要求所有分片编码参数必须完全一致AI默认生成的代码里混入了一个细微的差异——第一片用了不同的crf值。这种细节人力review时很容易漏掉但确实会让合并失败这也是为什么不能把AI的代码当成品直接用。3.2 关键代码逐段过录屏核心模块核心录屏模块我最后整理成了大约150行Python代码拆成三个类来组织。第一个类是RecorderConfig单纯的数据容器保存帧率、区域坐标、音频设备、是否需要混音、输出目录、CRF、PRESET这些值。把配置集中起来后续改界面和命令生成都方便。第二个类是FFmpegCommandBuilder负责根据配置生成命令行参数列表。举个片段import shlex def build_command(self, cfg: RecorderConfig) - list[str]: cmd [ ffmpeg, -f, gdigrab, -framerate, str(cfg.fps), ] if cfg.region: cmd [-offset_x, str(cfg.region[0]), -offset_y, str(cfg.region[1])] cmd [-video_size, f{cfg.region[2]}x{cfg.region[3]} if cfg.region else 1920x1080] cmd [-i, desktop] # 音频输入麦克风、系统声、或两者 if cfg.enable_mic and cfg.enable_system_audio: cmd [-f, dshow, -i, faudio{cfg.mic_device}] cmd [-f, dshow, -i, faudio{cfg.system_device}] cmd [-filter_complex, [1:a][2:a]amixinputs2:durationlongest[aout], -map, 0:v, -map, [aout]] elif cfg.enable_mic: cmd [-f, dshow, -i, faudio{cfg.mic_device}, -map, 0:v, -map, 1:a] elif cfg.enable_system_audio: cmd [-f, dshow, -i, faudio{cfg.system_device}, -map, 0:v, -map, 1:a] else: cmd [-map, 0:v] cmd [ -c:v, libx264, -preset, cfg.preset, -crf, str(cfg.crf), -g, 60, -c:a, aac, -b:a, 192k, ] cmd [cfg.output_path] return cmd注意我全程用参数列表而不是一个超长的字符串。原因很实际参数里可能有空格、中文路径如果用shlex拼接字符串再split很容易在各种奇怪的文件名上出错。参数列表能直接绕过shell解析规避一整个类别的bug。第三个类是RecorderEngine负责进程管理。它的核心逻辑就三件事启动时记录PID并进入等待循环暂停时给进程发暂停信号并保存切片停止时优雅退出并把分片合并。AI给过我用send_signal(signal.SIGSTOP)做暂停的方案我最后没有采纳原因后面会细说。3.3 AI的方案能信几分怎么交叉验证这一年度跑下来我的结论是AI生成的代码水平大概相当于一个记性好、速度极快但缺乏实战经验的实习生。它的优势是语法几乎不会错API调用看着都很合理劣势是它经常忽略真实世界的复杂性比如设备权限、进程生命周期、用户误操作、跨平台兼容性。所以我对AI的产出有一套固定的验证流程。第一步让AI解释它自己的代码。我会逐段贴回去问“这里为什么用这个参数”“这个分支在什么情况下触发”。AI如果强行编一个理由很容易被我抓住因为它对运行时细节的描述经常是含糊的。第二步构造最小复现实验。比如它生成了一段gdigrab命令我会先手工在命令行里跑一遍确认参数有效再把命令交给代码去执行。先验证底层命令再验证代码封装这个顺序不能反。第三步不把AI当搜索引擎用。AI给出FFmpeg参数时我坚持要再查一遍官方文档或社区帖子。它会一本正经地给我推荐一个已经废弃的滤镜写法我遇到过不止一次。AI适合“把已知方案转成代码”不适合“发明一个方案”。3.4 从AI拿到完整项目的局限性有几个坑我必须提醒后来人。第一AI会“过度设计”。我让它实现一个“暂停”按钮它在大约300行代码里引入了线程池、异步任务队列、状态机最后我删掉了一大半。项目初期一定是越简单越好先把跑的通的路径打通再谈优雅。第二AI对第三方库的版本兼容性不敏感。我用的FFmpeg版本是6.x但AI有时候生成的命令参数是针对4.x的虽然大部分兼容偶尔会有细微差异。在项目开始阶段把版本信息写clear然后告诉AI“请只基于FFmpeg 6.1的文档输出”能减少很多返工。第三AI编写的UI事件绑定偶尔会与PySide6的信号机制不太匹配导致按钮点击没有任何反应。这种问题往往是“别提了代码看着没问题”的类型排查起来非常消耗时间。我的经验是拿一个最小样本让AI对比“绑定了clicked信号和没有绑定”的差异能更快定位到它写错的生命周期关联。4. 实操全过程从环境搭建到第一段录屏4.1 环境准备验证FFmpeg能不能用我的开发机是Windows 11Python 3.11虚拟环境用venv管理。装好Python后第一步是安装PySide6pip install PySide6然后下载FFmpeg。Windows的FFmpeg是一个绿色压缩包解压后把bin目录加入系统PATH。这一步很多人会栽在环境变量上——命令行里敲ffmpeg -version提示“ffmpeg不是内部或外部命令”十有八九是没加PATH或者没重新打开终端。不过我的工具里也没有完全依赖系统PATH因为即使PATH里没有ffmpeg工具也会尝试几个常见路径去定位可执行文件。这部分逻辑同样让AI写的它产出的代码遍历了当前目录/ffmpeg/bin、C:/ffmpeg/bin、以及shutil.which(ffmpeg)基本覆盖了现实情况。4.2 手工验证FFmpeg录屏命令在写Python代码之前我花了整整半天时间在命令行里反复验证不同参数的录屏效果。这一步是整个项目最有价值的时间投资。因为如果我连FFmpeg命令都跑不通后边再漂亮的界面都是空中楼阁。我建议你也照着这个顺序做一遍。先在命令行里跑一个最简单的全屏录制10秒后手动停止ffmpeg -f gdigrab -framerate 30 -i desktop -c:v libx264 -preset ultrafast -crf 28 -t 10 test.mp4如果这个能成功说明抓屏通道是通的。然后尝试录制指定区域这里我们把屏幕左上角1280x720的区域录进来ffmpeg -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 1280x720 -i desktop -c:v libx264 -preset ultrafast -crf 28 -t 10 test_region.mp4接下来试音频。在命令行里跑一个包含音频输入的录制确认系统声或麦克风能进来。这一步最容易出问题对每一次音频报错都要仔细看日志。最后我建议测试一下“中断恢复”能力。录制过程中按键盘上的qFFmpeg会正常收尾输出文件但在实际工具里用户可能是通过界面按钮触发停止逻辑的所以必须确认你打算采用的停止方式不会破坏文件。我的方案是进程通信给ffmpeg子进程的标准输入写入一个q再用communicate()等待退出。4.3 Python GUI项目结构项目取名我很随意就叫screenie。目录结构如下screenie/ ├── main.py # 入口 ├── requirements.txt ├── gui/ │ ├── __init__.py │ ├── main_window.py # 主界面 │ └── widgets.py # 自定义控件 ├── core/ │ ├── recorder.py # 引擎 │ ├── config.py # 配置 │ └── command_builder.py └── utils/ ├── devices.py # 设备探测 └── logger.py这个结构也是AI帮我设计的。我提的要求是“入口文件保持干净核心逻辑不依赖界面以后能加命令行模式”它给的这个目录划分我认可。实际开发中GUI和core的解耦确实帮了大忙后边我调试音频设备时不用开着界面反复点按钮而是能写一个测试脚本直接调用设备枚举逻辑。4.4 完整实现录制、暂停、停止、预览录制引擎的核心代码看起来不算复杂但每一行都包含了踩坑后得到的取舍。启动录制时程序检查输出目录如果文件已存在就自动追加时间戳避免覆盖用户已有文件。然后根据配置构建命令启动子进程。import queue import subprocess import threading def start(self, cfg): self.queue queue.Queue() self.proc subprocess.Popen( self.builder.build_command(cfg), stdinsubprocess.PIPE, stdoutsubprocess.PIPE, stderrsubprocess.STDOUT, textTrue, encodingutf-8, errorsreplace, creationflagssubprocess.CREATE_NO_WINDOW if os.name nt else 0, ) self._monitor_thread threading.Thread(targetself._read_output, daemonTrue) self._monitor_thread.start()CREATE_NO_WINDOW是我特意加的一个Windows标志。没有它每次录制都会闪出一个黑色控制台窗口虽然不影响功能但录屏教程类视频里出现自己工具的黑色窗口就太尴尬了。暂停功能是项目里最纠结的一个点。FFmpeg的命令行本身不支持“暂停并恢复”这个操作。一个常规思路是录制时用-f segment把视频切成小段暂停就是停止当前段恢复就是开启新段最后把段合并。我用AI辅助实现了这个方案录制命令里加上-f segment -segment_time 300每5分钟自动切成一段。点击“暂停”时给ffmpeg发送q让它结束当前录制文件。点击“继续”时用同样的参数重新启动一个新段文件。点击“停止”时把所有段文件通过concat协议合并成一个最终mp4。有一个地方需要特别注意分段录制后每个段的编码参数必须完全一致。FFmpeg的concat复用器在合并时会校验流的编码参数不一致就拒绝合并。我最初就因为一段用了-preset ultrafast另一段用了-preset veryfast合并时报了参数不一致的错误。这是AI最不容易发现的坑。暂停方案的用户体验也不完美因为暂停的瞬间前一个段文件要收尾恢复后新开一个段两个段之间有一瞬间的黑屏或时间戳跳变。但如果只是讲解视频、演示操作这点瑕疵完全可接受。“停止”操作的实现我写在了stop()方法里def stop(self): if self.proc and self.proc.poll() is None: self.proc.stdin.write(q) self.proc.stdin.flush() self.proc.wait(timeout10) self._finalize()这段代码里timeout10很关键。如果编码器正在处理一个很大的缓冲段进程可能不会在几秒内退出。给一个合理的超时时间能避免界面假死超时后再尝试强制终止并提示用户输出文件可能不完整。4.5 让AI帮忙写出的代码长什么样AI帮我写的代码风格比我手写要“更周全”。它会自己加很多try/except会写访问属性的防御逻辑可维护性其实比我预想的好。但代价是代码复用度不高——它会频繁把一模一样的配置硬编码在多个地方导致参数一改就要改好几处。有一段代码让我印象很深。我让它处理“窗口关闭时正在录制怎么办”这个逻辑它没有直接给出递归的关闭确认而是设计了一个状态机录制中关闭窗口→先停止录制→再保存当前切片→最后询问用户是否合并切片→确认后退出。这个设计确实比我的初版思路优雅。我把它留下的原因就是它解决了现实中“用户关窗口手忙脚乱”的问题。我也去掉了很多AI生成的冗长注释。AI有一个喜欢给每行加注释的习惯比如“# 设置帧率为30”的废话我不太欣赏这种风格。我觉得注释应该写“为什么这么写”而不是“这行在干什么”。最终代码我保留的注释基本都是记录重要决策原因的比如# 使用 stdin 写入 q 比 terminate() 更安全 # 前者能让 ffmpeg 优雅完成封装动作避免文件损坏。5. 踩过的坑与排查实录5.1 录出来一片黑我遇到的第一种黑屏是录制的窗口在后台被系统忽略了。gdigrab抓的是屏幕像素如果被录制窗口被最小化或者被其他窗口挡住录下来的就是当前屏幕上能看到的内容而不是那个窗口。也就是说gdigrab录制全屏时录的是“屏幕当前显示的内容”它不是窗口级捕捉。想录窗口就得保证那个窗口置顶可见或者用gdigrab指定窗口标题抓取ffmpeg -f gdigrab -framerate 30 -i title我的窗口标题 -c:v libx264 output.mp4第二种黑屏和显卡驱动有关。有些机器上如果开启硬件加速编码nvencFFmpeg会直接调用GPU编码但GDI抓屏得到的帧格式和硬件编码器之间的色彩空间转换偶尔出问题黑屏就是其中的一个表现。用-c:v libx264纯软件编码就不会遇到这个问题。作为默认方案我更信赖libx264的稳定性。第三种黑屏是录制区域超出了屏幕范围。比如在1080p的屏幕上把-offset_y设为1080再把-video_size的高度也设为1080FFmpeg不会报错录出来的就是一个全黑画面因为抓取区域超出了物理屏幕边界。这个问题的排查方法很简单录制前用代码读取当前屏幕分辨率限制录制区域的坐标范围。5.2 没有声音/只有麦克风没有系统声这个是最多人踩的坑。系统声音录不下来原因是Windows默认不允许把正在播放的声音“录回”到采集设备里。FFmpeg能拿到的“立体声混音”设备很多时候是隐藏的。解决方法分两步。第一步在Windows声音设置里打开“立体声混音”右键小喇叭打开“声音设置”选“更多声音设置”切到“录制”标签页如果看不到“立体声混音”在空白处右键勾选“显示禁用的设备”右键“立体声混音”启用它第二步在FFmpeg命令里使用这个设备。注意不同声卡的设备名不同英伟达显卡可能会显示成“NVIDIA Virtual Audio Device”USB声卡可能有自己的名字。所以工具里我做了一个下拉框调用ffmpeg -list_devices true -f dshow -i dummy枚举所有设备让用户手动选择。这么做虽然简陋一些但兼容性最好。还有一个小细节有些机器上音频设备名里包含非ASCII字符比如中文。处理这类设备名命令行编码容易出错最好先把设备名的编码统一处理成UTF-8或者干脆重命名声卡的“录制”设备为纯英文。我吃过这个亏AI也没能在根因上帮上忙最后是看了FFmpeg官方社区才定位到编码问题。5.3 文件20分钟就几个GB视频文件体积膨胀是录屏初学者最容易忽略的问题。我第一版工具没有设置crf文件大得离谱。录了一个20分钟的内部课程结果显示接近5个GB别说分享连打开都吃力。解决文件体积过大的核心是两条。第一视频编码必须是H.264不要选默认的无损编码。FFmpeg的默认编码器在不同版本里不一样有的是mpeg4压缩率差文件能大好几倍。第二要显式写-crf参数用恒定质量因子来控制体积画质平衡。办公类录制建议crf 26~30教学视频建议crf 24~26,游戏录制才需要crf 18~22。音频码率也别默认用-b:a 128k或192k就够了。很多人忽略了音频结果音频流占了很大体积。128k的AAC音频用于语音讲解完全足够。其实画面变化不剧烈的录屏CRF 28veryfast是一个特别高效的组合。我用它录过一段PPT演示20分钟的视频只有800MB左右画面几乎无损。5.4 录制中断后文件打不开我中途用任务管理器强杀过ffmpeg进程想验证一下异常退出后文件状态。结果毫无悬念mp4文件直接损坏播放器提示“无法解析”。这是因为mp4的moov元数据块默认写在文件尾部只有正常结束封装时才会写入。如果进程中途被杀播放器就找不到索引信息。两个解法。第一个是录制时用mkv格式。MKV的索引写在文件头部即使程序崩溃中断MKV大概率还能播放。我的工具中把“临时录制格式”固定为mkv录制结束后再用FFmpeg转封装成mp4。这样多了一道转封装步骤但换取的是录制中断后的容错率代价很小。第二个是在启动FFmpeg时加一个提示参数ffmpeg -f gdigrab ... -f mpegts - | ffmpeg -f mpegts -i - -c copy output.mp4这是用管道方式先输出TS流再转封装。TS流是流式格式天然抗中断边录边写中断了也能修复。这个方案更复杂我作为备选方案记在文档里日常使用MKV方案已经足够。5.5 暂停功能的设计与最终方案我前面提到了暂停功能的最终方案是分段录制合并。这里多讲一点我的思考过程。我最早尝试的方案是让AI写一个基于SIGSTOP/SIGCONT的暂停。它写的代码是用signal库向进程发送SIGSTOP把ffmpeg进程挂起恢复时再发SIGCONT。这个方案在Linux下确实能“暂停”进程但在Windows上signal库对SIGSTOP的支持有限至少在我测试的Windows 11上没生效。而且即便进程被挂起编码器内部的时间戳时钟也在跳变恢复后画面和声音会明显错位。后来我也尝试了-vf selectnot(between(t,start_time,end_time))这种方式在录制时就排除掉某些时间段的画面。这个做法不适用于实时录制因为select滤镜基于时间戳过滤用于回放或后期处理可行实时采集场景里工作量巨大且不可控。最终的分片方案我前面已经展开过。它的代码集成成本不高也完全可控。核心思路就是“暂停结束当前片记住位置继续开新片”。如果以后想彻底消除暂停瞬间的视觉跳变可以考虑改用ffmpeg的-f segment配合-reset_timestamps 1让每个分片都从0开始时间戳合并时再用concat demuxer做时间戳重排。这个方案目前在我的拓展清单里暂未实现。5.6 AI给错参数怎么办AI给错参数这件事几乎每个深度用过的人都会遇到至少一次。我遇到过AI推荐我用-vcodec libx264rgb来录制屏幕说能保留原始色彩。这个参数确实存在但它产生的视频不是标准的YUV420格式很多播放器颜色会完全反色或偏色兼容性很差。AI是根据“rgb能记录更多颜色信息”这个理论推出来的方案可实际发布场景里兼容性才优先。还有一个经典案例AI让我用-pix_fmt yuv420p解决兼容性问题这确实是标准做法但它没告诉我这个参数必须放在编码器参数之前还是之后。放错了位置FFmpeg可能直接报错或者在特定版本里被忽略。我的处理方式是建立一个“信任但验证”的机制AI给的每一个新参数我要求它附带FFmpeg官方文档的链接或至少说明参数适用的版本范围。如果它给不出来我就默认不采用而是自己去查。这一条原则在后续开发里为我挡住了很多潜在问题。6. 实测对比自研工具 vs 付费软件6.1 功能对照表工具做完以后我把它和之前用过的几款主流付费录屏软件拉出来做了一次直观对比。下面的表格是我的真实使用感受可能存在主观因素但能说明方向上的差异。功能项自研工具付费录屏软件A付费录屏软件B完整桌面录制支持支持支持选区录制支持支持支持系统声音录制依赖声卡支持支持得更好支持得更好麦克风混音支持支持支持暂停/恢复分片合并方案原生支持原生支持画质参数调节完全自由预设档预设档GPU硬件编码手动加参数支持一键开启一键开启字幕/水印/剪辑不支持支持支持云分享不支持支持支持账号绑定不需要必须登录必须登录额外花费0年费数百年费数百从功能丰富度上看付费软件在“一站式体验”上确实赢了。它们把水印、剪辑、云分享、字幕全打包进一个应用里。但从核心的“录一段高质量视频”这个需求出发,我的工具已经覆盖了大多数场景而且没有强制登录、没有广告弹窗、没有资源占用焦虑。6.2 实测数据录制一分钟短视频对比我录了一段大约1分钟的系统操作演示内容包括切换窗口、滚动网页、打开菜单。分别在相同网络环境和同一台机器上用自研工具和付费软件各录一次。对比结果如下项目自研工具付费软件A输出格式MP4 (H.264)MP4 (H.264)视频码率约800kbps~1.2Mbps通常4Mbps以上一分钟文件大小约9MB约32MB画面清晰度文字边缘清晰文字边缘清晰略锐化编码耗时约30秒约15秒CPU占用录制时平均8%~15%12%~20%这里要说明一下付费软件的文件大是因为它默认目标码率更高画面更清晰。但录屏应用场景里办公演示这种画面变化小的内容低码率的H.264都能提供足够清晰的画质。对于大文件反而是负担。自研工具能拿到更小的文件体积是因为我用了CRF质量控制让编码器只在画面变化时分配高码率。6.3 你会失去什么、你会得到什么自研工具确实不是银弹我必须诚实说它的代价。首先是时间成本。你可能需要投入一个周末或者几个晚上来开发和调试。即便有AI辅助前期的命令验证、设备调试、兼容性测试都免不了。如果对命令行和编程完全没有概念学习曲线会更陡。其次是维护成本。工具一旦出现问题没有人给你写工单、打客服一切都得自己解决。FFmpeg每次升级旧命令可能会失效程序也要跟着测试。对纯粹“想录个视频”的用户来说这个维护成本完全没有必要。但你获得的东西也非常具体一是需求完全掌控。我不需要的功能一个都不用装我需要的功能也许付费软件反而不提供。比如指定“只记录鼠标点击区域并附上放大效果”这个需求在付费软件里得折腾滤镜和插件我在自己工具里加一个缩放滤镜就行。二是数据隐私。所有录制文件都保存在本地没有任何一个环节需要上传到云端。敏感的内网演示、客户的私有数据录制时完全不接触第三方服务器这让人安心得多。三是成本和技能积累。工具帮我把每年几百块的订阅费省下来了更重要的是我对FFmpeg、音视频处理、进程管理这些技术都有了更深入的理解。这个积累会体现在后续的每一个视频处理任务上。7. 经验与教训可以直接抄作业的部分7.1 给想上车的朋友的技术建议如果这篇文章勾起了你“也想做一个录屏工具”的念头我的建议非常明确先把FFmpeg命令跑通再写代码先做成命令行工具再做图形界面先满足一个核心场景再扩展边缘需求。具体落地步骤是第一步下载FFmpeg在终端里用官方文档和自己电脑的设备实际情况拼凑出一条能用的录屏命令。这一步不要编程就在终端测试。第二步把这条命令写进一个bash或bat脚本。脚本里支持传入输出文件名和录制时长。第三步用你最熟悉的语言把这堆命令封装成一个简单的CLI工具。配合subprocess、process通信、日志输出先体验一下管理外部进程的感觉。第四步再上GUI。如果你也选PythonPySide6我的建议是先让AI生成一个最小可运行的界面骨架再逐步往里加元素。每加一个功能都跑一遍别一口气写完一大堆再调试那样问题定位会非常痛苦。7.2 我给AI当“项目经理”的几条心得这次项目让我对AI辅助开发有了更实际的认识不是玄学几条心得供参考。第一需求描述越具体AI产出越可用。我的提示词通常包含“环境是Windows 11 FFmpeg 6.1 Python 3.11”“使用PySide6”“请只输出标准库和PySide6依赖”“不要使用需要额外安装的系统库”。我给得越细后面返工越少。第二让AI自己“先计划再执行”。每次给它一个稍大的需求我都不直接要完整代码而是先让它列步骤方案。比如“如果要实现暂停录音请给我3个可行方案并说明优缺点然后我们讨论后再输出代码”。这一招提高了不少方案质量也避免了我反复改代码。第三验证AI代码质量的一个诀窍是让它写测试。我让AI给command builder写了几个单元测试覆盖“不同区域配置”“音频设备变化”“输出路径含空格”等场景。这些测试反过来帮AI发现自己代码里的参数拼接漏洞这比人工逐行review效率高多了。7.3 这项目还能往哪扩展工具的基本功能稳定以后我还有一串想法排在待办清单上。第一个方向是增加硬件编码支持。录一些高帧率游戏画面时libx264的CPU占用会比较高。FFmpeg在Windows上可以通过-c:v h264_nvenc调用NVIDIA显卡的硬件编码器在Linux上可以通过h264_vaapi调用Intel或AMD显卡。把这个做成下拉选项就能兼顾性能和画质。第二个方向是自动上传或归档。录完的视频自动移动到指定目录并按今天的日期或项目名命名。这个逻辑用Python写非常简单但能极大提升日常使用的效率。第三个方向是增加“鼠标事件可视化”。录教学视频时给鼠标点击位置画一个显眼的圆圈高亮显示点击动作。FFmpeg的drawbox滤镜和鼠标事件捕捉脚本可以组合实现是个有趣的增强功能。第四个方向是音量调节。现在的工具只能统一混音不能分开调系统音量和麦克风音量。以后可以在GUI里加两个滑块通过调整volume滤镜参数实时控制两路音量大小。Audio mixing技术里这是很容易做的对教学视频特别有意义。结尾一点真心话很多人在网上问“有了AI编程我是不是不需要学编程了”。这次做一个录屏工具给我的体会是AI能替你把想法变成代码但它没法替你对软件效果负责、没法替你在设备兼容性上踩坑更没法替你想清楚“到底什么功能才是该做的”。这些判断力仍然需要建立在实打实的动手实践上。对我来说AI最好的使用方式不是当“自动生成器”而是当“高级搜索引擎结对编程队友”我来定问题和标准它来提速和补全场景最终我们把一个能用的、顺手的东西交出来。从这个卖几百块的付费软件开始到最后只用了几条FFmpeg命令和几百行Python代码我得到的不仅仅是一个省钱的录屏工具更是一份对常用软件背后原理的掌握。以后再遇到类似的日常痛点我不再会下意识去搜“XXX软件哪个好用”而是会先想这事自己能不能用代码解决这个思维转变才是这次实践里最有价值的部分。