SpringBoot - 使用javaCV截取RTMP、RTSP视频流图片
作者:hangge | 2024-05-09 08:20
有时我们需要在后台自动拉取 rtsp、rtmp 等视频流并进行截图,这个使用 javaCV 库即可实现。javaCV 之所以叫 javaCV 就是因为 openCV 而得名,不过 javaCV 的功能远远大于 openCV,openCV 只能用于处理图像,而 javacv 不仅包含 openCV 全套 api,还支持 ffmpeg 音视频编解码,tensflow、caffe 等深度学习库,tessrac ocr 等字符识别,矩阵计算库。下面我通过样例演示如何使用 javaCV。
(2)运行结构如下,可以看到视频图片已经成功保存到本地:
(2)运行结果如下:
(2)运行效果如下:
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)