<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.5</version>
</dependency>
由于整个依赖较大(约900M),以下为实际需要的依赖(不同的操作系统需要根据自己的操作系统进行适配),以下xml配置了properties及dependencies两个节点。
bytecode-sys配置根据运行系统可以自行变更为,以下部分系统值:
系统 | 值 |
windows64 | windows-x86_64 |
windows32 | windows-x86 |
arm64 | linux-arm64 |
x86_64 | linux-x86_64 |
mac | macosx-x86_64 |
<properties>
<bytecode-sys>linux-x86_64</bytecode-sys>
</properties>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>4.3.2-1.5.5</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<classifier>${bytecode-sys}</classifier>
<version>4.3.2-1.5.5</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.5</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.5</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<classifier>${bytecode-sys}</classifier>
<version>1.5.5</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--endregion-->
</dependencies>
FFmpegFrameGrabber通过grab方法可以获取视频信息,当frame不为空则正常;
但是该方法会导致阻塞,因此此处通过Future的get方法,设置一个超时时间,超时后返回false。
import com.hz.utils.CustomThreadPool;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.junit.jupiter.api.Test;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class RtmpCheckTest {
@Test
public void test01() {
try (CustomThreadPool pool = CustomThreadPool.initPool(1, 1, 1, "ceshi");) {
Future<Boolean> future = pool.submit(() -> {
String rtmpUrl = "rtmp://yourRtmpServer:1935/live/test";
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtmpUrl);
try {
grabber.start();
Frame frame = grabber.grab();
boolean status = frame != null;
return status;
} catch (Exception e) {
return false;
} finally {
grabber.stop();
}
});
Boolean status = false;
try {
status = future.get(10, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("视频状态:" + status);
}
}
}
package com.hz.utils;
import java.io.Closeable;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description:
* @author: pp_lan
* @date: 2022/3/15
*/
public class CustomThreadPool implements Closeable {
private ThreadPoolExecutor pool;
private AtomicInteger count = new AtomicInteger();
private CustomThreadPool(int core, int max, int queueSize, String threadName) {
this.pool = new ThreadPoolExecutor(core, max, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(queueSize),
r -> new Thread(r, threadName + count.getAndIncrement()));
}
public ThreadPoolExecutor getPool() {
return pool;
}
/**
* 获取对象
* @param core
* @param max
* @param queueSize
* @param threadName
* @return
*/
public static CustomThreadPool initPool(int core, int max, int queueSize, String threadName) {
return new CustomThreadPool(core, max, queueSize, threadName);
}
/**
* callable批量任务
* @param tasks
* @param <T>
* @return
*/
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
try {
List<Future<T>> futures = this.pool.invokeAll(tasks);
return futures;
} catch (InterruptedException e) {
throw new RuntimeException("线程被中断", e);
}
}
/**
* callable单个任务
* @param task
* @param <T>
* @return
*/
public <T> Future<T> submit(Callable<T> task) {
return this.pool.submit(task);
}
/**
* runnable任务
* @param runnable
*/
public void execute(Runnable runnable) {
this.pool.execute(runnable);
}
/**
* runnable任务
* @param runnable
*/
public Future<?> submit(Runnable runnable) {
return this.pool.submit(runnable);
}
/**
* 线程池关闭,建议使用try-resource进行自动关闭,不要手动执行
*/
public void shutdown() {
this.pool.shutdown();
try {
if (!this.pool.awaitTermination(1, TimeUnit.MINUTES)) {
this.pool.shutdownNow();
if (!this.pool.awaitTermination(1, TimeUnit.MINUTES)) {
throw new RuntimeException("线程池关闭失败");
}
}
} catch (InterruptedException e) {
throw new RuntimeException("线程池关闭失败", e);
}
}
@Override
public void close() {
this.shutdown();
}
}