返回 导航

SpringBoot / Cloud

hangge.com

SpringBoot - 使用javaCV截取RTMP、RTSP视频流图片

作者:hangge | 2024-05-09 08:20
    有时我们需要在后台自动拉取 rtsprtmp 等视频流并进行截图,这个使用 javaCV 库即可实现。javaCV 之所以叫 javaCV 就是因为 openCV 而得名,不过 javaCV 的功能远远大于 openCVopenCV 只能用于处理图像,而 javacv 不仅包含 openCV 全套 api,还支持 ffmpeg 音视频编解码,tensflowcaffe 等深度学习库,tessrac ocr 等字符识别,矩阵计算库。下面我通过样例演示如何使用 javaCV

1,安装配置

在项目 pom.xml 文件中添加 javaCV 依赖配置即可:
<dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>javacv-platform</artifactId>
        <version>1.5.7</version>
</dependency>

2,使用样例

(1)下面样例中我们获取一个 RTSP 视频流并截取视频图片:
public class VideoCapture {
  public static void main(String[] args)  {
    // 视频路径
    String url = "rtmp://ns8.indexforce.com/home/mystream";
    // 保存路径
    String savePath = "/Users/hangge/Desktop/" + System.currentTimeMillis() + ".jpg";

    try {
      // 开始截图
      startCaputre(url, savePath);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 开始截图
   */
  public static void startCaputre(String url, String savePath)
          throws IOException, InterruptedException{
    FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(url);
    grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重
    //grabber.setImageWidth(960); //设置宽高尺寸(不设置则使用视频流原始宽高)
    //grabber.setImageHeight(540);
    System.out.println("--- grabber start ---");
    grabber.start();
    while (true){
      Frame frame = grabber.grabImage();
      if (frame != null) {
        File outPut = new File(savePath);
        ImageIO.write(frameToBufferedImage(frame), "jpg", outPut);
        grabber.stop();
        grabber.release();
        System.out.println("图片已保存:" + outPut.getPath());
        System.out.println("--- grabber end ---");
        break;
      }
    }
  }

  /**
   * 创建BufferedImage对象
   */
  public static BufferedImage frameToBufferedImage(Frame frame) {
    Java2DFrameConverter converter = new Java2DFrameConverter();
    BufferedImage bufferedImage = converter.getBufferedImage(frame);
    return bufferedImage;
  }
}

(2)运行结构如下,可以看到视频图片已经成功保存到本地:

附一:实现视频的连续截图

(1)下面对样例稍作修改,可以通过设置时间间隔(秒)和最大截图张数来实现连续截图:
public class VideoCapture {
  public static void main(String[] args)  {
    // 视频路径
    String url = "rtmp://ns8.indexforce.com/home/mystream";
    // 保存路径
    String savePath = "/Users/hangge/Desktop/";

    try {
      // 开始截图(每5秒截取一张图片,总共10张)
      startCaputre(url, savePath, 5, 10);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 开始截图
   */
  public static void startCaputre(String url, String savePath, int interval, int total)
          throws IOException, InterruptedException{
    FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(url);
    grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重
    //grabber.setImageWidth(960); //设置宽高尺寸(不设置则使用视频流原始宽高)
    //grabber.setImageHeight(540);
    System.out.println("--- grabber start ---");
    grabber.start();
    while (total>0){
      Frame frame = grabber.grabImage();
      if (frame != null) {
        File outPut = new File(savePath + System.currentTimeMillis() + ".jpg");
        ImageIO.write(frameToBufferedImage(frame), "jpg", outPut);
        System.out.println("图片已保存:" + outPut.getPath());
        total--;
        Thread.sleep(interval * 1000);
      }
    }
    grabber.stop();
    grabber.release();
    System.out.println("--- grabber end ---");
  }

  /**
   * 创建BufferedImage对象
   */
  public static BufferedImage frameToBufferedImage(Frame frame) {
    Java2DFrameConverter converter = new Java2DFrameConverter();
    BufferedImage bufferedImage = converter.getBufferedImage(frame);
    return bufferedImage;
  }
}

(2)运行结果如下:

附二:对外提供接口服务

(1)下面样例将截图功能封装成一个 API 接口服务,通过 Get 请求方式传入视频流地址后返回截图:
@RestController
public class VideoCaptureController {

  @GetMapping(value = "/capture",produces = MediaType.IMAGE_PNG_VALUE)
  public byte[] capture(@RequestParam("url") String url) {
    try {
      return startCapture(url);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 开始截图
   */
  public byte[] startCapture(String url) throws IOException, InterruptedException{
    FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(url);
    grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重
    //grabber.setImageWidth(960); //设置宽高尺寸(不设置则使用视频流原始宽高)
    //grabber.setImageHeight(540);
    System.out.println("--- grabber start ---");
    grabber.start();
    while (true){
      Frame frame = grabber.grabImage();
      if (frame != null) {
        //获取BufferedImage对象
        BufferedImage bufferedImage = frameToBufferedImage(frame);
        //将获取BufferedImage转成byte[]返回
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", out);
        grabber.stop();
        grabber.release();
        System.out.println("--- grabber end ---");
        return out.toByteArray();
      }
    }
  }

  /**
   * 创建BufferedImage对象
   */
  public BufferedImage frameToBufferedImage(Frame frame) {
    Java2DFrameConverter converter = new Java2DFrameConverter();
    BufferedImage bufferedImage = converter.getBufferedImage(frame);
    return bufferedImage;
  }
}

(2)运行效果如下:
评论

全部评论(0)

回到顶部