简介:首先功能基于gitee上的开源项目封装,感谢开源作者。
车载视频点播大概流程:建立通讯连接-->向车载视频终端发送指令-->流媒体拉流播放
车载视频终端:卡车驾驶室里像电视机顶盒一样的东西,终端是内置sim卡的是有流量的,可以实时通讯,当然也可以发送数据出去
文章只介绍我个人最近如何开发的车载视频点播功能,如何从零开始向车载视频终端发送9101音视频实时传输指令,使其往我们指定的地址推送音视频流数据,从而我们能够拉流播放视频。各位大佬仅作参考。
一、准备工作
1、gitee下载808项目,地址:(下文中简称808服务)中国交通标准808协议解析二次开发包: 中国交通标准808协议解析二次开发包
2、交通运输部官网上下载JTT808协议文档以及JTT1078文档(自行搜索)
3、创建一个自己的业务项目,这里我们创建的是springboot项目(下文中简称业务服务)
3、搭建流媒体服务,文章最后会推荐一个开源的服务,可先忽略
二、后端开发
1、将下载的808服务最小化并内置到业务服务(具体步骤不赘述)相当于起了两个服务,业务上也方便使用808服务里面的方法
2、与车载视频终端建立连接,通知终端厂商让他们建立连接,告诉他们你的808服务的ip和端口以及你需要建立连接的车辆就行了(注意公网权限问题,需要我们开通外网访问权限他们才能连上),当然也可以通过webSocket建立连接,我没尝试就不说了
3、业务服务中封装指令消息并发送指令,以下是代码:
import java.nio.ByteBuffer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sn.core.dto.SingleResult;
import com.sn.core.exception.PreconditionCheckFailedException;
import com.zhoyq.server.jt808.starter.core.SessionManagement;
import com.zhoyq.server.jt808.starter.helper.ResHelper;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@RestController
@RequestMapping("/**/xxx")
public class VehicleVideoRealTimeController {
private SessionManagement session;
private @Autowired ResHelper resHelper;
public VehicleVideoRealTimeController(SessionManagement session) {
this.session = session;
}
public SingleResult<String> send9101(String sim, Integer chanel) {
if(StringUtils.isBlank(sim) || chanel == null){
throw new PreconditionCheckFailedException("请选择车辆以及视频通道号!");
}
if(!session.contains(sim)){
throw new PreconditionCheckFailedException("该车辆视频通讯连接失效!");
}
SingleResult<String> result = new SingleResult<String>();
// 根据1078协议封装指令,command不包含起始符、校验码、结束符以及转义的数据 因为发送之前808服务会自动添加这些
byte[] startCommand = build9101CommandParams(sim, chanel);
session.write(sim, startCommand);
result.setSuccess(true);
return result;
}
public byte[] build9101CommandParams(String phoneNum, Integer chanel) {
// sim卡号
byte[] phoneNumArray = this.genPhoneByteArray(phoneNum);
// 指令编号
byte[] messageId = new byte[]{(byte)0x91,(byte) 0x01};
// 消息体
byte[] messageBody = this.gen9101MessageBody(chanel);
return this.resHelper.warp(messageId, phoneNumArray, messageBody);
}
private byte[] genPhoneByteArray(String phoneNum) {
int numBytes = phoneNum.length() / 2;
byte[] phoneNumBytes = new byte[numBytes];
for (int i = 0; i < phoneNum.length(); i += 2) {
int num = Integer.parseInt(phoneNum.substring(i, i + 2));
// 注意:这里我们直接转换,但请记住Java的byte是有+-符号的
phoneNumBytes[i / 2] = (byte) num;
}
return phoneNumBytes;
}
private byte[] gen9101MessageBody(int chanel) {
String IP = "127.0.0.1";// 流媒体服务id
int port = 1935;// 流媒体服务TCP端口
ByteBuffer buffer = ByteBuffer.allocate(8+IP.length()); // 需要计算得出,消息一共多少个字节
// ======================消息体开始======================================
// ip长度 1字节
buffer.put((byte)IP.length());
// ip
buffer.put(IP.getBytes());
// TCP端口 2字节
buffer.putShort((short)port);
// UDP端口 2字节(UDP协议传输才需要,如果是TCP协议这里随便,0x00也行)
buffer.putShort((short)port);
// 逻辑通道号 1字节(结合车辆实际情况,一般车辆上也就4路监控)
buffer.put((byte)chanel);
// 数据类型 1字节(0=音视频、1=仅视频...参考1078协议文档)
buffer.put((byte)1);
// 码流类型 1字节(0=主码流 清晰度高,1=子码流 清晰度低)
buffer.put((byte)1);
// ======================消息体结束======================================
return buffer.array();
}
}
注意控制台输出信息,指令发送成功后,终端会响应对应的指令(0001还是0002忘记了)
三、流媒体服务
公司有运维或开发大佬,完全可以基于ffmpeg等开源播放器搭建一个自己的流媒体服务去拉流控制播放等...,这里推荐一个开源的服务,拿来就用的,也可以用作测试音视频能否播放
jtt1078-video-server: 基于JT/T 1078标准实现的视频转播服务器
1、下载后启动服务,发送9101指令时将1078服务的ip和tcp协议端口作为参数即可,1078服务提供了测试页面:http://127.0.0.1:3333/test/multimedia#018666666666-1
2、点击Play Video按钮等个几秒就可以播放了
注:018666666666-1为对应的sim卡号-通道号
1078服务同时支持往一路rtmp协议服务上推流(RTMPPublisher.java),可以用作支持rtmp协议地址拉流播放的播放器使用,但是我自测会造成卡顿,不建议