当前位置: 首页 > news >正文

spring boot 实现resp视频推流

1、搭建resp服务(docker方式)

docker pull aler9/rtsp-simple-server
docker run -d --restart=always \--name rtsp-server \-p 8554:8554 \aler9/rtsp-simple-server

2、maven依赖

<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.11</version><exclusions><exclusion><groupId>org.bytedeco</groupId><artifactId>opencv</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.bytedeco</groupId><artifactId>ffmpeg-platform</artifactId><version>7.1-1.5.11</version></dependency>

3、新建RtspStreamer服务类

package com.example.superior_conjuncte_iot_web.system_config.videoConfig;import jakarta.annotation.PreDestroy;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.stereotype.Component;import java.awt.image.BufferedImage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;@Component
public class RtspStreamer {static {// 强制加载 FFmpeg 核心库Loader.load(org.bytedeco.ffmpeg.global.avutil.class);Loader.load(org.bytedeco.ffmpeg.global.avcodec.class);Loader.load(org.bytedeco.ffmpeg.global.avformat.class);}private FFmpegFrameRecorder recorder;private ExecutorService executor = Executors.newSingleThreadExecutor();private boolean isStreaming = false;private final Java2DFrameConverter converter = new Java2DFrameConverter();/*** 启动 RTSP 流服务* @param rtspUrl 例如: "rtsp://localhost:8554/live"* @param width 视频宽度* @param height 视频高度*/public void startStream(String rtspUrl, int width, int height) {if (isStreaming) return;recorder = new FFmpegFrameRecorder(rtspUrl, width, height);recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 编码格式recorder.setFormat("rtsp"); // 输出格式
//        recorder.setFrameRate(30); // 帧率recorder.setFrameRate(25);try {recorder.start();isStreaming = true;} catch (Exception e) {e.printStackTrace();throw new RuntimeException("启动 RTSP 失败", e);}}/*** 推送视频帧* @param image 视频帧图像*/public void pushFrame(BufferedImage image) {if (!isStreaming) return;executor.submit(() -> {try {Frame frame = converter.getFrame(image);recorder.record(frame);} catch (Exception e) {e.printStackTrace();}});}@PreDestroypublic void stopStream() {if (recorder != null) {try {isStreaming = false;recorder.stop();recorder.release();} catch (Exception e) {e.printStackTrace();}}executor.shutdown();}
}

4、测试代码

package com.example.superior_conjuncte_iot_web.tj.project_video.service.impl;import com.example.superior_conjuncte_iot_web.system_config.videoConfig.RtspStreamer;
import com.example.superior_conjuncte_iot_web.tj.project_video.service.IVideoRtspService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;import java.awt.*;
import java.awt.image.BufferedImage;@Service
@Slf4j
public class VideoRtspServiceImpl implements IVideoRtspService, ApplicationRunner {@Resource@Lazyprivate RtspStreamer rtspStreamer;@Overridepublic void run(ApplicationArguments args)  {rtspStreamer.startStream("rtsp://localhost:8554/live", 640, 480);// 模拟生成视频帧(例如从摄像头或文件读取)Thread thread=new Thread(() -> {while (true) {BufferedImage image = generateTestFrame(); // 生成测试帧rtspStreamer.pushFrame(image);try {Thread.sleep(33); // 约30帧/秒} catch (InterruptedException e) {e.printStackTrace();}}});thread.setDaemon(true);thread.start();}// 生成测试帧(渐变颜色)private BufferedImage generateTestFrame() {BufferedImage img = new BufferedImage(640, 480, BufferedImage.TYPE_3BYTE_BGR);Graphics2D g2d = img.createGraphics();g2d.setColor(new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)));g2d.fillRect(0, 0, 640, 480);g2d.dispose();return img;}
}

5、用VLC工具测试
测试地址:rtsp://localhost:8554/live,其中localhost:8554为rtsp服务器的地址

相关文章:

  • 数据结构:绪论之时间复杂度与空间复杂度
  • OceanBase数据库全面指南(函数篇)函数速查表
  • 基于cornerstone3D的dicom影像浏览器 第二十一章 显示DICOM TAGS
  • 先更新数据库,再删除缓存的cache aside策略
  • 性能测试、压力测试、负载测试如何区分
  • 工业 / 农业 / AR 场景怎么选?Stereolabs ZED 双目3D相机型号对比与选型建议
  • 【Django Serializer】一篇文章详解 Django 序列化器
  • WooCommerce缓存教程 – 如何防止缓存破坏你的WooCommerce网站?
  • [免费]微信小程序宠物医院管理系统(uni-app+SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
  • 初步尝试AI应用开发平台——Dify的本地部署和应用开发
  • 优化 CRM 架构,解锁企业竞争力密码
  • 【开源解析】基于深度学习的双色球预测系统:从数据获取到可视化分析
  • Redisson分布式锁案列和源码解读
  • labview设计一个虚拟信号发生器
  • 大模型应用开发之Dify进阶版使用教程—react前端+django后端+dify-API制作聊天界面
  • 了解Android studio 初学者零基础推荐(2)
  • 高级SQL技巧:时序数据查询优化与性能调优实战
  • Labview实现计算CPK参数
  • 在react项目中使用andt日期组件,选择周和季度,直接获取所对应的日期区间
  • 鸿蒙仓颉开发语言实战教程:实现商城应用首页
  • 政府门户网站内容建设/业务网站制作
  • 网站内地图位置怎么做/关键词全网搜索工具
  • wordpress 网站搬家/互联网营销师培训费用是多少
  • 手机友好型网站/网络推广公司运营
  • 做会计应关注什么网站/小网站
  • 百度一直不收录网站/精准的搜索引擎优化