水军大提督 发表于 2025-4-16 08:34:58

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]
查看完整版本: java是实现视频流Rtsp转Rtmp