WebSocket+FFmpeg录屏视频提前结束问题(EC2部署后)
录屏应用部署EC2后视频保存时长不稳定问题
我开发了一款录屏应用:前端用MediaRecorder生成video/webm;codecs=H264格式的流,通过WebSocket每2秒把字节数据发送到FastAPI后端;后端调用FFmpeg把接收的字节写入MP4文件。本地运行完全正常,但部署到us-east-1区域的EC2实例后,录制30秒的视频只能保存3秒左右,有时能保存90%,时长极不稳定。调试多日没解决,相关代码及FFmpeg日志如下:
前端代码
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=H264', videoBitsPerSecond: 8000000 }); recorder.ondataavailable = (e: BlobEvent) => { socketRef.socket.send(e.data) }
后端代码
@router.websocket("/stream") async def websocket_endpoint(websocket: WebSocket, token: str = Query(...), videoId: str = Query(...), authorize: AuthJWT = Depends()): await manager.connect(websocket) dataNumber = 1 recordingFile = os.path.join(temp_dir, f"recording_{videoId}.mp4") command = [ 'ffmpeg', '-y', '-i', '-', '-codec:v', 'copy', '-f', 'mp4', recordingFile, ] process = subprocess.Popen(command, stdin=subprocess.PIPE) try: while True: try: data = await websocket.receive_bytes() if not data: break process.stdin.write(data) await websocket.send_json({"chunkNumber": dataNumber, "status": 200}) dataNumber = dataNumber + 1 except RuntimeError: break except WebSocketDisconnect: print(f"Client disconnected: {websocket.client.host}") finally: manager.disconnect(websocket) process.stdin.close() process.wait() process.terminate()
FFmpeg日志
libpostproc 57. 3.100/57. 3.100 Input #6, matroska, webm, from 'fd:': Metadata: encoder: Chrome Duration: N/A, start: 0.000000, bitrate: N/A Stream #0:0(eng): Video: h264 (Constrained Baseline), yuv420p(tv, bt789, progressive), 1920x1080, SAR 1:1 DAR 16:9, 30.30 fps, 56 tbr, 1k tbn (default) Output #8, mp4, to /tmp/recording_d367d8d3-60de-483e-bf29-1849841b82f3.mp4': Metadata: encoder: Lavf60.16.100 Stream #0:0(eng): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 38.30 fps, 56 tbr, 16k tbn (default) Stream mapping: Stream #0:0> #0:6 (copy) Client disconnected: 127.0.0.189 bitrate=3374.0kbits/s speed=0.999x [matroska, webm @ 8x61e88988f3c0] 9493864 (0x98dd68) [out#0/mp4 @ 0x61e8898cc488] video:9263kB audio:0kB subtitle:0kB other streams: 9kB global headers: 8kB muxing overhead: 0.143342% size= 9276kB time=00:00:21.85 bitrate=3476.8kbits/s speed=1.08x INFO: connection closed INFO: 127.0.0.1:52546 "POST /api/process HTTP/1.1" 200 ок
问题分析与解决方案
核心问题点
- WebSocket数据传输与FFmpeg写入异步不匹配:后端同步写入
process.stdin.write(data)在EC2网络环境下,可能因为缓冲区未及时刷新导致数据滞留丢失;同时FastAPI异步WebSocket接收逻辑与同步subprocess写入存在线程安全隐患。 - MP4容器特性限制:MP4依赖全局索引(moov原子),直接流拷贝
-codec:v copy时,若WebM流不完整或FFmpeg未正确收尾,会导致MP4文件无法完整解析时长。 - EC2网络与进程收尾逻辑缺陷:网络带宽波动可能导致WebSocket数据接收不完整,且客户端断开时FFmpeg未收到EOF信号,无法正确完成文件写入。
具体修复步骤
1. 修复后端写入逻辑,强制刷新缓冲区
每次写入数据后强制刷新FFmpeg输入缓冲区,避免数据滞留在内存:
# 替换原写入代码 process.stdin.write(data) process.stdin.flush() # 新增:强制刷新缓冲区
2. 调整FFmpeg命令,适配流式MP4生成
添加-movflags frag_keyframe+empty_moov+default_base_moof参数,让FFmpeg生成支持流式处理的MP4片段,无需等待完整moov原子:
command = [ 'ffmpeg', '-y', '-i', '-', '-codec:v', 'copy', '-movflags', 'frag_keyframe+empty_moov+default_base_moof', # 新增流式MP4参数 '-f', 'mp4', recordingFile, ]
3. 优化WebSocket接收与进程收尾逻辑
- 添加接收超时处理,避免无限等待;
- 客户端断开时确保FFmpeg收到EOF信号,完成文件写入:
try: while True: try: # 新增:30秒超时,防止进程卡住 data = await asyncio.wait_for(websocket.receive_bytes(), timeout=30) if not data: break process.stdin.write(data) process.stdin.flush() await websocket.send_json({"chunkNumber": dataNumber, "status": 200}) dataNumber += 1 except asyncio.TimeoutError: print("WebSocket接收超时,关闭连接...") break except WebSocketDisconnect: print(f"客户端断开连接: {websocket.client.host}") finally: manager.disconnect(websocket) # 确保FFmpeg收到EOF并完成写入 process.stdin.close() process.wait(timeout=10) process.terminate()
4. 前端优化MediaRecorder分片策略
明确设置timeslice参数,确保分片间隔稳定,且只发送非空数据:
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=H264', videoBitsPerSecond: 8000000, timeslice: 2000 // 明确设置2秒分片间隔 }); recorder.ondataavailable = (e: BlobEvent) => { if (e.data.size > 0) { // 只发送非空数据块 socketRef.socket.send(e.data) } }
验证方法
部署修复后的代码到EC2,多次录制30秒视频,检查MP4文件时长是否稳定;查看FFmpeg日志,确认无truncated或invalid frame等错误信息。
内容的提问来源于stack exchange,提问作者Zaid
相关产品推荐
相关产品推荐

