限时福利领取


背景与痛点

最近在做一个视频监控项目时,遇到了一个经典问题:摄像头输出的RTSP流无法直接在浏览器中播放。这是因为现代浏览器基本不再支持RTSP/RTMP协议,而更倾向于使用HTTP-FLV、HLS等基于HTTP的流媒体协议。

流媒体协议对比

FLV格式有几个显著优势:

  • 兼容性:所有现代浏览器都支持通过flv.js等库播放FLV流
  • 低延迟:相比HLS通常有2-3秒的延迟,FLV可以做到1秒以内
  • 实现简单:不需要切片文件,适合实时监控场景

技术方案选型

经过调研,主要有三种实现方案:

  1. FFmpeg转码+WebSocket
  2. 优点:延迟最低,实现灵活
  3. 缺点:需要维护WebSocket连接

  4. FFmpeg转码+HTTP-FLV

  5. 优点:兼容性好
  6. 缺点:需要HTTP服务器支持

  7. 商业转码服务

  8. 优点:开箱即用
  9. 缺点:成本高,可控性差

综合考虑延迟和实现复杂度,我们选择了第一种方案。

核心实现

1. FFmpeg转码

首先需要在服务器安装FFmpeg,然后通过Java调用:

ProcessBuilder pb = new ProcessBuilder(
    "ffmpeg",
    "-i", rtspUrl,          // 输入流地址
    "-c:v", "libx264",      // 视频编码
    "-preset", "ultrafast", // 速度优先
    "-tune", "zerolatency", // 零延迟
    "-f", "flv",           // 输出格式
    "pipe:1"               // 输出到标准输出
);
Process process = pb.start();

2. WebSocket传输

使用Java的WebSocket API建立连接:

@ServerEndpoint("/live/{streamId}")
public class VideoSocket {
    @OnOpen
    public void onOpen(Session session) {
        // 新连接建立时,创建转码进程
        FFmpegProcess process = new FFmpegProcess(rtspUrl);
        process.addOutputConsumer(data -> {
            session.getBasicRemote().sendBinary(data);
        });
    }
}

3. 前端播放

使用flv.js库播放WebSocket流:

const player = flvjs.createPlayer({
    type: 'flv',
    url: 'ws://your-server/live/stream1',
    isLive: true
});
player.attachMediaElement(videoElement);
player.load();
player.play();

性能优化

  1. FFmpeg参数调优
  2. 使用-threads 2限制CPU占用
  3. 设置-bufsize 1000k避免缓冲延迟

  4. 内存管理

  5. 使用环形缓冲区防止内存暴涨
  6. 及时关闭空闲连接释放资源

  7. 并发处理

  8. 每个流单独进程隔离
  9. 使用连接池管理WebSocket会话

常见问题

Q: 延迟越来越高怎么办? A: 检查FFmpeg的-preset-tune参数,确保使用最低延迟配置。

Q: 内存不断增长? A: 可能是WebSocket消息积压,需要实现背压控制。

Q: 连接频繁断开? A: 增加心跳机制保持连接活跃。

安全建议

  1. 对输入流URL进行严格校验
  2. 使用wss协议加密传输
  3. 限制单个IP的连接数
  4. 实现鉴权机制

系统架构图

总结

这套方案在实际项目中运行稳定,1080p流平均延迟在800ms左右,CPU占用率约15%。关键点在于FFmpeg参数调优和WebSocket的合理管理。完整示例代码已放在GitHub上,欢迎交流讨论。

对于更高并发的场景,可以考虑引入Kafka等消息队列做流量削峰,这也是我们下一步的优化方向。

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐