java是实现视频流Rtsp转Rtmp

打印 上一主题 下一主题

主题 1599|帖子 1599|积分 4797

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
简言:视频流格式大致分为:RTMP、RTSP、RTP、HLS、MPEG-DASH。
本文就只说一下Rtsp转Rtmp格式,转换成功之后Rtmp的视频流存储到srs上
Pom文件
  1. <dependency>
  2.     <groupId>org.bytedeco</groupId>
  3.     <artifactId>javacv-platform</artifactId>
  4.     <version>1.5.1</version>
  5. </dependency>
复制代码
Constant类
  1. public class Constant {
  2.     public final static String rtmp="rtmp://";
  3.     public final static String colon=":";
  4.     public final static String slash="/";
  5.     public final static String stop="stop";
  6. }
复制代码
application.properties
  1. rtmp.host:
  2. rtmp.port:
  3. rtmp.folder:
复制代码
rtmp.host: srs安装的ip所在
rtmp.port: srs的端口
rtmp.folder:视频流存储的位置
详细实现
  1. import org.bytedeco.ffmpeg.global.avcodec;
  2. import org.bytedeco.javacv.FFmpegFrameGrabber;
  3. import org.bytedeco.javacv.FFmpegFrameRecorder;
  4. import org.bytedeco.javacv.FFmpegLogCallback;
  5. import org.bytedeco.javacv.Frame;
  6. import org.springframework.beans.factory.annotation.Value;
  7. import org.springframework.util.StringUtils;
  8. import org.springframework.web.bind.annotation.CrossOrigin;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RestController;
  11. /**
  12. * @author: majinzhong
  13. * @date: 2022/6/10 13:53
  14. * @Version 1.0
  15. */
  16. @RestController
  17. @CrossOrigin
  18. @RequestMapping("/stream")
  19. public class CameraPushController {
  20.     @Value("${rtmp.host}")
  21.     public String rtmpHost;
  22.     @Value("${rtmp.port}")
  23.     public String rtmpPort;
  24.     @Value("${rtmp.folder}")
  25.     public String rtmpFolder;
  26.     @RequestMapping("/info")
  27.     public String info(){
  28.         return "项目启动成功";
  29.     }
  30.     /**
  31.      *
  32.      * @param rtsUrl rtsp的推流地址(在用户关闭时也要传值)
  33.      * @param status 是否停止的状态(在用户关闭时传值,其他时候不传)
  34.      * @return
  35.      */
  36.     @RequestMapping("/push")
  37.     public String streamPush(String rtsUrl,String status)throws Exception{
  38.         //取出rtsUrl入参中的最后一个/后的streamId
  39.         String streamId = rtsUrl.substring(rtsUrl.lastIndexOf(Constant.slash) + 1);
  40.         //对SRS的推流地址进行拼接
  41.         String rtmpUrl = Constant.rtmp + rtmpHost + Constant.colon + rtmpPort + Constant.slash + rtmpFolder + Constant.slash + streamId;
  42.         //实例化帧抓取器对象,将rtsp地址放入
  43.         FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtsUrl);
  44.         grabber.setOption("rtsp_transport", "tcp");
  45.         //初始化帧抓取器
  46.         grabber.start();
  47.         //实例化FFmpegFrameRecorder,将SRS地址传入
  48.         FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(rtmpUrl,
  49.                 grabber.getImageWidth() * 2,
  50.                 grabber.getImageHeight() * 2,
  51.                 grabber.getAudioChannels());
  52.         int v_rs = 25;
  53.         //设置编码格式
  54.         recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
  55.         //设置封装格式
  56.         recorder.setFormat("flv");
  57.         //一秒内的帧数
  58.         recorder.setFrameRate(v_rs);
  59.         //两个关键帧之间的帧数
  60.         recorder.setGopSize(v_rs);
  61.         //设置音频通道,与视频源的通道数相等
  62.         recorder.setAudioChannels(grabber.getAudioChannels());
  63.         FFmpegLogCallback.set();
  64.         //初始化帧录制器
  65.         recorder.start();
  66.         try {
  67.             //使用异步线程让视频流 从rtsp转为rtmp
  68.             if(!StringUtils.isEmpty(status)) {
  69.                 //获取当前所有在运行的线程
  70.                 ThreadGroup currentGroup =
  71.                         Thread.currentThread().getThreadGroup();
  72.                 int noThreads = currentGroup.activeCount();
  73.                 Thread[] lstThreads = new Thread[noThreads];
  74.                 currentGroup.enumerate(lstThreads);
  75.                 for (int i = 0; i < noThreads; i++){
  76.                     //找到视频流的线程
  77.                     if("push".equals(lstThreads[i].getName())){
  78.                         //让视频流线程睡眠1秒,因为在执行的线程不能直接结束
  79.                         lstThreads[i].sleep(1000);
  80.                         //结束线程,阻止推流
  81.                         lstThreads[i].suspend();
  82.                     }
  83.                 }
  84.                 //如果是停止就关闭录制器和抓取器并退出程序,如果是替换,就继续创建新线程推流
  85.                 if(Constant.stop.equals(status)) {
  86.                     //关闭帧录制器
  87.                     recorder.close();
  88.                     //关闭帧抓取器
  89.                     grabber.close();
  90.                     return "停止推流成功!";
  91.                 }
  92.             }
  93.             //创建新线程进行推流
  94.             Thread thread = new Thread(() -> {
  95.                 try {
  96.                     //持续从视频源取帧
  97.                     Frame frame;
  98.                     while (null != (frame = grabber.grab())) {
  99.                         //取出的每一帧都推送到SRS
  100.                         recorder.record(frame);
  101.                     }
  102.                 } catch (Exception e) {
  103.                     e.printStackTrace();
  104.                 }
  105.             });
  106.             //给线程设置名称,方便后续查找
  107.             thread.setName("push");
  108.             //启动线程
  109.             thread.start();
  110.         }catch (Exception e){
  111.             e.printStackTrace();
  112.             System.out.println(e);
  113.         }
  114.         return rtmpUrl;
  115.     }
  116. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

水军大提督

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表