glaciall / jtt1078-video-server

基于JT/T 1078标准实现的视频转播服务器
Other
291 stars 137 forks source link

长时间推流后,程序会崩溃 #3

Open zhongren opened 5 years ago

zhongren commented 5 years ago

2019-05-16 09:55:52,414 INFO nioEventLoopGroup-3-2 [cn.org.hentai.jtt1078.server.Jtt1078Handler2] - start streaming to rtmp://10.20.129.54:1935/live/stream/018600000004_1 2019-05-16 09:56:02,409 INFO nioEventLoopGroup-3-3 [cn.org.hentai.jtt1078.server.Jtt1078Handler2] - start streaming to rtmp://10.20.129.54:1935/live/stream/018600000004_2 2019-05-16 09:56:14,484 INFO nioEventLoopGroup-3-4 [cn.org.hentai.jtt1078.server.Jtt1078Handler2] - start streaming to rtmp://10.20.129.54:1935/live/stream/018600000004_3 2019-05-16 09:56:23,488 INFO nioEventLoopGroup-3-5 [cn.org.hentai.jtt1078.server.Jtt1078Handler2] - start streaming to rtmp://10.20.129.54:1935/live/stream/018600000004_4 2019-05-16 10:02:55,193 WARN nioEventLoopGroup-3-2 [io.netty.channel.DefaultChannelPipeline] - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception. java.nio.channels.AsynchronousCloseException at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:205) at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:216) at cn.org.hentai.jtt1078.video.PublisherManager$Publisher.publish(PublisherManager.java:188) at cn.org.hentai.jtt1078.video.PublisherManager.publish(PublisherManager.java:94) at cn.org.hentai.jtt1078.server.Jtt1078Handler2.channelRead0(Jtt1078Handler2.java:77) at cn.org.hentai.jtt1078.server.Jtt1078Handler2.channelRead0(Jtt1078Handler2.java:29) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:297) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:413) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1414) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:945) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:146) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748) 2019-05-16 10:02:55,212 WARN nioEventLoopGroup-3-2 [io.netty.channel.DefaultChannelPipeline] - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception. java.lang.RuntimeException: no such publisher: 1 at cn.org.hentai.jtt1078.video.PublisherManager.publish(PublisherManager.java:80) at cn.org.hentai.jtt1078.server.Jtt1078Handler2.channelRead0(Jtt1078Handler2.java:77) at cn.org.hentai.jtt1078.server.Jtt1078Handler2.channelRead0(Jtt1078Handler2.java:29) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:297) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:413) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1414) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:945) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:146) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748)

长时间推流之后,fileChannel.write(byteBuffer) 推流就异常了

glaciall commented 5 years ago

你所说的长时间推流是有多长时间? 你发来的这一大串日志看得我脑壳疼,我找到了java.lang.RuntimeException: no such publisher: 1这个我自己报出来的错误,你仔细看看日志里面,看看是不是发生了超时而导致了自动关闭呢?如果车载终端5000毫秒以上不发送视频流到服务器端的话,就会自动触发关闭掉的。

zhongren commented 5 years ago

大概4个摄像头 推了7分钟左右 nioEventLoopGroup-3-2 [io.netty.channel.DefaultChannelPipeline] - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception. java.nio.channels.AsynchronousCloseException at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:205) at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:216) at cn.org.hentai.jtt1078.video.PublisherManager$Publisher.publish(PublisherManager.java:188) at cn.org.hentai.jtt1078.video.PublisherManager.publish(PublisherManager.java:94) at cn.org.hentai.jtt1078.server.Jtt1078Handler2.channelRead0(Jtt1078Handler2.java:77) at cn.org.hentai.jtt1078.server.Jtt1078Handler2.channelRead0(Jtt1078Handler2.java:29) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) at

FileChannelImpl.write(FileChannelImpl.java:216)这一行就报错了,后续的no such publisher 我觉得是不是因为exceptionCaught里面只是ctx.close,但是并没有在map里移除publisher

zhongren commented 5 years ago

我看了下,没有数据的话,5秒后 publisher就从map里移除了,但是ctx还没关闭,然后再次收到推流后,从session里获取publishId 这时候就无法推流了, 那是不是需要在5秒断开后,给终端发送停止推流的指令呢

glaciall commented 5 years ago

不,首先exceptionCaught方法只是在当ChannelInBoundHandler处理消息时发生未捕获的异常时的最后一个处理的地方,这个位置没有什么意义。

no such publisher表示的是,通道与fifo文件的对照关系已经不复存在了,现在的问题就是为什么5秒之后会被删掉,按我原来的设计,是只要车载终端一直在推流,这就一直会维持这个关系的,你多多跟踪一下看看,我现在手头上不方便调试。

glaciall commented 5 years ago

PublisherManager里,有一个map维持了一个rtmp地址到fifo文件的关联关系,这个关系将在publisher推流器过期时被删掉,有两个地方你注意一下,分别是PublisherManager类的87行和104行这里。

zhongren commented 5 years ago

public boolean publish(byte[] data) throws Exception { if (process.isAlive() == false) return false; byteBuffer.clear(); byteBuffer.put(data); byteBuffer.flip(); fileChannel.write(byteBuffer); byteBuffer.flip(); this.lastActiveTime = System.currentTimeMillis(); return true; } 好像是把数据写入fifo的这一段 如果数据写入成功,会在最后this.lastActiveTime = System.currentTimeMillis(); 更新时间戳,也就是您在定时器里面用来判断是否超时. 目前就是fileChannel.write(byteBuffer);报错了,导致更新时间戳的这一行代码没有执行到,从而导致publisher从map里被移除了

glaciall commented 5 years ago

嗯,往FIFO管道文件写数据失败了,晚点我跟踪一下FFMPEG的控制台输出,你看到PublisherManager类的149行的那一大片注释掉的东西了吗?你把这里解开,看看ffmpeg发生了什么情况了没有。。。

glaciall commented 5 years ago

我今天测试过一次20多分钟的长时间推流,一直都没有报错,但是有时候也是会有5分钟就报错的情况发生,实际使用时,还是跟当时的网络情况有有关,需要你来制定发起实时音视频传输指令的策略来控制好,比如失败了就另外重新请求让车载终端再次推流等等,因为车辆在移动过程中,4G信号强度处于不断的变化之中,不可控的因素太多,还是做好事后处理比较好。

我这里只是提了一种使用FIFO管道文件处理这种应用程序间配合的一种方案,可以避开对opencv或ffmpeg深度集成的问题。

zhongren commented 5 years ago

好的 谢谢大佬,我去想想重连的方案

glaciall commented 5 years ago

不客气啊,有什么发现了或是可以改进的地方告诉我一声。。。。

glaciall commented 5 years ago

@zhongren 更新一下,解决掉了一个读包的错误。