eb端是无法直接播放rtsp流的,目前常用的解决方案是如jsmpeg、flv.js等。这些方案都是要推送流到服务端,之后才能在web上播放视频,相对比较麻烦。我采用websocket结合mse的方式,实现了一个websocket网关,及其对应的js播放器,在这里做下说明,具体代码参考github上我的源码。
这套方案的原理是,ws网关在拉到rtsp流后,取得mime,将其发送给web端,然后将rtsp流转为fmp4格式,以二进制数据格式发给web端;web端用其初始化mse,然后将websocket收到的二进制数据扔给mse,实现视频的播放。
ws网关有两个关键的问题需要解决,一是封装成fmp4后,输出要到内存而不是文件,二是要能取得mime。如果以网上以回调函数作为ffmpeg输出的例子来写,会发现创建失败。mime对应的是编码类型,需要解析流才能得到,具体怎么解决这两个问题,看看下面的说明。
创建输出的AVFormatContext的代码:
这里需要注意的是pb不仅write_flag要设置成1,seekable也要设置成1,seekable这个很容易就忽略了,然而这个如果不是1,那么创建会失败。ffmpeg写数据输出到内存部分,参考avio_alloc_context的回调函数用法。
获取mime的方法:
mime可以通过spspps取得,ffmpeg在创建AVStream后,264的spspps可以从codecpar->extradata取得,在extradata中跳过264的分隔符后,接下来的第2、3、4个字节就可以拼出264的mime。
mime的音频部分可以参考https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio,以"mp4a.40.2"举例,mp4a.40表示音频解码器为aac,.2表示AAC LC,对比ffmpeg的定义可以发现,这个值就是codecpar的profile加1.
另外说明一下movflags,fmp4需要设置成frag_keyframe+empty_moov,这样就是fmp4,我设置的值是frag_keyframe+empty_moov+omit_tfhd_offset+faststart+separate_moof+disable_chpl+default_base_moof+dash,其中omit_tfhd_offset这个设置是针对chrome浏览器的,如果不设置的该项,chrome上是会播放失败的,faststart是为了将moov移动到mdat前面,separate_moof如果不加上,chrome处理音频时会有问题,尚未找出是视频源问题还是共性问题。
js播放器这边很简单,需要说明一下的是收到ws数据后的处理
字符串数据这里只用了很简单的定义,如果ws网关打开rtsp失败,那么返回的是“fail”,如果返回成功,则是“open:mime”,通过分隔符将mime取出,就可以初始化mime了;如果是二进制数据,则直接放到队列中。js代码不熟,有需要的各位自己按需求优化。
这套代码对rtsp源有格式要求,必须是h264+aac或纯h264的rtsp数据,因为mse对能播放的fmp4有要求,代码中并未对音视频进行重编码。另外代码中是使用rtp over tcp来传输的,使用udp模式请修改代码。最后,本方案达到的延时极低,但在chrome和firefox上对比,firefox的延时略大一些,估计各个浏览器的缓存策略造成了差异。
rtsp流转为fmp4并由WebSocket网关转发,及对应js播放器
原文:https://www.cnblogs.com/lidabo/p/14436726.html