一、依赖
导入JavaCV和绑定的FFmpeg依赖,不依赖于系统FFmpeg。可根据系统平台选择性导入,以减小打包体积:
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.9</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.0-1.5.9</version>
<classifier>windows-x86_64</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.0-1.5.9</version>
<classifier>linux-x86_64</classifier>
</dependency>
二、功能代码
- 实例化FFmpegFrameGrabber对象,传入视频流。
- 配置读取器参数。
- 启动读取器。
- 抓取一帧。
- 实例化Java2DFrameConverter对象。
- 将抓取到的帧通过Java2DFrameConverter转化为BufferedImage。
- 通过ImageIO.write()方法将BufferedImage保存到本地。
String videoUrl = "videoUrl";
String outputImagePath = "outputImagePath";
// 实例化帧抓取器对象,将文件路径传入
try(FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoUrl)) {
// 配置rtsp流读取协议为tcp
grabber.setOption("rtsp_transport", "tcp");
// 启动读取器
// grabber.start(false);
grabber.startUnsafe(false);
// 抓取一帧
Frame frame = grabber.grabImage();
if (frame != null) {
// 转换为 BufferedImage
try(Java2DFrameConverter converter = new Java2DFrameConverter()){
BufferedImage bufferedImage = converter.convert(frame);
// 保存图片
ImageIO.write(bufferedImage, "png", new File(outputImagePath));
System.out.println("图片保存成功:" + outputImagePath);
}
} else {
System.out.println("未能抓取到视频帧!");
}
} catch (Exception e) {
// e.printStackTrace();
System.out.println("异常:" + e.getMessage());
}
注:
- 启动读取器时使用startUnsafe()方法而不是start()方法,防止阻塞,特别是多线程条件下,一个阻塞会全部阻塞。
- 启动读取器时使用startUnsafe()/start()带false参数,实现不处理音频,加快启动速度。
- 此代码为简洁功能代码,可根据需求扩展读取器配置等其他内容,增强代码健壮性。如:可配合线程池ExecutorService和Future.get()方法实现代码超时重试功能。