醋醋百科网

Good Luck To You!

30 分钟搞定 SpringBoot 视频推拉流!实战避坑指南

30 分钟搞定 SpringBoot 视频推拉流!实战避坑指南

在音视频开发领域,SpringBoot 凭借其快速开发特性,成为很多开发者实现视频推拉流功能的首选框架。但实际开发中,从环境搭建到流处理优化,处处都可能遇到 “坑”。本文将从实战角度出发,带大家一步步搭建 SpringBoot 视频推拉流系统,解决常见问题,让你快速上手音视频开发。

一、先搞懂:视频推拉流核心概念

在动手开发前,必须先理清几个关键概念,避免后续开发 “一头雾水”。视频推拉流简单来说,就是 “推流端” 将视频数据传输到 “流媒体服务器”,“拉流端” 从服务器获取视频数据并播放的过程。其中,流媒体服务器是核心枢纽,负责接收、转码、分发视频流;常用的协议有 RTMP、HLS、RTSP,不同协议适用场景不同 ——RTMP 延迟低(1-3 秒),适合直播互动;HLS 基于 HTTP,兼容性强(支持浏览器、手机),但延迟较高(10-30 秒);RTSP 多用于安防监控设备。

而 SpringBoot 在这套体系中,主要负责 “胶水工作”:整合流媒体服务器、处理业务逻辑(如用户认证、流权限控制)、提供 API 接口供前端调用。比如,我们可以用 SpringBoot 开发一个 “直播房间管理” 功能,用户创建房间后,系统自动分配推流地址,观众进入房间时自动获取拉流地址,整个过程通过 SpringBoot 的接口完成交互。

二、实战第一步:环境搭建与依赖配置

1. 选择合适的流媒体服务器

实战中,不建议重复造轮子开发流媒体服务器,推荐使用成熟的开源方案。这里我们选SRS(Simple RTMP Server) ,它轻量、高性能,支持 RTMP、HLS、HTTP-FLV 等协议,且有完善的中文文档,对国内开发者友好。

SRS 的安装很简单(以 Linux 为例):

bash

# 克隆源码
git clone https://github.com/ossrs/srs.git
# 进入目录编译
cd srs/trunk && ./configure && make
# 启动服务器(默认端口1935,RTMP协议)
./objs/srs -c conf/srs.conf

启动后,通过telnet 127.0.0.1 1935能连接成功,说明 SRS 已正常运行。

2. SpringBoot 项目依赖配置

创建一个 SpringBoot 项目(推荐 2.x 版本,兼容性更稳定),在pom.xml中引入核心依赖:

  • Spring Web:提供 HTTP 接口,用于前后端交互;
  • FFmpeg 相关依赖:处理视频转码(如 RTMP 转 HLS,适配浏览器播放);
  • Lombok:简化代码,减少 getter/setter;
  • Spring Security(可选):用于推流 / 拉流权限控制。

关键依赖代码如下:

xml

<!-- Spring Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- FFmpeg工具类 -->
<dependency>
    <groupId>com.github.kokorin.jaffree</groupId>
    <artifactId>jaffree</artifactId>
    <version>1.5.11</version>
</dependency>
<!-- Lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

三、核心功能开发:从推流到拉流全流程

1. 推流端实现:用 FFmpeg 模拟推流

实际项目中,推流端可能是手机 APP、PC 客户端(如 OBS),但开发阶段我们可以用 FFmpeg 命令模拟推流,快速验证流程。

首先,准备一个测试视频文件(如test.mp4),执行以下命令将视频推送到 SRS 服务器:

bash

# 格式:ffmpeg -re -i 视频文件 -c:v libx264 -c:a aac -f flv rtmp://SRS服务器IP:1935/live/房间号
ffmpeg -re -i test.mp4 -c:v libx264 -c:a aac -f flv rtmp://192.168.1.100:1935/live/room123

其中,-re表示按视频实际帧率推流(避免推流过快),live是 SRS 配置的 “应用名”(对应srs.conf中的vhost __defaultVhost__下的app live),room123是 “流名”(可理解为直播房间 ID,需唯一)。

如果想通过 SpringBoot 接口触发推流(比如自动推流监控视频),可以封装 FFmpeg 工具类,通过 Java 代码调用 FFmpeg 命令:

java

@Slf4j
@Component
public class FFmpegUtil {
    // 推流方法:输入文件路径、SRS推流地址
    public void pushStream(String inputPath, String rtmpUrl) {
        try {
            // 构建FFmpeg命令
            FFmpeg.atPath()
                    .addArgument("-re")
                    .addArgument("-i")
                    .addArgument(inputPath)
                    .addArgument("-c:v")
                    .addArgument("libx264")
                    .addArgument("-c:a")
                    .addArgument("aac")
                    .addArgument("-f")
                    .addArgument("flv")
                    .addArgument(rtmpUrl)
                    .execute();
            log.info("推流成功,推流地址:{}", rtmpUrl);
        } catch (Exception e) {
            log.error("推流失败:{}", e.getMessage());
            throw new RuntimeException("推流异常", e);
        }
    }
}

2. 拉流端实现:多端适配(PC / 手机 / 浏览器)

拉流端需要适配不同设备,这里分两种场景实现:

(1)RTMP 拉流(适合 PC 客户端,如 VLC)

直接使用推流地址的 RTMP 链接,在 VLC 播放器中 “打开网络串流”,输入
rtmp://192.168.1.100:1935/live/room123,即可播放视频。

(2)HLS 拉流(适合浏览器 / 手机)

浏览器不支持 RTMP 协议,需要将 RTMP 流转成 HLS 流(生成.m3u8索引文件和.ts分片文件)。我们可以在 SRS 中配置自动转码,修改srs.conf:

conf

vhost __defaultVhost__ {
    app live {
        # 开启HLS转码
        hls {
            enabled on;
            # HLS文件保存路径(需提前创建)
            hls_path ./objs/nginx/html;
            # 分片时长(默认10秒,越小延迟越低)
            hls_fragment 5;
            # 索引文件包含的分片数
            hls_window 3;
        }
    }
}


重启 SRS 后,推流时会自动生成 HLS 文件,拉流地址为http://SRS服务器IP:8080/live/room123.m3u8(SRS 默认开启 8080 端口提供 HTTP 服务)。

在 SpringBoot 中,我们可以开发一个 “获取拉流地址” 的接口,根据设备类型返回不同协议的地址:

java

@RestController
@RequestMapping("/stream")
@RequiredArgsConstructor
public class StreamController {
    private final String srsIp = "192.168.1.100";

    // 获取拉流地址:deviceType=pc(RTMP)、mobile/browser(HLS)
    @GetMapping("/pull")
    public ResultVO getPullUrl(@RequestParam String roomId, @RequestParam String deviceType) {
        String pullUrl;
        if ("pc".equals(deviceType)) {
            pullUrl = "rtmp://" + srsIp + ":1935/live/" + roomId;
        } else {
            pullUrl = "http://" + srsIp + ":8080/live/" + roomId + ".m3u8";
        }
        return ResultVO.success("拉流地址获取成功", pullUrl);
    }
}

3. 权限控制:防止非法推流 / 拉流

没有权限控制的流很容易被 “盗用”,比如别人用你的推流地址推垃圾内容,或盗用你的直播流。我们可以用 Spring Security 实现简单的权限校验:

(1)推流权限校验

推流时,要求客户端携带 “认证令牌”,SpringBoot 接口验证令牌通过后,才返回有效的推流地址。

首先,生成推流令牌(可用 JWT):

java

@Component
public class JwtUtil {
    private final String secret = "springboot-stream-secret"; // 密钥,实际项目需加密存储

    // 生成推流令牌:包含房间号、过期时间(1小时)
    public String generatePushToken(String roomId) {
        return Jwts.builder()
                .setSubject(roomId)
                .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
    }

    // 验证令牌
    public boolean validateToken(String token, String roomId) {
        try {
            Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            return roomId.equals(claims.getSubject()) && new Date().before(claims.getExpiration());
        } catch (Exception e) {
            return false;
        }
    }
}

然后,开发 “获取推流地址” 的接口,验证令牌后返回地址:

java

@PostMapping("/push")
public ResultVO getPushUrl(@RequestParam String roomId, @RequestParam String token) {
    // 验证令牌
    if (!jwtUtil.validateToken(token, roomId)) {
        return ResultVO.error("令牌无效,无推流权限");
    }
    String pushUrl = "rtmp://" + srsIp + ":1935/live/" + roomId;
    return ResultVO.success("推流地址获取成功", pushUrl);
}

(2)拉流权限校验

拉流时,SRS 支持 “回调校验”,即每次拉流前,SRS 会调用 SpringBoot 的校验接口,通过后才允许拉流。配置srs.conf:

conf

vhost __defaultVhost__ {
    app live {
        # 拉流回调校验
        http_hooks {
            enabled on;
            # 校验接口地址
            on_hls_play http://SpringBoot服务器IP:8081/stream/checkPull;
        }
    }
}

SpringBoot 中开发校验接口,比如验证用户是否已登录:

java

@PostMapping("/checkPull")
public void checkPull(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // SRS回调时会携带roomId(流名)、userId(可从请求参数获取,需客户端传递)
    String roomId = request.getParameter("stream");
    String userId = request.getParameter("userId");
    
    // 模拟校验:用户是否已登录(实际项目查数据库/Redis)
    boolean hasPermission = "user123".equals(userId);
    
    // 校验通过返回200,失败返回403
    if (hasPermission) {
        response.setStatus(HttpServletResponse.SC_OK);
    } else {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    }
}

四、实战避坑:这些问题 90% 的人都会遇到

1. 推流失败:连接超时 / 拒绝连接

  • 原因 1:SRS 服务器未启动,或端口被占用(1935 端口常用,可能被其他程序占用)。
    解决:用netstat -tuln | grep 1935查看端口占用,杀死占用进程后重启 SRS。
  • 原因 2:防火墙未开放 1935(RTMP)、8080(HLS HTTP)端口。
    解决:Linux 执行firewall-cmd --add-port=1935/tcp --permanent和firewall-cmd --add-port=8080/tcp --permanent,然后firewall-cmd --reload。

2. 拉流延迟过高(超过 30 秒)

  • 原因:HLS 分片时长设置过大,或 SRS 缓存配置不合理。
    解决:在srs.conf中减小hls_fragment(如设为 3 秒),同时开启 “低延迟模式”:

conf

hls {
    enabled on;
    hls_fragment 3;
    hls_window 2;
    # 开启低延迟
    hls_low_latency on;
}


3. 浏览器播放 HLS 流卡顿

  • 原因:视频码率过高,浏览器加载分片慢;或分片文件未及时生成。
    解决:推流时降低码率(FFmpeg 命令加-b:v 500k,表示视频码率 500kbps);同时确保 SRS 的hls_path目录有写入权限。

五、项目优化:从 “能用” 到 “好用”

1. 流状态监控

实时监控推流是否正常,避免 “推流断了但没人知道”。可以用 SRS 的 HTTP API 获取流状态,SpringBoot 定时调用接口:

java

@Component
@Scheduled(fixedRate = 5000) // 每5秒监控一次
public class StreamMonitor {
    private final String srsApiUrl = "http://192.168.1.100:8080/api/v1/streams";

    @Autowired
    private RestTemplate restTemplate;

    public void monitorStream() {
        try {
            String response = restTemplate.getForObject(srsApiUrl, String.class);
            // 解析JSON,判断流是否存在(如room123是否在流列表中)
            JSONObject json = new JSONObject(response);
            JSONArray streams = json.getJSONArray("streams");
            boolean isPushing = streams.stream()
                    .map(JSONObject.class::cast)
                    .anyMatch(s -> "live/room123".equals(s.getString("name")));
            
            if (!isPushing) {
                log.warn("房间room123推流已中断!");
                // 发送告警(如短信、钉钉通知)
            }
        } catch (Exception e) {
            log.error("流监控失败:{}", e.getMessage());
        }
    }
}

2. 集群部署(高并发场景)

当直播房间多、观众量大时,单台 SRS 服务器扛不住,需要集群部署。核心思路是:

  • 用 Nginx 做负载均衡,分发推流 / 拉流请求;
  • 多台 SRS 服务器通过 “集群同步”(如 SRS 的 RTMP Edge 模式)共享流数据;
  • SpringBoot 服务集群部署,用 Redis 共享用户会话、流状态。

六、总结:快速上手的核心要点

  1. 先搭环境再开发:优先搞定 SRS 服务器,用 FFmpeg 模拟推流,验证基础流程;
  2. 协议选择看场景:低延迟用 RTMP,兼容性用 HLS;
  3. 权限控制不能少:用 JWT+SRS 回调防止非法访问;
  4. 遇到问题先查日志:SRS 日志(./objs/srs.log)和 SpringBoot 日志是排错关键。

按照本文的步骤,你可以在 1 小时内搭建一个能跑通的 SpringBoot 视频推拉流系统,后续再根据业务需求(如直播带货、在线教育)扩展功能(如弹幕、连麦)。如果在开发中遇到具体问题,欢迎在评论区交流!


感谢关注【AI码力】!

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言