JavaCV中FFmpegFrameGrabber调用start()方法时出现阻塞的解决办法

Nerissa ·
更新时间:2024-11-10
· 748 次阅读

JvaCV中FFmpegFrameGrabber调用start方法阻塞的解决办法问题描述解决方法问题11.avformat_open_input():2.avformat_find_stream_info():问题2

项目码云(Gitee)地址:https://gitee.com/banmajio/RTSPtoRTMP
项目github地址:https://github.com/banmajio/RTSPtoRTMP
个人博客:banmajio’s blog

javacv使用ffmpeg将rtsp转rtmp直播流播放的问题解决与优化系列文章:
FFmpeg转封装rtsp到rtmp(无需转码,低资源消耗)
JavaCV中FFmpegFrameGrabber调用start()方法时出现阻塞的解决办法
JavaCV使用FFmpeg进行rtsp转rtmp直播流画面延时的优化方法
JavaCV1.5.3版本FFmpegFrameGrabber初始化的时候加载时间长的解决方法
av_write_frame() error -22 while writing video packet解决方法

问题描述

目前出现阻塞的情况有如下两种:
1.拉历史流的时候,会发生阻塞,grabber.start()阻塞无法继续执行。
2.如果rtsp指令的ip乱输(或者无法建立连接),start()也会发生阻塞。

解决方法 问题1

可以通过设置超时时间,如果拉不到流,触发超时时间,自动断开TCP连接。

// 设置采集器构造超时时间(单位微秒,1秒=1000000微秒) grabber.setOption("stimeout", "2000000");

上述方法貌似没多大作用,依然会被阻塞…

查看源码发现会发生阻塞的函数有两个:

1.avformat_open_input():

打开流通道,探测一些视频格式等信息,对AVFormatContext结构体初始化。
对于这个函数阻塞的优化方法:将下面函数的seekCallback 设置为null,禁止javacv查找。

avio = avio_alloc_context(new BytePointer(av_malloc(4096)), 4096, 0, oc, readCallback, null, maximumSize > 0 ? seekCallback : null); 2.avformat_find_stream_info():

探测流信息(宽高码率等信息)
这个函数存在执行时间较长或者阻塞的问题,可以通过以下属性设置,来减小函数执行的时间。probesize属性限制探测时读取的最大数据量。max_analyze_duration属性限制info函数执行的时长,AV_TIME_BASE是单位秒。但是对于阻塞的问题好像并不能有效的解决,只是可以缩短函数的执行时间:

// 限制avformat_find_stream_info接口内部读取的最大数据量 oc.probesize(5120); // 设置avformat_find_stream_info这个函数的持续时长,超过这个时间不结束也会结束 oc.max_analyze_duration(5 * AV_TIME_BASE); // 将avformat_find_stream_info内部读取的数据包不放入AVFormatContext的缓冲区packet_buffer中 oc.flags(AVFormatContext.AVFMT_FLAG_NOBUFFER);

3.使用inputstream进行推流时,最新版本的javacv(1.5.3),在grabber new的时候有一行注释:

/** * Calls {@code FFmpegFrameGrabber(inputStream, Integer.MAX_VALUE - 8)} so that * the whole input stream is seekable. */ public FFmpegFrameGrabber(InputStream inputStream) { this(inputStream, Integer.MAX_VALUE - 8); } /** Set maximumSize to 0 to disable seek and minimize startup time. */ //将maximumSize设置为0以禁用查找并最小化启动时间 public FFmpegFrameGrabber(InputStream inputStream, int maximumSize) { this.inputStream = inputStream; this.closeInputStream = true; this.pixelFormat = AV_PIX_FMT_NONE; this.sampleFormat = AV_SAMPLE_FMT_NONE; this.maximumSize = maximumSize; }

将maximumSize设置为0以禁用查找并最小化启动时间;也就是grabber = new FFmpegFrameGrabber(inputStream,0);效果等同于上述序号1的设置,不修改源码来禁用avio_alloc_context()函数的seekCallback

问题2

上述设置超时时间的方法对于拉流地址(rtsp指令中的ip)输入错误时并不生效,依旧会阻塞,查看源码奈何才疏学浅不知道如何解决。变向通过检测是否能建立TCP连接,来判定是否可以正常推拉流。

如下代码:如果可以建立连接,则继续执行;否则释放资源,return null;

// 解决ip输入错误时,grabber.start();出现阻塞无法释放grabber而导致后续推流无法进行; Socket rtspSocket = new Socket(); Socket rtmpSocket = new Socket(); // 建立TCP Scoket连接,超时时间1s,如果成功继续执行,否则return try { rtspSocket.connect(new InetSocketAddress(cameraPojo.getIp(), 554), 1000); } catch (IOException e) { grabber.stop(); grabber.close(); rtspSocket.close(); System.err.println("与拉流地址建立连接失败..."); return null; } try { rtmpSocket.connect(new InetSocketAddress(IpUtil.IpConvert(config.getPush_ip()), Integer.parseInt(config.getPush_port())), 1000); } catch (IOException e) { grabber.stop(); grabber.close(); rtspSocket.close(); System.err.println("与推流地址建立连接失败..."); return null; }

如有错误或者更好的解决办法,请指正!!!

斑马jio 原创文章 23获赞 11访问量 3万+ 关注 私信 展开阅读全文
作者:斑马jio



start 方法

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章