近期项目中需要抽取rtsp流图像进行图像处理,目前网上可以找到的教程中绝大部分使用的是opencv或者javacv,我一开始是采用的javacv方案,但是javacv不支持h265格式,而且对于长时间抽流的逻辑来说,监控抽流状态也比较麻烦,因为网络波动等一些问题导致的抽流中断,也不是很好监控,于是改用了vlcj库重构了抽帧逻辑。
官网:http://capricasoftware.co.uk/
vlcj是libvlc的java实现,著名的开源播放器VLC就是基于libvlc实现的。VLC是个特别强悍的播放器,尤其是播放各种协议的流媒体,几乎没有vlc不支持的格式,而且稳定性也特别好。
相对于传统的opencv和javacv方案,vlcj主要有如下几个优点:
先说一下我的业务需求:同时抽取多个海康摄像头的rtsp流,每隔一段时间提取其中一帧,然后进行图像处理。最主要的一点是,仅获取图像数据用来计算,不做前端展示。 下边的示例代码是以这个业务需求仅为基础编写的。
需要先安装libvlc环境, 具体方法可以百度。还有个比较省事的做法, 下载VLC播放器, 安装的时候勾选全部组件即可(安装位置不限,无需配置环境变量)。
添加maven依赖,vlcj有3.x和4.x两个版本,两个版本的api相差很大,这里使用的是vlcj3
<dependency>
<groupId>uk.co.caprica</groupId>
<artifactId>vlcj</artifactId>
<version>3.12.1</version>
</dependency>
示例代码
public class VLCJTest {
private BufferedImage image;
private MediaPlayerFactory mediaPlayerFactory
private HeadlessMediaPlayer mediaPlayer
//--live-caching 0设置播放器缓存为0,保证获取到的都是实时画面,第二个参数可以不加,暂时没看出啥效果
static String options[] = new String[]{"--live-caching 0", "--avcodec-hr=vaapi_drm"};
//这两个参数可加可不加,如果想要通过窗口展示视频画面,就不加, 如果不想显示视频画面,就加上
static String[] VLC_ARGS = { "--vout", "dummy" };
static String videoSources = "rtsp://admin:123123@192.168.14.175:554/h265/ch0/main/av_stream";
public static void main(String[] args) {
new NativeDiscovery().discover(); //自动搜索libvlc路径并初始化,这行代码一定要加,且libvlc要已经安装,否则会报错
// 创建播放器工厂
mediaPlayerFactory = new MediaPlayerFactory(VLC_ARGS); //这样写的话则不展示视频图像, 要想展示图像的话则直接new MediaPlayerFactory();
// 创建一个HeadlessMediaPlayer ,在不需要展示视频画面的情况下,使用HeadlessMediaPlayer 是最合适的(尤其是在服务器环境下)
mediaPlayer = mediaPlayerFactory.newHeadlessMediaPlayer();
String url = videoSources;
mediaPlayer.playMedia(url, options); //开始播放视频,这里传入的是rtsp连接, 传入其他格式的链接也是可以的,网络链接、本地路径都行
//开始播放之后,可以另起一个线程来获取视频帧 (这里使用的hutool框架来开启线程)
ThreadUtil.execAsync(()->{
while (true){
if (mediaPlayer.isPlaying()){
image = mediaPlayer.getSnapshot();
// 具体计算逻辑省略
}
}
});
}
其中有几点需要注意的地方(敲黑板):