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

java是实现视频流Rtsp转Rtmp

简言:视频流格式大致分为:RTMP、RTSP、RTP、HLS、MPEG-DASH。
本文就只说一下Rtsp转Rtmp格式,转换成功之后Rtmp的视频流存储到srs上
Pom文件

<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.1</version>
</dependency>

Constant类

public class Constant {public final static String rtmp="rtmp://";public final static String colon=":";public final static String slash="/";public final static String stop="stop";
}

application.properties

rtmp.host: 
rtmp.port: 
rtmp.folder: 

rtmp.host: srs安装的ip地址
rtmp.port: srs的端口
rtmp.folder:视频流存储的位置

具体实现

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author: majinzhong* @date: 2022/6/10 13:53* @Version 1.0*/
@RestController
@CrossOrigin
@RequestMapping("/stream")
public class CameraPushController {@Value("${rtmp.host}")public String rtmpHost;@Value("${rtmp.port}")public String rtmpPort;@Value("${rtmp.folder}")public String rtmpFolder;@RequestMapping("/info")public String info(){return "项目启动成功";}/**** @param rtsUrl rtsp的推流地址(在用户关闭时也要传值)* @param status 是否停止的状态(在用户关闭时传值,其他时候不传)* @return*/@RequestMapping("/push")public String streamPush(String rtsUrl,String status)throws Exception{//取出rtsUrl入参中的最后一个/后的streamIdString streamId = rtsUrl.substring(rtsUrl.lastIndexOf(Constant.slash) + 1);//对SRS的推流地址进行拼接String rtmpUrl = Constant.rtmp + rtmpHost + Constant.colon + rtmpPort + Constant.slash + rtmpFolder + Constant.slash + streamId;//实例化帧抓取器对象,将rtsp地址放入FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtsUrl);grabber.setOption("rtsp_transport", "tcp");//初始化帧抓取器grabber.start();//实例化FFmpegFrameRecorder,将SRS地址传入FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(rtmpUrl,grabber.getImageWidth() * 2,grabber.getImageHeight() * 2,grabber.getAudioChannels());int v_rs = 25;//设置编码格式recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//设置封装格式recorder.setFormat("flv");//一秒内的帧数recorder.setFrameRate(v_rs);//两个关键帧之间的帧数recorder.setGopSize(v_rs);//设置音频通道,与视频源的通道数相等recorder.setAudioChannels(grabber.getAudioChannels());FFmpegLogCallback.set();//初始化帧录制器recorder.start();try {//使用异步线程让视频流 从rtsp转为rtmpif(!StringUtils.isEmpty(status)) {//获取当前所有在运行的线程ThreadGroup currentGroup =Thread.currentThread().getThreadGroup();int noThreads = currentGroup.activeCount();Thread[] lstThreads = new Thread[noThreads];currentGroup.enumerate(lstThreads);for (int i = 0; i < noThreads; i++){//找到视频流的线程if("push".equals(lstThreads[i].getName())){//让视频流线程睡眠1秒,因为在执行的线程不能直接结束lstThreads[i].sleep(1000);//结束线程,阻止推流lstThreads[i].suspend();}}//如果是停止就关闭录制器和抓取器并退出程序,如果是替换,就继续创建新线程推流if(Constant.stop.equals(status)) {//关闭帧录制器recorder.close();//关闭帧抓取器grabber.close();return "停止推流成功!";}}//创建新线程进行推流Thread thread = new Thread(() -> {try {//持续从视频源取帧Frame frame;while (null != (frame = grabber.grab())) {//取出的每一帧都推送到SRSrecorder.record(frame);}} catch (Exception e) {e.printStackTrace();}});//给线程设置名称,方便后续查找thread.setName("push");//启动线程thread.start();}catch (Exception e){e.printStackTrace();System.out.println(e);}return rtmpUrl;}
}


文章转载自:
http://basaltic.gbfuy28.cn
http://barmecidal.gbfuy28.cn
http://bobbly.gbfuy28.cn
http://allegorically.gbfuy28.cn
http://accordatura.gbfuy28.cn
http://bootleg.gbfuy28.cn
http://basso.gbfuy28.cn
http://acoelomate.gbfuy28.cn
http://centimetre.gbfuy28.cn
http://brotherless.gbfuy28.cn
http://buccinator.gbfuy28.cn
http://azov.gbfuy28.cn
http://blighty.gbfuy28.cn
http://arabinose.gbfuy28.cn
http://bargello.gbfuy28.cn
http://almacantar.gbfuy28.cn
http://brickfield.gbfuy28.cn
http://azus.gbfuy28.cn
http://cga.gbfuy28.cn
http://amnesty.gbfuy28.cn
http://algebraical.gbfuy28.cn
http://calciferol.gbfuy28.cn
http://champignon.gbfuy28.cn
http://byroad.gbfuy28.cn
http://affirmant.gbfuy28.cn
http://actualistic.gbfuy28.cn
http://aftertime.gbfuy28.cn
http://breen.gbfuy28.cn
http://anima.gbfuy28.cn
http://bibulosity.gbfuy28.cn
http://www.dtcms.com/a/135025.html

相关文章:

  • 从工业到家居:电源方案的广泛应用 | 多领域解决方案
  • VMWare 16 PRO 安装 Rocky8 并部署 MySQL8
  • 低功耗数字工厂的新时代:安卓触摸一体机助力绿色高效管理
  • SAP ABAP BOM 抬头更改(BAPI:CSAP_MAT_BOM_MAINTAIN)
  • 20250415-vue-插槽-默认内容
  • 「数据可视化 D3系列」入门第二章:选择器与数据绑定
  • DELL电脑开机进入自检界面
  • 【开源项目】Excel手撕AI算法深入理解(三):Backpropagation、mamba、RNN
  • TypeScript 快速上手--禹神
  • Redis-高级篇(分布式缓存/持久化)
  • 数据结构(4)
  • redis 放置序列化的对象,如果修改对象,需要修改版本号吗?
  • 数据库的基本原则
  • 【Vue级联选择器数据处理优化:解决企业类型选择与回显问题】
  • 实现添加用户和SpringBoot-实现修改和删除
  • Golang|在线排查协程泄漏
  • Go:goroutine 和通道
  • 按键精灵安卓/ios脚本辅助工具开发教程:如何把界面配置保存到服务器
  • Linux——共享内存
  • 2025年第十六届蓝桥杯省赛JavaB组真题回顾
  • 威锋VL822-Q7T10GHUB芯片适用于扩展坞显示器
  • Java异常报错:java.nio.channels.UnresolvedAddressException
  • 在 IntelliJ IDEA 中开发 Java Web 项目时,遇到包内明明存在某个类但类名仍然爆红(显示红色错误提示)
  • 广汽滴滴Robotaxi首次亮相,中国自动驾驶加速领跑新赛道
  • 明天见!奇兵到家将携“偏远服务第一网”登陆成都建博会
  • Linux常见指令介绍上(入门级)
  • ubuntu 2204 安装 vcs 2023
  • LangChain4j (3):集成 DeepSeek 大模型的Java程序
  • 质量问题频发,如何提升源头把控
  • classpath “com.android.tools.build:gradle:8.1.0“ 和 Gradle插件版本8.5 有什么关系