javacv FFmpegFrameGrabber 阻塞问题解决方法
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.7</version>
</dependency>
修改org.bytedeco.javacv.FFmpegFrameGrabber.java源码
//1、在createDefault方法后添加 以下代码
/**
* 读流超时时间 : 20秒
*/
private static final int FRAME_READ_TIMEOUT = 20 * 1000;
// 增加监听
private final AtomicLong lastFrameTime = new AtomicLong(System.currentTimeMillis());
private boolean interrupt_grab = false;
public boolean isInterrupt_grab() {
return interrupt_grab;
}
private final org.bytedeco.ffmpeg.avformat.AVIOInterruptCB.Callback_Pointer cp = new org.bytedeco.ffmpeg.avformat.AVIOInterruptCB.Callback_Pointer() {
@Override
public int call(Pointer pointer) {
// 0:continue, 1:exit
if (lastFrameTime.get() + FRAME_READ_TIMEOUT < System.currentTimeMillis()) {
interrupt_grab = true;
try {
// 读流时使用了Process p = Runtime.getRuntime().exec() ; 执行了ffmpeg命令
// p.waitFor(); 该方法使线程阻塞, 使用interrupt()取消/退出线程
Thread.currentThread().interrupt();
} catch (java.lang.Exception e) {
log.error("Thread interrupt", e);
}
return 1;
}
return 0;
}
};
//2、在startUnsafe()方法中
//if ((ret = avformat_open_input(oc, filename, f, options)) < 0) 代码前 添加
// 回调
lastFrameTime.set(System.currentTimeMillis());
oc = avformat_alloc_context();
org.bytedeco.ffmpeg.avformat.AVIOInterruptCB cb = new org.bytedeco.ffmpeg.avformat.AVIOInterruptCB();
cb.callback(cp);
oc.interrupt_callback(cb);
//3、在grabFrame方法中if (oc == null || oc.isNull()) 判断结束后添加
// 回调
lastFrameTime.set(System.currentTimeMillis());
// 4 在使用FFmpegFrameGrabber读取帧时, isInterrupt_grab()进行退出循环
while (true) {
frame = grabber.grab();
if (grabber.isInterrupt_grab()) {
log.info("grabber Interrupt_read");
break;
}
if (frame.image != null) {
log.info("处理逻辑......");
}
}