从 0 到 1,实战 SpringBoot 打造轻量视频推拉流系统

whdahanh 发布于 2025-09-29 384 次阅读


在智慧安防、在线教育直播、户外设备实时回传等实际项目中,视频推拉流是核心基础能力。最初我尝试基于 Netty 手动封装 RTSP 协议实现服务 —— 既要处理 RTSP 的信令交互,又要解决视频帧解包的时序同步问题,实际开发中不仅遇到解包效率低的瓶颈,还出现了不同设备兼容性差的问题,自研成本远超预期。

后来偶然发现Zlm4j这个工具:它是基于高性能流媒体框架 ZLMediaKit 封装的 JNA 接口,能直接与 SpringBoot 无缝集成,省去了底层协议解析、端口管理等繁琐工作。特别感谢 ZLMediaKit 与 Zlm4j 的开源团队,让我们不用重复造轮子,快速落地流媒体服务。

本文将结合完整代码,一步步教你在 SpringBoot 中搭建可直接复用的视频推拉流系统,涵盖推流鉴权、多协议播放、前端可视化页面,帮助你跳过 “踩坑环节”,直接对接实际业务需求。

核心实现步骤

第一步:引入关键依赖

项目核心依赖围绕 Zlm4j 展开,同时搭配 Web 模块与 Thymeleaf 模板引擎(用于前端页面),无需单独安装 ZLMediaKit 服务,JNA 会自动处理底层调用。

pom.xml配置如下:

<!-- Zlm4j:封装ZLMediaKit核心能力 --><dependency>    <groupId>com.aizuda</groupId>    <artifactId>zlm4j</artifactId>    <version>1.0.5</version>    <scope>system</scope>    <systemPath>${project.basedir}/lib/zlm4j-1.0.5.jar</systemPath></dependency><!-- JNA:处理底层SDK调用 --><dependency>    <groupId>net.java.dev.jna</groupId>    <artifactId>jna</artifactId>    <version>5.15.0</version></dependency><!-- SpringBoot Web:提供HTTP服务 --><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><!-- Thymeleaf:前端页面渲染 --><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

第二步:编写配置类,启动多协议服务

创建配置类ZlmStreamConfig,核心作用是初始化 ZLMediaKit 环境、启动 HTTP/RTSP/RTMP/RTP 等主流流媒体协议服务,同时注册事件监听载体。

代码示例:

package com.stream.config;import com.aizuda.zlm4j.core.ZLMApi;import com.aizuda.zlm4j.structure.MK_EVENTS;import com.sun.jna.Native;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class ZlmStreamConfig {    /**     * 初始化ZLMApi,启动多协议服务     */    @Bean    public ZLMApi zlmApi() {        // 加载ZLMediaKit核心库        ZLMApi zlmApi = Native.load("mk_api", ZLMApi.class);
        // 初始化SDK环境:日志开启、后台运行、默认配置        zlmApi.mk_env_init1(1, 1, 1, null, 0, 0, null, 0, null, null);
        // 启动各协议服务(端口可根据业务调整)        zlmApi.mk_http_server_start((short) 7789, 0);  // HTTP服务:用于FLV/HLS播放        zlmApi.mk_rtsp_server_start((short) 9758, 0); // RTSP服务:常用于设备推流        zlmApi.mk_rtmp_server_start((short) 9760, 0); // RTMP服务:常用于直播平台        zlmApi.mk_rtp_server_start((short) 32001);    // RTP服务:用于实时媒体传输
        return zlmApi;    }    /**     * 注册事件监听载体:处理推流鉴权、流状态变化等事件     */    @Bean    public MK_EVENTS mkEvents() {        return new MK_EVENTS();    }}

各协议端口说明如下:

协议端口用途
HTTP7789提供 HTTP-FLV、HLS 格式视频播放
RTSP9758接收设备(如摄像头)推流
RTMP9760接收直播推流、支持播放器播放
RTP32001低延迟实时媒体数据传输

第三步:实现事件监听,保障服务安全

在 SpringBoot 启动类中实现CommandLineRunner接口,注册推流鉴权流状态监控事件 —— 前者防止非法推流,后者实时感知流的上线 / 下线,方便排查问题。https://wxa.wxs.qq.com/tmpl/oc/base_tmpl.html

代码示例:

package com.stream;import com.aizuda.zlm4j.core.ZLMApi;import com.aizuda.zlm4j.structure.MK_EVENTS;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import java.util.Date;@SpringBootApplicationpublic class VideoStreamApp implements CommandLineRunner {    @Autowired    private MK_EVENTS mkEvents;    @Autowired    private ZLMApi zlmApi;    public static void main(String[] args) {        SpringApplication.run(VideoStreamApp.class, args);    }    @Override    public void run(String... args) {        // 1. 推流鉴权事件:验证推流请求合法性        mkEvents.on_mk_media_publish = (urlInfo, invoker, sender) -> {            // 获取推流携带的鉴权参数(如token)            String authParams = zlmApi.mk_media_info_get_params(urlInfo);            System.out.println("[" + new Date() + "] 推流鉴权参数:" + authParams);            // 实际业务中可校验token:合法则允许推流(0表示通过),非法则拒绝            boolean isAuthPass = authParams.contains("token=stream2025");            zlmApi.mk_publish_auth_invoker_do(invoker, "", isAuthPass ? 0 : 1, 0);        };        zlmApi.mk_events_listen(mkEvents);        // 2. 流状态变化事件:监控流的上线/下线        mkEvents.on_mk_media_changed = (isOnline, sender) -> {            String appName = zlmApi.mk_media_source_get_app(sender);            String streamName = zlmApi.mk_media_source_get_stream(sender);            String protocol = zlmApi.mk_media_source_get_schema(sender);
            String status = isOnline == 1 ? "上线" : "下线";            System.out.println("[" + new Date() + "] 流状态变化:" + protocol + "://" + appName + "/" + streamName + " " + status);        };        zlmApi.mk_events_listen(mkEvents);    }}

推拉流测试:验证链路通畅

1. 推流操作(基于 FFmpeg)

使用 FFmpeg 工具将本地视频文件推送到 RTSP 服务端口,同时携带鉴权 token(需与鉴权逻辑匹配)。
打开终端执行命令:

# -re:按视频实际速率推流;-an:不传输音频;-c:v libx264:使用H.264视频编码ffmpeg -re -an -i /Users/test/videos/demo.mp4 -c:v libx264 -f rtsp rtsp://127.0.0.1:9758/live/demo?token=stream2025

2. 控制台事件输出

推流成功后,控制台会打印鉴权信息和流上线通知:

[Wed Sep 05 08:30:00 CST 2025] 推流鉴权参数:token=stream2025[Wed Sep 05 08:30:01 CST 2025] 流状态变化:rtsp://live/demo 上线

3. 播放验证(多播放器支持)

  • VLC 播放器打开 “媒体”→“打开网络串流”,输入 RTMP 地址 rtmp://127.0.0.1:9760/live/demo,点击播放即可观看。
  • PotPlayer输入 HTTP-FLV 地址 http://127.0.0.1:7789/live/demo.flv,支持更低延迟播放。

前端播放页面:可视化交互

为了让业务方更方便地使用,我们基于Thymeleaf+Bootstrap+flv.js开发前端页面,支持浏览器直接播放视频。

第一步:编写控制器(跳转页面)

创建StreamPlayerController,传递视频播放地址到前端:

package com.stream.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;@Controllerpublic class StreamPlayerController {    /**     * 跳转视频播放页面     */    @GetMapping("/stream/player")    public String toPlayerPage(Model model) {        // 传递HTTP-FLV播放地址(浏览器兼容性更好)        String flvUrl = "http://127.0.0.1:7789/live/demo.flv";        model.addAttribute("videoUrl", flvUrl);        return "stream-player";    }}

第二步:开发前端页面(stream-player.html)

页面采用 Bootstrap 美化布局,使用 flv.js 处理 FLV 格式视频,同时增加播放状态提示:

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>实时视频播放平台</title>    <!-- 引入Bootstrap样式 -->    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">    <!-- 引入flv.js:处理FLV视频流 -->    <script src="https://cdn.jsdelivr.net/npm/flv.js/dist/flv.min.js"></script></head><body class="bg-gray-100"><div class="container mt-6">    <!-- 页面标题 -->    <div class="text-center mb-5">        <h2 class="text-primary">实时视频播放</h2>        <p class="text-muted" id="playStatus">等待推流连接...</p>    </div>    <!-- 视频播放区域 -->    <div class="card shadow rounded-4">        <div class="card-body p-0">            <video id="streamPlayer" class="w-100 rounded-top-4" controls autoplay></video>            <div class="p-3 bg-light">                <p class="mb-0"><span class="fw-bold">播放地址:</span><span th:text="${videoUrl}"></span></p>            </div>        </div>    </div></div><script th:inline="javascript">    // 获取后端传递的视频地址    const videoUrl = [[${videoUrl}]];    const videoElement = document.getElementById('streamPlayer');    const statusElement = document.getElementById('playStatus');    // 初始化flv播放器    if (flvjs.isSupported()) {        const flvPlayer = flvjs.createPlayer({            type: 'flv',            url: videoUrl,            isLive: true // 标记为直播流,优化延迟        });        // 绑定视频元素        flvPlayer.attachMediaElement(videoElement);        // 加载并播放        flvPlayer.load();        flvPlayer.play().then(() => {            statusElement.textContent = "播放中(低延迟模式)";            statusElement.className = "text-success fw-medium";        }).catch(error => {            statusElement.textContent = "播放失败:" + error.message;            statusElement.className = "text-danger";        });        // 监听播放错误        flvPlayer.on('error', (err) => {            statusElement.textContent = "播放异常:" + err;            statusElement.className = "text-danger";        });        // 监听流断开        flvPlayer.on('stats', (stats) => {            if (stats.bufferedLength === 0 && !flvPlayer.isPlaying()) {                statusElement.textContent = "流已断开,请检查推流服务";                statusElement.className = "text-warning";            }        });    } else {        statusElement.textContent = "当前浏览器不支持FLV播放,请更换Chrome/Firefox";        statusElement.className = "text-danger";    }</script></body></html>

访问页面

启动SpringBoot 项目后,在浏览器输入

http://127.0.0.1:8080/stream/player,即可看到视频播放页面 —— 推流正常时会自动播放,同时显示实时状态。

系统总结与扩展方向

核心优势

  1. 后端轻量高效基于 Zlm4j 封装,无需关注底层协议,几行配置即可启动多协议服务;
  2. 安全可控支持推流鉴权,防止非法接入;流状态监控便于问题排查;
  3. 前端易用浏览器直接播放,无需安装额外插件,适配主流浏览器;
  4. 兼容性强支持 RTSP/RTMP/HTTP-FLV/HLS 等多种协议,可对接摄像头、直播软件等不同设备。

扩展方向

  • 视频录制集成 ZLMediaKit 的录制接口,实现 “推流即录制”,支持按时间切片存储;
  • 多房间管理基于 Redis 存储流信息,实现多用户同时观看不同流,支持房间权限控制;
  • 转码功能添加 FFmpeg 转码服务,自动将视频转为多种分辨率(如 720P/480P),适配不同网络环境;
  • 告警通知对流断开、推流超时等异常情况,通过短信 / 邮件发送告警,提升运维效率


微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2025-09-29