2019年的上半年开始做1078的音视频开发工作,并开源了jtt1078-video-server这个项目,在9月份创建了QQ群,认识了很多这个行业的开发人员,服务器端开发的、车载终端开发的,认识到了很多有趣的人,也大大的开拓了我在音视频方面的知识面。
JT/1078协议是用于营运车辆车载终端做音视频传输的一个协议,交通部对于很多车辆是要求强制安装的,并且实时的音视频传输协议必须是JT/1078协议,而这个协议起草得相当的差劲,文档里好几处错误、设计有缺陷、厂家不按套路来,并且在音视频传输的细节里,有很多不明确不详细的地方,对于初次接触音视频开发的人来说,无从下手、完全摸不着头脑是很正常的事,开发进度一拖再拖,领导给的脸色也是越来越差,真是太蛋疼了。。。
闲话不多说,JT/1078协议是对808协议的扩展,就是在它的基础上,增加了几个用于音视频传输控制的指令,以及几个报警信息,所以如果之前就已经有808协议服务器的,直接在它的基础上,增加1078协议的几个指令的传输控制就可以了。
在整个音视频的传输与播放的环节里,是以下几个方面配合一起完成的。
1078指令服务器负责下发9101指令来通知车载终端开始音视频传输,由协议定义的消息体包含以下内容:
起始字节
字段
数据类型
描述及要求
0
流媒体服务器IP地址长度
BYTE
长度n
1
流媒体服务器IP地址
STRING
流媒体服务器IP地址,如1.2.3.4,字节内容就是31 2E 32 2E 33 2E 34
1+n
流媒体服务器监听端口号(TCP)
WORD
如端口号1078,值为04 36
3+n
流媒体服务器监听端口号(UDP)
WORD
如果是TCP协议的,这里可填写为00 00
5+n
逻辑通道号
BYTE
按照JT/T 1078-2016中的表2字义,可见文章末尾的逻辑通道号对照表
6+n
数据类型
BYTE
0:音视频,1:视频,2:双向对讲,3:监听,4:中心广播,5:透传
7+n
码流类型
BYTE
0:主码流,1:子码流
流媒体服务器是我们这个协议中的主体,是完成对音视频传输的数据对接,到转码、封装为新形式音视频,以提供给用户前端进行播放的关键服务器,涉及到了大量的音视频编解码、分布式架构、各种网络协议方面的知识。
在这里,我们主要要完成对RTP消息包的解析,从中分离出音频或视频的数据体,并且完成解码或重装封装的工作,如果可能,还需要提供音视频流的订阅,以供给用户前端来播放。
1078在定义音视频传输消息包时,借鉴了RTP协议,但又不是完全一致,而且里面还有很多不清楚以及有错误的地方,这里是重中之重。协议文档里的定义如下:
起始字节
字段
数据类型
描述及要求
0
帧头标识
DWORD
固定为0x30 0x31 0x63 0x64,ASCII码为01cd
4
V
2 BITS
固定为2
P
1 BIT
固定为0
X
1 BIT
RTP头是否需要扩展位,固定为0
CC
4 BITS
固定为1
5
M
1 BIT
标志位,确定是否完整数据帧的边界,因为数据体的最大长度是950字节,而一个视频I帧通道要远远超过950字节,所以视频的一个帧通常会分包
PT
7 BITS
负载类型,原文档里的这里的参考表是错误的,实际上是参考文档的表12,此文章的附录里也有
6
包序号
WORD
初始为0,每发送一个RTP数据包,序列号加1
8
SIM卡号
BCD[6]
终端设备SIM卡号
14
逻辑通道号
BYTE
按照JT/T 1076-2016中的表2
15
数据类型
4 BITS
0000:数据I祯,0001:视频P帧,0010:视频B帧,0011:音频帧,0100:透传数据
分包处理标记
4 BITS
0000:原子包,不可拆分等,0001:分包处理时的第一个包,0010:分包处理时的最后一个包,0011:分包处理时的中间包
16
时间戳
BYTE[8]
标识此RTP数据包当前祯的相对时间,单位毫秒(ms)。当数据类型为0100时,则没有该字段,RTP协议里规定这个数字是以任意值开始,然后按毫秒的时间间隔递增即可,千万不要认为它是常规的时间戳的定义,目前有碰到个别厂家提供的时间戳有问题,一直不变。
24
Last I Frame Interval
WORD
该祯与上一个关键祯之间的时间间隔,单位毫秒(ms),当数据类型为非视频祯时,则没有该字段
26
Last Frame Interval
WORD
该祯与上一个关键祯之间的时间时间,单位毫秒(ms),当数据类型为非视频祯时,则没有该字段
28
数据体长度
WORD
后续数据体长度,不含此字段
30
数据体
BYTE[n]
音视频数据或透传数据,长度不超过950 byte
我做了一个对于此消息类型的解析工具,见:https://www.hentai.org.cn/format/
RTP协议的定义是有缺陷的,因为实时音视频和历史音视频传输时,使用的RTP消息包格式完全一致,而每个连接通道我们只能够使用消息体里的SIM卡号和逻辑通道号作为标识,导致我们无法正确的区分现在连接到流媒体服务器上来的到底是实时还是回放,所以一般做法是,实时音视频和回放这里,分开两个不同的服务器端口来提供服务。
另外,视频编码一般,或者说几乎所有的终端使用的都是H.264编码,好像有群友碰到过AVS编码的。而音频编码最常用的就是G.711A、G.711U、ADPCMA以及G.726这四种,比较头疼的是,终端经常搞鬼,有时间消息体里传递过来的音频编码与实际的不相符,对于这种情况,最好是在服务器端做配置设置,不以终端的标识为准,以服务器端配置的来。四种常见的音频解码,我提供了acodec音频编解码库项目,大家可以参考一下(目前只支持G711A、G711U、ADPCM的解码)。
还有一点,使用了海思音频芯片的终端(比如锐明的终端),音频数据体通常会带上海思头,它的形式如00 01 XX 00
,XX表示后续字节数的一半,如果碰到符合这个规则的前四个字节,直接去掉就可以了。
在这一步里,我们需要完成对已经读到的音频或视频的解码封装的工作,车载终端传输过来的音频或视频,用户前端的浏览器或APP不一定能够直接播放,通常需要封装为其它形式。最佳的办法是提供RTMP+HTTP-FLV,这样的话,网页端可以使用flv.js进行播放(摆脱对flash的依赖),而APP端或小程序等,可以播放RTMP流媒体。最简单的办法是,使用ffmpeg将视频直接推流到RTMP服务器,这里推荐nginx-http-flv-module这个流媒体插件,ffmpeg完成将视频推送,而身为RTMP服务器的nginx-http-flv-module除了接收RTMP推送,同时还能够将RTMP流转为HTTP-FLV流,同时兼顾两种形态的流媒体。
而音频就比较麻烦了,ffmpeg虽然可以将音频和视频整合推流(参考FFMPEG入门与集成开发指南),但是里面有太多不可控制的因素了,我项目里的multimedia分支就做了这个尝试,但是效果很糟糕,而有的群友就很成功,不推荐这个办法。如果需要音频,建议默认只开启视频,需要音频时,再发送指令开始传输音频再传输到用户前端进行播放。
实时音视频流是可以共享的,也就是说,对于同一辆辆的同一个通道的音视频,是可以有多个用户同时播放观看的,而历史音视频不行,必须是独占的。如果在流媒体服务器上直接提供音视频的话,则需要控制好这一点,而如果使用了比如nginx所提供的RTMP服务器,就不需要另外考虑,流媒体天生就是一对多的。
因为RTP消息包结构只有SIM卡号和通道号可以作为通道标识,而无法区分是实时音视频还是历史音视频,所以通常我们另外开启一个TCP端口监听来为历史回放提供支持。
在官方文档的0x9201指令消息体里,文档里有错误,快进或快退倍数重复了两遍,忽略掉这个小错误,只写一次即可,切记切记,其它的流程里,就与实时音视频一样的处理就可以了,里面有一点要注意的是,历史音视频的传输速度会以终端的最大带宽进行传输数据,比较典型的结果就是,如果车载终端目前已经传输了5分钟的数据量了,而用户前端只播放到30秒,那此时对车载终端下发回放控制指令(如快进、暂停、seek定位等)可能会很久以后才会响应到,最好就是在发送播放控制指令后,清空流媒体的缓冲数据,或是干脆重建流媒体,或是控制服务器端的接收速率,让它能够尽快的响应过来。
双向对讲模式下,车载终端与流媒体建立的连接通道将是一个双向通道,终端将采集上来的音频编码后发送到服务器端,服务器端也可以通过这个连接通道发送音频数据下去,终端将完成播放。
首先,下发的消息包,结构也是按照上面的RTP消息包结构来的,需要注意以下事项:
语音对讲比实时和历史音视频的坑要大得多,一定要注意多测试,并且控制测试的粒度,不要把用户前端的录音到传输到流媒体服务器等整个链路一起来测试,应该直接准备一个PCM数据文件,直接进行分包下发测试,听到终端的声音后再考虑完整的流程应该是怎么样去规划。
协议里要求的历史音视频上传的接收端,必须是一个FTP服务器,在架设FTP服务器时,注意PASV被动模式的端口问题,FTP服务器通常使用21号端口提供指令服务,同时还要提供一个端口范围段,来提供数据交换服务。
协议里的0x9206指令消息体里,文件上传路径是一个关键性的字段,应该把这个字段与用户请求关联起来,建议使用 /{UUID}/ 这样的值(这个路径是相对于FTP根目录的一个路径,终端会通过协议自动创建),当车载终端上传完成后,它还会再次主动上报上传结果的,这个时候我们就可以知道应该去FTP的哪个目录下去读取媒体文件了。这里还要注意一件事,终端上传到 /{UUID}/ 目录下的文件可是千奇百怪的,什么样的命名都有,什么编码的都有,而且通常是好几个文件,建议直接取大小最大的那个文件就好,而上传的视频文件一般有h264裸流和mp4这两种,建议在上传完成后,使用ffmpeg转码统一为mp4后再提供给用户。
如果要求提供上传进度功能,可以参考我的FTP代理服务器项目:ftp-proxy-server
上面建议使用nginx-http-flv-module,它可以支持RTMP的推流,同时可以提供RTMP流媒体、以及HTTP-FLV的支持,在网页上,可以使用flv.js来播放,在移动APP端就可以使用RTMP来播放,相信各位可以很容易找到支持RTMP协议的播放器,这里就不细说了。
chrome浏览器对于同一个域名的并发连接是6路,而HTTP-FLV是基于HTTP协议的长连接,一般不注意的话,很容易误以为流媒体服务器有什么并发上的性能问题,其实这是浏览器的锅,这里建议使用多域名或是多端口号来避开浏览器对单域名的并发数的限速。
本文档写了差不多两天,断断续续的,很多地方也还没有写清楚,还只是把常见的一些问题和简单的流程写了一下,还有很多实现上的细节需要了解的,可以进群交流,群里各种语言的开发者都有。
通道编号
通道类型
监控区域
1
音视频/视频
驾驶员
2
音视频/视频
车辆正前方
3
音视频/视频
车前门
4
音视频/视频
车厢前部
5
音视频/视频
车厢后部
6
音视频/视频
车后门
7
音视频/视频
行李舱
8
音视频/视频
车辆左侧
9
音视频/视频
车辆右侧
10
音视频/视频
车辆正后方
11
音视频/视频
车厢中部
12
音视频/视频
车中门
13
音视频/视频
驾驶席车门
14~32
预留
预留
33
音频
驾驶员
36
音频
车厢前部
37
音频
车厢后部
注意:实际上车辆在安装摄像头的时候,并不会遵照通道号的要求,很多都是乱七八糟的接,线只要接上就行了,所以通道号的对照表没有什么用。另外,最重要的一点,如果要做双向对讲,是需要在消息体内声明逻辑通道号的,这里我建议先按协议要求的试一试,如果不行就从1试到255,因为有家厂家我记得使用的驾驶员音频通道号是99。
编码
名称
备注
0
保留
--
1
G.721
音频
2
G.722
音频
3
G.723
音频
4
G.728
音频
5
G.729
音频
6
G.711A
音频
7
G.711U
音频
8
G.726
音频
9
G.729A
音频
10
DVI4_3
音频
11
DVI4_4
音频
12
DVI4_8K
音频
13
DVI4_16K
音频
14
LPC
音频
15
S16BE_STEREO
音频
16
S16BE_MONO
音频
17
MPEGAUDIO
音频
18
LPCM
音频
19
AAC
音频
20
WMA9STD
音频
21
HEAAC
音频
22
PCM_VOICE
音频
23
PCM_AUDIO
音频
24
AACLC
音频
25
MP3
音频
26
ADPCMA
音频
27
MP4AUDIO
音频
28
AMR
音频
29~90
保留
音频
91
透传
系统
92~97
保留
视频
98
H.264
视频
99
H.265
视频
100
AVS
视频
101
SVAC
视频
102~110
保留
111~127
自定义
原网址: 访问
创建于: 2020-12-17 16:59:54
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论