android播放rtsp视频流app, demo app .使用live555+MediaCodec

用libvlc提供的库播放rtsp,总是延迟比较大(局域网的情况下,存在明显的画面延时),netcaching设置为0还是存在延迟,但是网络延迟已经比较低了,没办法,自己写了一个APP,现在只测试了接受一个视频流的rtp流,没有音频。延迟较低,总的播放延迟基本在网络部分。原理:

1.0 解码播放端:使用android 的MediaCodec 播放h264流,先行使用h264裸流文件模拟网络流进行了测试,可以达到给一帧就解码播放一帧,1080p的视频 60 帧(实际视频文件是30fps,这里可以倍速)每秒的输入速度没有问题,所以安照网络视频流接受的帧率,来一帧解一帧完全没有问题,延迟应该就只在接受完一帧网络流,接受端的延迟。

2.0 接受网络视频流,从vlc的源码来看,也是使用live555来拉流,但是vlc来驱动live555拉流的线程(live555是单线程,需要外部驱动),1调用部分是有wait的,拉取到流数据之后送到解码器解码,还会有一个缓冲区,2解码器从缓冲区取数据进行解码的线程又有一个wait,就是sleep. 待解码完把数据再放到 显示缓冲区,3再有显示线程来获取数据的时候还是有一个wait. 所以总的流程下来,有多处缓冲和wait等待。  还有一个问题是,vlc从live555接受过来的视频帧,会对时间戳进行一个简要的调整,以防止出现网络视频流接受端失序,接受到的帧顺序和解码的顺序不一致,所以对连续的几帧会有一个时间戳的矫正,即时间戳可能会被改动。所以解码线程解码的时候就会根据这个时间戳来wait休眠。显示的时候同样也需要用到这个时间戳来休眠《vlc读取rtsp流-源码分析---时间戳dts的计算 》这里自己写的app,就不理会这个时间戳,直接网络受到一帧解一帧,估有可能在使用udp传输的时候,受到的帧失序,导致解码顺序不正确,出现花屏。(live555内部还是有一个缓冲区的,默认100ms)

主要的实现:

git下载 https://github.com/Canok7/RTSP_PLAYER_can

说明:1.0 只编译了arm64 的live555库,live555相关的库从vlc源码编译中提取出来的,也可以直接使用live555源码文件使用ndk自己编译 

2.0 MediaCode 播放h264部分,从网上找的,工程中有自己添加的从h264文件分离出h264NAL 帧的代码,分别有java 实现的DataProVide_file 类,和c++版本,在jni目录下的 geth264Frame.cpp ,可以测试MedaiCode

3.0 live555拉流部分,在jni目录下额live555.cpp,从live555源码里面的 testRTSPClient.cpp 修改而来,改这个文件,有几处要注意的地方:3.1 在shutdownStream()函数里面,把exit(exit_code) 这一行去掉,改为 eventLoopWatchVariable = 1。 不改动的话会出现如果rtsp 流打不开情况下,app闪退。 3.2 在afterGettingFrame() 函数里面取走你要的 h264流数据。3.3 去掉函数continueAfterPLAY()里面的定时器,这个定时器会自己关掉流。3.3 源文件有一个 #define REQUEST_STREAMING_OVER_TCP False  宏定义,要求服务端使用tcp传输的话,把这个宏定义定义为True, 这样的话如果你的rtsp服务器支持用tcp传输,就会优先用tcp来传输rtp流了,如果服务器本身不支持使用tcp传输,还是会重新用udp来传输的,这里提醒下 vlc 目前是没有支持用tcp来推送rtp流的。所以用vlc来推流测试,改为True,也不顶用。

testRTSPClient.cpp分析 《live555:testRTSPClient.cpp 源码分析-读取rtsp流demo》

4.0 从live555拉流出来,为了保证其及时性,这里启了一个线程专门负责拉流,将数据保存到一个缓冲队列,自己实现的一个环形缓冲队列,入数据不会阻塞,会覆盖最老的数据,取数据有两种方式,阻塞式获取或者非阻塞式获取,播放rtsp流这里解码器线程用阻塞式获取数据,只要有数据立马取出进行解码播放。

5.0 可能会出现的问题:

5.1 花屏 。无非是丢帧,可以通过在各个环节取流来逐个排查。可能是网络丢帧(改用rtp-over-tcp吧),这种情况可以通过wireshark或者tcpdump在客户端抓网络包,从抓的包中提取h264裸流,也可能是接受端live555处理不过来丢帧(可以通过增加live555接受端socket缓冲区的办法缓解)。可以将live555获取到的流数据保存成h264流————在本demo中 从live555库拉流出来的数据,存放到native层的一个 queue缓冲队列,app java 层通过jni调用从队列中取数据,可以将 VideoDecoder.java 中的 bSave2file 设为true,程序会把live555拉取的码流数据存储到/storage/emulated/0/dest.h264  。 再或者,就是mediacode解码输入端处理不正确,丢数据。

5.2 卡顿不流畅:这个情况一般在rtp-over-tcp 的情况下出现,ip网络层丢帧,tcp传输层会重发,这样如果一旦ip层丢帧,就会使得这一个数据包重发出现延时,播放来看就会发现这个画面卡主。 

发布了96 篇原创文章 · 获赞 27 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u012459903/article/details/101215123
今日推荐