本地屏幕录制与操作行为记录系统:从FFmpeg到事件日志的工程实践

发布时间:2026/8/30 12:47:52
本地屏幕录制与操作行为记录系统:从FFmpeg到事件日志的工程实践 先给结论每一个按键、每一次窗口切换、每一段屏幕画面在“Everything You Do Is Being Recorded”这类项目里都会被完整保留。它的核心思路很简单——在本地把用户操作过程记录成一条可回放的行为时间线屏幕帧、活跃窗口标题、事件发生时间、操作顺序全部落盘。这类能力在录屏教程、Bug 复现、自动化测试验证、自有产品行为分析里非常实用也是很多 RPA 和测试框架的底层基础。这类项目通常不是一个单独的大仓库而是“录制内核 事件监听 存储回放”的组合实现。门槛比大部分人想象的低不需要独立显卡CPU 编码就能跑磁盘占用取决于分辨率、帧率和压缩参数启动方式以命令行为主也可以包一层 Web 服务提供 API。本文会从环境准备、部署启动、功能验证、接口封装、批量任务、性能观察和排错几个方向把一套可落地的本地活动记录系统完整讲清楚。先说一个务实的建议第一次验证先跑通屏幕录制再加事件日志最后再考虑 API 化和批量导出。不要一上来就把全部功能堆在一起否则出了问题很难定位是录制模块、事件模块还是接口模块的锅。1. 核心能力速览由于标题指向的是一个技术方向而不是某个固定仓库下面按这类项目的常见实现形态来梳理能力。能力项说明项目类型本地计算机活动记录 / 屏幕录制 事件追踪工具主要功能屏幕画面录制、活跃窗口追踪、事件时间线记录、回放与导出硬件要求CPU 编码即可不需要独立显卡内存建议 8GB 以上显存占用无 GPU 推理需求显存占用可以视为 0支持平台Windows / Linux / macOS取决于录制后端启动方式命令行启动可封装为 Web 服务是否支持 API可通过 FastAPI / Flask 自行封装是否支持批量任务支持适合批量回放、批量压缩导出存储格式视频MP4/WebM 事件日志JSONL适合场景教程录制、Bug 复现、测试验证、行为分析、数字证据留存一个常见的误解是记录一切 无脑截屏。实际工程实现里通常要把“画面录制”和“事件记录”分开处理。画面录制解决“看到了什么”事件记录解决“用户当时在做什么”两者通过时间戳对齐才能支撑后面的时间轴回放。2. 适用场景与使用边界先讲清楚适合谁用。这类工具最适合的人群是软件测试工程师、自动化脚本开发者、技术写作者和产品经理。测试工程师可以用它复现偶发 Bug把失败路径录下来交给开发技术写作者可以用它录制操作演示省去临时架摄像头的麻烦产品经理可以在自己参与设计的测试环境里观察用户操作路径优化交互流程。不适合什么场景未经授权的监控、账号密码记录、敏感聊天内容采集、以及任何针对他人设备的隐蔽记录。这些场景不只是道德问题在绝大多数国家和地区都涉及违法违规这里不做任何操作层面的建议。使用边界必须提前划好特别是当项目涉及人脸、声音、键盘输入记录时设备边界只录制自己拥有或已获得明确授权的设备。数据边界采集范围最小化密码输入框、支付页面、聊天窗口最好直接排除。时间边界设定自动清理周期默认不长期保存。告知边界如果录制内容会涉及他人必须提前获得知情同意。从工程角度看最稳妥的设计不是“先录下来再说”而是“录制前就把敏感区域和敏感应用过滤掉”。比如在录屏时只截取指定窗口或裁剪掉输入法区域事件记录里过滤掉已知的密码输入窗口标题。这样即使文件泄露风险也可控。3. 环境准备与前置条件以一套通用的本地活动记录系统为例推荐环境如下3.1 操作系统与运行环境Windows 10/11或者 Ubuntu 20.04 以上的 Linux 发行版。Python 3.9 以上用于运行事件监听和 Web API 服务。FFmpeg 4.x 以上用于屏幕录制和视频转码。无头服务器需要额外准备虚拟显示方案比如 Xvfb。3.2 磁盘空间评估磁盘占用是最容易被低估的变量。按经验估算1080p、30fps、H.264 中等码率每小时约 1-2GB。同样的分辨率如果使用无损或高码率设置每小时可能到 5GB 以上。事件日志 JSONL 文件很小每小时通常只有几 MB 到几十 MB取决于事件密度。所以存储规划不要太乐观。建议录制输出目录和数据目录分开方便做容量配额和自动清理。3.3 显卡与显存这类项目不需要 GPU 推理。屏幕录制走的是 FFmpeg 的 CPU 编码或硬件编码事件监听走的是系统 API显存占用可以视为 0。如果你的机器有 NVIDIA 显卡可以按需使用 NVENC 硬件编码降低 CPU 占用但没有也不影响基础功能。5. 安装部署与启动方式下面给出一套可复用的参考实现包含 Python 虚拟环境、FFmpeg 录制、事件监听脚本和 Web API 服务。实际操作时请把命令里的路径、分辨率和窗口标题替换成你自己的值。4.1 创建 Python 环境并安装依赖# 创建虚拟环境按实际项目目录调整路径 python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate # 安装事件监听和图像处理依赖 pip install pynput pillow opencv-python fastapi uvicorn requests4.2 检查 FFmpegffmpeg -version如果系统没有安装 FFmpegLinux 可以用 apt 安装sudo apt update sudo apt install ffmpegWindows 用户建议直接下载官方 release 包把 bin 目录加入系统 PATH。4.3 启动屏幕录制Linux 下使用 x11grab 录制整个桌面# 录制 1920x108030 帧声音使用 PulseAudio 默认输入源 # 如果不需要声音去掉 -f pulse 部分 ffmpeg -f x11grab -framerate 30 -video_size 1920x1080 -i :0.0 \ -f pulse -i default \ -c:v libx264 -preset ultrafast -crf 28 \ -c:a aac -b:a 128k \ output.mp4Windows 下使用 gdigrab 录制桌面ffmpeg -f gdigrab -framerate 30 -video_size 1920x1080 -i desktop \ -c:v libx264 -preset ultrafast -crf 28 \ output.mp4参数解释-preset ultrafast牺牲一点压缩率换取更低的 CPU 占用。-crf 28画质折中参数数值越大文件越小、画质越低。-framerate 30录屏时建议不低于 15否则回放会明显掉帧。录制过程中FFmpeg 会持续输出帧统计信息。按q键可以正常结束录制避免生成损坏的 MP4 文件。4.4 启动事件监听脚本屏幕画面只能证明“屏幕上有内容”配合事件记录才能知道用户当时在操作什么。下面是一个最小参考实现重点记录窗口切换和鼠标点击事件。# event_logger.py # 参考实现按目标平台调整窗口标题读取方式 import json import time from pynput import mouse, keyboard from datetime import datetime LOG_FILE events.jsonl def write_event(event_type, detail): with open(LOG_FILE, a, encodingutf-8) as f: f.write(json.dumps({ event: event_type, detail: detail, ts: time.time(), time: datetime.now().isoformat() }) \n) def on_click(x, y, button, pressed): if pressed: write_event(mouse_click, {x: x, y: y, button: str(button)}) def on_press(key): # 避免记录密码等敏感输入这里只记录按键名称不记录组合内容 if key keyboard.Key.esc: write_event(keyboard_esc, {}) return False # 启动监听 with mouse.Listener(on_clickon_click) as ml: with keyboard.Listener(on_presson_press) as kl: ml.join() kl.join()这个脚本故意做了两件事来规避风险一是只记录鼠标点击坐标不记录按键文本二是收到 Esc 键就结束监听方便紧急停止。实际项目中如果确实需要记录键盘输入务必在采集层过滤掉密码框和敏感输入法区域。运行方式python event_logger.py4.5 整合为带 Web 服务的完整启动事件监听和 FFmpeg 是两条独立的进程如果希望用 API 控制录制启动和停止可以用一个 FastAPI 服务统一管理。# app.py # 参考实现需要根据实际项目改造 import subprocess import json import time from pathlib import Path from fastapi import FastAPI app FastAPI() OUTPUT_DIR Path(./sessions) OUTPUT_DIR.mkdir(exist_okTrue) ffmpeg_proc None app.get(/health) def health(): return {status: ok, time: time.time()} app.post(/api/record/start) def start_record(rate: int 30, size: str 1920x1080): global ffmpeg_proc if ffmpeg_proc is not None: return {error: recording already running} out_file OUTPUT_DIR / fsession_{int(time.time())}.mp4 cmd [ ffmpeg, -y, -f, x11grab, -framerate, str(rate), -video_size, size, -i, :0.0, -c:v, libx264, -preset, ultrafast, -crf, 28, str(out_file) ] ffmpeg_proc subprocess.Popen(cmd) return {status: started, file: str(out_file)} app.post(/api/record/stop) def stop_record(): global ffmpeg_proc if ffmpeg_proc is None: return {error: no recording running} ffmpeg_proc.stdin.close() ffmpeg_proc.terminate() ffmpeg_proc None return {status: stopped}启动服务uvicorn app:app --host 127.0.0.1 --port 80805. 功能测试与效果验证部署完之后按下面的顺序做功能验证确保每个环节都能独立判断成败。5.1 屏幕录制测试测试目的确认 FFmpeg 能正常录制、正常收尾、输出文件可播放。操作步骤在终端启动 FFmpeg 录制命令。打开浏览器切换几个页面滚动几次。按q结束录制。用播放器打开输出的 MP4。预期结果视频长度接近实际录制时长画面没有大面积花屏切换窗口的过程是连续的。判断标准视频能正常拖动进度条最后 3 秒内容完整文件没有损坏。常见失败原因Linux 下DISPLAY环境变量不对导致黑屏Windows 下 gdigrab 对高 DPI 屏适配不佳画面可能被裁剪。5.2 事件日志测试测试目的确认鼠标点击和窗口切换事件能被记录且时间戳和视频时间轴能对得上。操作步骤启动 event_logger.py。做三次固定的鼠标点击操作例如点击浏览器地址栏。停止脚本查看 events.jsonl。预期结果events.jsonl 里出现 6 条记录按下和抬起各算一次每次点击位置和屏幕录制中的实际位置一致。判断标准事件时间戳与视频时间轴差值在 1 秒以内说明对齐可用。5.3 接口服务测试测试目的确认 Web API 能控制录制的启停。# 检查服务状态 curl http://127.0.0.1:8080/health # 启动录制 curl -X POST http://127.0.0.1:8080/api/record/start?rate30size1920x1080 # 停止录制 curl -X POST http://127.0.0.1:8080/api/record/stop预期结果三个请求都能返回 JSONsessions 目录下生成新的 MP4 文件。判断标准停止请求返回后目标 MP4 文件大小不再变化播放正常。6. 接口 API 与批量任务API 化的价值在于把“录制”从人工操作变成可编程的任务。有了/api/record/start和/api/record/stop你就能在自己的脚本里按需录制。6.1 Python 调用录制接口import requests import time base_url http://127.0.0.1:8080 # 启动录制 resp requests.post( f{base_url}/api/record/start, params{rate: 30, size: 1920x1080} ) print(resp.json()) # 模拟录制 10 秒 time.sleep(10) # 停止录制 resp requests.post(f{base_url}/api/record/stop) print(resp.json())启动后这个脚本可以集成到自动化测试的用例里遇到断言失败时自动录制前后 30 秒帮助定位问题。6.2 批量压缩导出录制时间长了磁盘上会积累大量原始视频。批量转码是这类项目最常用的批量任务。# batch_compress.py # 将 sessions 目录下的所有 MP4 转为低码率 H.264 文件并归档 import subprocess from pathlib import Path input_dir Path(./sessions) output_dir Path(./archive) output_dir.mkdir(exist_okTrue) for video in input_dir.glob(*.mp4): out_file output_dir / f{video.stem}_compressed.mp4 cmd [ ffmpeg, -y, -i, str(video), -c:v, libx264, -preset, medium, -crf, 32, -an, str(out_file) ] result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode 0: print(f[OK] {video.name} - {out_file.name}) else: print(f[FAIL] {video.name}: {result.stderr[-200:]})批量任务建议遵循三个原则每次处理都要记录日志便于定位哪条任务挂了。任务失败不要直接中断整个队列收集错误后统一重试。输出目录和输入目录严格分离避免覆盖原始文件。7. 资源占用与性能观察这类项目的资源占用主要集中在三个地方FFmpeg 编码进程、事件监听进程和磁盘写入。7.1 如何观察 CPU 与内存占用Linux 下直接用htop或top找到 FFmpeg 进程和 python 进程top -b -n 1 | grep -E ffmpeg|python|PIDWindows 下打开任务管理器按 CPU 排序即可。如果 FFmpeg 进程 CPU 占用长期高于 80%说明编码参数需要调低比如把-preset ultrafast改成ultrafast配合-crf 30或者降低录制的分辨率。7.2 显存占用观察这类项目没有 GPU 推理需求。如果使用 NVENC 硬件编码可以用nvidia-smi观察 GPU 编码器占用但显存占用基本为 0。这一点和跑大模型完全不同对只有集显或老显卡的机器非常友好。7.3 影响性能的关键变量分辨率从 4K 降到 1080pCPU 占用通常能下降一半以上。帧率30fps 降到 15fps文件体积接近减半对操作类教程影响不大。录制区域只录单个窗口或裁剪掉固定区域比全屏录制省很多资源。音频不需要声音时关掉音频能明显降低编码压力。7.4 降低磁盘占用的手段# 手动清理超过 7 天的录制文件 find ./sessions -name *.mp4 -mtime 7 -delete也可以让 FFmpeg 按固定时长分段录制方便后续自动清理和检索ffmpeg -f x11grab -framerate 30 -video_size 1920x1080 -i :0.0 \ -c:v libx264 -preset ultrafast -crf 28 \ -f segment -segment_time 300 -reset_timestamps 1 \ session_%04d.mp4每 5 分钟生成一个文件单个文件损坏不会影响整个录制。8. 常见问题与排查方法问题现象可能原因排查方式解决方案录制后视频是黑屏DISPLAY 环境变量错误或无头环境执行echo $DISPLAYLinux 下设置export DISPLAY:0无头服务器用 XvfbMP4 文件无法播放未正常结束录制编码头缺失查看 FFmpeg 日志是否有中断下次用q正常退出给停止接口加终止信号处理CPU 占用过高编码参数太激进用 top 观察 FFmpeg 进程调低分辨率、降低帧率、改用 NVENC事件日志为空事件监听脚本未启动或权限不足检查 python 进程是否存在以当前桌面用户运行脚本不要用 sudo 启动接口启动失败端口被占用netstat -tlnp或lsof -i:8080更换端口uvicorn app:app --port 8081磁盘快速写满码率和 CRF 设置太高du -sh ./sessions查看目录大小使用分段录制并配置清理策略事件时间戳和视频对不上两个进程启动时间不同步对比日志首条时间戳启动录制后先写一条同步事件再开始操作高 DPI 屏幕画面被裁剪gdigrab 对缩放适配不佳检查录出的分辨率与桌面实际分辨率改用 Windows Graphics Capture 或调整 DPI 缩放9. 最佳实践与使用建议第一先小参数测试再上生产。第一次录制用 1280x720、15fps、10 秒确认整个链路能跑通再逐步提高分辨率。不要一上来就录 4K 一小时否则即使功能正常后续排查问题也会很痛苦。第二目录结构要清晰。建议把原始视频、事件日志、回放归档三个目录分开project/ ├── sessions/ # 原始录制文件 ├── events/ # JSONL 事件日志 └── archive/ # 压缩后归档第三事件日志用 JSONL 而不是单独的 JSON 文件。JSONL 是追加写入进程崩溃最多丢最后一条不会把整个文件写坏后续也方便用jq或 Python 流式处理。第四接口服务一定要限制访问范围。如果只是本机使用监听地址写127.0.0.1不要写0.0.0.0。如果确实需要远程访问前面加一层带认证的反向代理。第五涉及人脸、声音、键盘输入记录时必须确认授权范围。建议在采集层做敏感信息过滤密码框不记录、支付页面不录制、聊天内容不落入日志。这是技术问题也是合规红线。对录制的内容设定保留周期测试用途的数据用完后及时删除。第六批量任务必须加日志和失败重试。批量转码、批量导出看起来简单数据量一上来就会出现各种单点失败。每处理一个文件打一条日志失败文件单独放一个列表处理完统一查看。10. 总结与下一步“Everything You Do Is Being Recorded”这类项目最值得尝试的地方不是“记录一切”这个概念本身而是它把画面、事件、时间戳、接口和批量任务串成了一条完整的数据链路。你先验证屏幕录制能不能稳定出片再确认事件日志能不能准确落盘然后把录制启停封装成 API最后接批量压缩和清理策略。这条链路跑通你就拥有了一套可以复用在自己自动化测试和教程制作里的基础能力。最容易踩的坑有两个一是磁盘规划不够录了一小时把系统盘写满二是事件记录和视频时间轴对不齐导致回放时定位不到操作点。这两个问题在前期设计阶段就要解决不要等数据量上来再改。后续可以扩展的方向不少给录制帧加 OCR 提取屏幕文字实现基于内容的检索把事件日志接到自己的后端做操作路径分析或者用自动化剪辑规则把录制的空闲时间段自动裁剪掉。这篇文章提到的方案适合先跑起来再根据业务需要逐步完善。建议收藏备用下次需要做本地行为记录时直接按这个流程操作。