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入参中的最后一个/后的streamId
String 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转为rtmp
if(!StringUtils.isEmpty(status)) {
//获取当前所有在运行的线程
ThreadGroup currentGroup =
Thread.currentThread().getThreadGroup();
int noThreads = currentGroup.activeCount();
Thread[] lstThreads = new Thread;
currentGroup.enumerate(lstThreads);
for (int i = 0; i < noThreads; i++){
//找到视频流的线程
if("push".equals(lstThreads.getName())){
//让视频流线程睡眠1秒,因为在执行的线程不能直接结束
lstThreads.sleep(1000);
//结束线程,阻止推流
lstThreads.suspend();
}
}
//如果是停止就关闭录制器和抓取器并退出程序,如果是替换,就继续创建新线程推流
if(Constant.stop.equals(status)) {
//关闭帧录制器
recorder.close();
//关闭帧抓取器
grabber.close();
return "停止推流成功!";
}
}
//创建新线程进行推流
Thread thread = new Thread(() -> {
try {
//持续从视频源取帧
Frame frame;
while (null != (frame = grabber.grab())) {
//取出的每一帧都推送到SRS
recorder.record(frame);
}
} catch (Exception e) {
e.printStackTrace();
}
});
//给线程设置名称,方便后续查找
thread.setName("push");
//启动线程
thread.start();
}catch (Exception e){
e.printStackTrace();
System.out.println(e);
}
return rtmpUrl;
}
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]