FAQ about TJAI GasDetector

探测器常见问题解答

气体探测器(布控球)的常见问题, 主要是接入商和平台提供商的疑问解答。咨询技术支持前可以先看一下。


主界面上的实时浓度数据为什么不显示了?

我们的最新系列布控球采用分体设计:气体传感器部分安装在手持式设备里,方便现场工人随身携带着进入作业现场。而数据接收、传输、视频录像等功能放在球机内,用于跟外部平台通讯。在只有球机开机,手持设备关闭的情况下球机上是没有数据显示的。

所以球机主界面没数据时可以先看手持设备是否开机,如果开机了检查一下手持设备跟球机距离是否过远,并且确认手持设备跟球机是否是正确的配对,不要拿错。


设备连不上网了?

球机设备采用wifi和蜂窝数据连入网络。发现设备无法联网的情况可以先确认联网方式:

如果是wifi连接可以检查一下信号强度和无线路由器本身的网络通讯是否顺畅。可以尝试关掉wifi以蜂窝数据(4G/5G)联网来排查问题;

如果是用的4G/5G联网,可以检查一下设备自带的物联网卡是否已经完成实名认证,并且没有欠费停机的情况。同样也要注意周围是否存在信号屏蔽/基站过远等情况。


怎么才能远程查看实时视频?

本设备采用rtsp推流的方式将实施视频流推送到服务端。设备本身不提供rtsp服务端,需要平台方自行开发或者部署rtsp服务器端,并且将部署好的服务告知我们设备提供方,我们进行相应设置。如果服务已经正确部署并且调试畅通,那么客户就可以访问部署好的服务来查看远程视频。

实施视频和录像的具体部署方案可以参考: [视频服务部署]


怎么把实时气体数据发送/接入到远程平台?

与实施视频类似,实施数据同样需要平台商或服务提供商自行搭建 HTTP Restful API 接口用于接收来自球机的实时视频数据。接口搭建好后告知我们设备提供方,在配置并测试无误后,实时数据将以10s一次的频率发送给接口。(当然要在网络通畅的情况下)

接口搭建的文档可以参考: [探测器数据外发结构概述]


为什么观看实时RTSP视频流会随着时间延迟越来越高?

在读取RTSP流时,客户端可以选择以pipeline或者newest两种策略进行读取播放。前者策略会尽量保证画面的连续性,后者专注于画面的实时性。 如果选择了pipeline策略来读取实施视频流,由于网络延迟的客观存在,在遇到画面帧数据没有及时传输到播放客户端的情况时,客户端会冻结当前帧,并且在下一帧传输完毕后解冻。这种策略保证了总体的画面连续,不会出现一个人前一秒还在A位置后一秒突然跳到B位置。但是在长时间的网络质量不佳的情况下,当前画面跟实际画面的时差会越来越大。

如果选择了newest策略,遇到同样没及时收到下一帧的情况时,会在帧传输完毕后直接跳到最新一帧来播放。这样可以最大限度保证画面的实时性,但是也会出现「丢帧」的情况。

两种情况各有利弊需要平台方在客户端设置中做出取舍。如果不想画面延迟越来越大,可以选用newest策略。


现代浏览器(Firefox/Chrome/Safari)不支持直接在<video>标签中插入rtsp地址怎么办?

推荐几种解决方案:

WebRTC方案

在服务器端部署网站,调用浏览器端的webrtc接口。服务器端从本地的rtsp端口拉流。然后用户方跟服务器端连接后即可在服务器端查看实施画面。开源方案参考 webrtc-streamer

HLS方案

在服务器端部署rtsp转hls的服务。hls地址可以直接插入<video>标签。某些rtsp服务自带该转换功能,如:rtsp-simple-server

ffmpeg.wasm方案

调用ffmpeg.wasm库,直接在浏览器前端将rtsp流转换成flv或rtp流进行播放。参考文档:ffmpeg.wasm


怎么获取录像?

录像是存在球机设备的存储卡中,并且在网络通畅的情况下与远程云存储进行同步。如果需要播放或下载录像,只需要直接获得云存储中的录像名称和地址直接下载即可。录像名称和地址的获取方式在 [视频服务部署] 的第二部分有详细阐述。


录像片段一段只有30秒,我想要长时间连续的一整段视频该怎么做?

由于设备性能的局限,目前设备中的录像只能以30s一个片段的形式存储。如果客户确有需求要长时间的完整录像,建议平台方可以部署服务,根据用户选择的时间段获取设备在该时间段内的所有录像片段的名称和地址,并将合并工作交给服务器或客户浏览器进行。 前者使用普通的ffmpeg命令或者ffmpeg库,后者在浏览器脚本中使用ffmpeg.wasm库。 这里提供两个方案的代码片段供参考。

服务器端方案

在平台方的服务器中编写并开启一个Restful API服务,监听来自客户端的请求。收到请求后,根据请求负载中的时间片段和设备,查询并提取出时间范围内的视频片段文件名, 将所有文件名按时间顺序写入一个clips2concat.txt文本文件。

1
2
3
4
5
# clips2concat.txt
file /path/to/records/{devicename}/{clipname1}.avi
file /path/to/records/{devicename}/{clipname2}.avi
file /path/to/records/{devicename}/{clipname3}.avi
...

然后执行以下系统命令开启合并进程:

1
ffmpeg -f concat -safe 0 -i clips2concat.txt -c copy {timestart-timeend}.avi

客户端方案

编写前端页面文件和脚本。(此处以React框架为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// example of Reactjs
export default function ClipDownload() {
const [videoSrc, setVideoSrc] = useState();
const handleConcat = async () => {
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });

const transcode = async ({ target: { recLists } }) => {
const message = document.getElementById("message");
message.innerHTML = "Loading ffmpeg-core.js";
await ffmpeg.load();
message.innerHTML = "Start Concating";
const inputPaths = [];
for (const rec of recList) {
const resp = await fetch(`http://${host}:${port}/records/tj06/${rec}.avi`);
const clip = await resp.arraybuffer();
const name = `${rec}.avi`;
ffmpeg.FS('writeFile', name, new Uint8Array(clip, 0, clip.byteLength));
inputPaths.push(`file ${name}`);
}
ffmpeg.FS('writeFile', 'concat_list.txt', inputPaths.join('\n'));
await ffmpeg.run('-f', 'concat', '-safe', '0', '-i', 'concat_list.txt', 'output.mp4');
message.innerHTML = "Complete Concating";
const data = ffmpeg.FS('readFile', 'output.mp4');
setVideoSrc(URL.createObjectURL(
new Blob([data.buffer], {
type: "video/mp4"
})
))
};
};
return (
<>
<Button onClick={handleConcat}>Concatenate</Button>
{videoSrc && <Link href={videoSrc}>Download</Button>}
</>
)
}