使用手机摄像头实现视频监控实时播放

Posted shuaijie506

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用手机摄像头实现视频监控实时播放相关的知识,希望对你有一定的参考价值。

使用手机摄像头实现视频监控实时播放

一、概述

视频监控实时播放的原理与目前较为流行的直播是一致的,所以采用直播的架构实现视频监控实时播放,流程图如下:

推流 安卓APP 直播服务器 VLC播放器 其他播放端

目前实时视频流的传输协议有以下几种:RTSP、RTMP、HLS、Http-flv。
安卓APP开发使用HBuilder,而HBuilder内置了LivePusher直播推流控件,该控件使用了RTMP协议,所以暂时选择使用RTMP协议

协议RTSPRTMPHLSHttp-flv
实时预览
实时回放
定位×
暂停恢复×
视频加密×
视频格式H264/H265H264/H265H264H264/H265
音频格式G711u, G711a, G726, MP2L2, AACAACAACAAC
首屏时间1秒1秒3~4秒1秒
播放延迟1秒1秒3~4秒1秒

二、RTMP服务器搭建

RTMP服务器使用nginx+rtmp模块搭建,linux下可以下载nginx源代码+nginx-rtmp-module模块重新编译,windows下nginx编译较为麻烦,可以下载nginx 1.7.11.3 Gryphon,然后再下载nginx-rtmp-module模块进行配置即可

相关软件下载地址

nginx地址:https://github.com/nginx/nginx
nginx-rtmp-module地址:https://github.com/arut/nginx-rtmp-module/
nginx 1.7.11.3 Gryphon地址:http://nginx-win.ecsds.eu/download/nginx 1.7.11.3 Gryphon.zip
ffmpeg地址:https://ffmpeg.org/download.html

服务器搭建步骤

  1. 下载nginx 1.7.11.3 Gryphon后解压到任意目录,注意目录中尽量不带中文字符和空格
  2. 下载nginx-rtmp-module(直接从github clone或下载zip压缩包),将nginx-rtmp-module目录放到nginx的根目录下,与conf目录同级
  3. 将conf/nginx-win.conf复制一份,改名为nginx.conf
  4. 配置nginx.conf文件,增加rtmp的server,同时给http的server中增加路径映射
  5. 启动nginx
  6. 打开http://localhost/stat查看状态
  7. 使用ffmpeg进行直播测试

nginx配置

在http段之前增加以下内容:

rtmp 
    server 
        listen 1935;
        application live 
            live on;
			record off;
			publish_notify on;
			#on_publish http://localhost:8080/newsweb/api/v1/rtmp/on_publish;
			#on_publish_done http://localhost:8080/newsweb/api/v1/rtmp/on_publish_done;
			#on_play http://localhost:8080/newsweb/api/v1/rtmp/on_play;
			#on_play_done http://localhost:8080/newsweb/api/v1/rtmp/on_play_done;
        
        application hls 
            live on;
            hls on;  				 #是否开启hls
            hls_path temp/hls; 		 #本地切片路径
            hls_fragment 8s;  		 #本地切片长度
			publish_notify on;
			#on_publish http://localhost:8080/newsweb/api/v1/rtmp/on_publish;
			#on_publish_done http://localhost:8080/newsweb/api/v1/rtmp/on_publish_done;
			#on_play http://localhost:8080/newsweb/api/v1/rtmp/on_play;
			#on_play_done http://localhost:8080/newsweb/api/v1/rtmp/on_play_done;
        
    

在http->server下,location /段之前增加以下内容:


		location /stat 
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        

        location /stat.xsl 
            root nginx-rtmp-module/;
        
		#HLS配置开始,这个配置为了`客户端`能够以http协议获取HLS的拉流
        location /hls   
            #server hls fragments  
            types  
                application/vnd.apple.mpegurl m3u8;  
                video/mp2t ts;  
              
            alias temp/hls;  
            expires -1;  
          

注:其中rtmp段中的on_publish、on_publish_done、on_play、on_play_done是事件触发,当直播开始、直播结束、观看开始、观看结束时,会触发指定的URL,并将推流和观看时的相关参数传递到相关URL上,如果HTTP返回的状态码不是200时表示鉴权失败,会直接阻断下一步的操作

直播测试

  1. 本地找一个mp4文件
  2. 使用在ffmpeg\\bin目录下执行推流命令
  3. 使用ffplayer播放视频
#推流地址解释:rtmp://localhost:1935/live/home?p=v
#rtmp://为协议名
#localhost是域名
#1935为端口号,rtmp默认为1935端口
#live为nginx.conf中配置的rtmp标记
#home为指定字符串,生产环境中可以设置为设备ID或用户ID
#?p=v是附加参数,用于鉴权和记录直播开始使用

#ffmpeg推流测试:
ffmpeg.exe -re -i c:\\ffmpeg\\inputfile.mp4 -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/live/home 

#ffmpeg 拉流测试:
ffplay.exe rtmp://localhost:1935/live/home

三、安卓APP推流

安卓APP推流使用HBuilder的LivePusher直播推流控件,代码如下:

<!DOCTYPE html>
<html>
	<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
	<title>Video Example</title>
	<script type="text/javascript">
		var pusher = null;
		// H5 plus事件处理
		function plusReady()
			// 创建直播推流控件
			pusher = new plus.video.LivePusher('pusher',
				url:'rtmp://172.16.70.182:1935/live/phone',
				mode:'SD',
				muted:false,
			);
			pusher.preview();
			// 监听状态变化事件
			pusher.addEventListener('statechange', function(e)
				console.log('statechange: '+JSON.stringify(e));
			, false);
		
		document.addEventListener('plusready', plusReady, false);
		// 设置推流服务器
		function updatePusher() 
			var url= document.getElementById('pushurl').value;
			pusher.setOptions(
				url:url
			);
		
		// 开始推流
		function startPusher() 
			console.log(pusher)
			pusher.start();
		
		
		// 切换摄像头
		function switchCamera() 
			pusher.switchCamera();
		
	</script>
	</head>
	<body style="margin:0;padding:0;text-align:center;">
		<div id="pusher" style="width:100%;height:300px;background-color:#000000;margin:auto"></div>
		<br/>
		<input type="text" id="pushurl" value="rtmp://172.16.70.182:1935/live/phone"  style="width: 500px;"/>  <br><br>
		<button onclick="updatePusher()">更新推流服务器</button>
		<br/><br>
		<button onclick="startPusher()">开始推流</button>  
		<br><br>
		<button onclick="switchCamera()">切换摄像头</button>
		<br/><br/>
		
	</body>
</html>

四、客户端观看直播

目前暂时使用VLC进行视频播放
VLC下载地址:https://www.videolan.org/vlc/

国标28181:实时视频播放

流程

一个流媒体平台主要分为一些几个部分

主要用途:对接监控摄像头、视频直播、多对多视频聊天器

系统架构由三个部分组成:

  • 接口服务器(HTTP服务器)主要用于响应客户端的请求
  • 信令服务器(SIP服务器)主要用于和流媒体服务器和视频设备交互,主要功能是管理摄像头之类的设备以及控制摄像头将视频流转发给流媒体服务器的哪个端口
  • 流媒体服务器主要用于处理视频流的接收、转发和分发

接口服务器和信令服务器可以整合为一个服务器。

流媒体服务器最好单独部署,避免流媒体服务器压力过大,可以用ZLMediaKit代替。我们要开发的就是接口服务器和信令服务器。

实时码流点播采用SPI协议中的INVITE方法实现会话连接,采用RTP/RTCP协议实现媒体传输。

整个播放过程如下:

其通信流程如下:

视频流是怎么推流的

SIP视频流的获取是指解码器(ZLMediaKit)通过SIP协议向GB28181服务器获取视频流的过程

  • GB28181服务器(也就是SIP服务器)会像摄像头发送一些信令,主要是请求播放实时视频。
    • 开启SIP服务器,服务器将会监听某个端口,可以从这个端口收到SDP信息
    • 摄像机端发送Register消息后,然后服务端应答注册消息代码
    • SIP服务端响应注册命令后,发送Invite请求,请求catalog信息,也就是设备基本信息
    • 摄像机端收到消息发送其自身的catalog消息,将会服务具体的具体的catalog消息。
    • SIP服务取都摄像机的信息后就可以发送请求视频信息到摄像头。下面看下SDP信息怎么写
static string createSDP(MediaContext& mediaContext)

	char str[500] =  0 ;
	pj_ansi_snprintf(str, 500,
	"v=0\\n"
	"o=%s 0 0 IN IP4 %s\\n"
	"s=Play\\n"
	"c=IN IP4 %s\\n"
	"t=0 0\\n"
	"m=video %d RTP/AVP 96 98 97\\n"
	"a=recvonly\\n"
	"a=rtpmap:96 PS/90000\\n"
	"a=rtpmap:98 H264/90000\\n"
	"a=rtpmap:97 MPEG4/90000\\n"
	"y=0100000001\\n",
	mediaContext.GetDeviceId().c_str(),
	mediaContext.GetRecvAddress().c_str(),
	mediaContext.GetRecvAddress().c_str(),
	mediaContext.GetRecvPort()
			);
	return str;

  • 信令交互成功之后,摄像头(媒体流发送者)会将视频数据以rtp的方式推送到指定的端口 (端口在上面的invite消息指定)流到媒体服务器
  • 媒体服务器(GB28181服务器)在指定的端口接收视频流
  • 媒体服务器(GB28181服务器)将视频流转发给流媒体接收者(比如ZLMediaKit)

具体流程如下:

视频流格式

GB28181要求传输的视频流格式为PS流,或者H264流,或者MP4格式。

可以用wireshark抓包,数据报类型是RTP的PS流

国标流媒体服务器其实就是负责将GB28181设备或者平台推送的PS流转成ES流,然后提供RTSP、RTMP、FLV、HLS等格式进⾏分发。

PS流和ES流的区别

IP数据报有⾸部和数据两部分组成的,⾸部的前⼀部
分是固定长度20字节,是所有IP数据报必须具有的。⾸部包括:总长度、标识、MF、DF、⽚偏移。
数字信号实际传送的是数据流,⼀般数据流包括以下三种:

  • ES流(Elementary Stream):也叫基本码流,包含视频、⾳频或数据的连续码流。
  • PES流(Packet Elementary Stream):也叫打包的基本码流,是将基本的码流ES流根据需要分成长度不等的数据
    包,并加上包头就形成了打包的基本码流PES流。
  • TS流:也叫传输流,是由固定长度为188字节的包组成,含有独⽴时基的⼀个或多个program, ⼀个program⼜可以包含多个视频、⾳频、和⽂字信息的ES流; 每个ES流会有不同的PID标⽰,为了可以分析这些ES流, TS有⼀些固定的PID⽤来间隔发送program和ES流信息的表格: PAT和PMT表。适⽤于误码较多的环境

ES 是直接从编码器出来的数据流,可以是编码过的视频数据流,⾳频数据流,或其他编码数据流的统称。 ES 流经过PES 打包器之后,被转换成 PES 包,再通过RTSP、RTMP、FLV、HLS格式分发出去,实现WEB、⼿机、PC、微信等多终端的播放

传播方式

GBT28181协议规定码流使用RTP包负载,推荐为PS流,也可以是ES流,对于媒体流的传输在原有UDP传输的基础中,增加了主动tcp和被动tcp的方式。

(1)UDP被动

  • 这个是普遍的传输方式。
    • GB28181流媒体服务器监听单个UDP端口,然后发送一个SIP信令(INVITE),其携带的SDP中包含了接收媒体的端口
    • 设备端收到信令后,解析该端口,然后设备主动通过UDP向流媒体服务端监听的那个端口上发送视频流

(2)TCP被动

  • 有两种,一种是主动,一种是被动
  • 对于主动: 设备端告知服务端自己的媒体流tcp端口,服务端主动去连接设备端的该端口,获取数据。。这种场景应用较少,可以忽略
  • 对于被动:流媒体服务器监听单个TCP端口,然后通过SIP信令(INVITE)告诉设备端口,设备主动向当前流媒体服务端发送视频流,基本等同于UDP流

实时视频

流程

前提:注册成功>>>>>>心跳成功>>>>>>设备目录查询>>>>>实时视频观看

服务端步骤

不管是TCP方式看,还是UDP方式看,其步骤都为:
(1)打开视频端口
(2)发送实时视频请求
(3)等待设备回复200OK
(4)发送ACK
(5)播放码流
(6)停止视频请求
(7)关闭视频端口
(8)普通等待

抓包分析

测试设备IP:192.168.0.107
服务端IP:192.168.0.60

实时视频建立_UDP

第零步:【服务端】打开视频端口

第一步:【服务端>>客户端】请求播放视频

INVITE sip:34020000001310000002@4401020049 SIP/2.0
Call-ID: helloVideo
CSeq: 1 INVITE
From: <sip:44010200492000000001@4401020049>;tag=bccedfd0111
To: <sip:34020000001110000001@4401020049>
Max-Forwards: 70
Contact: <sip:34020000001310000002@4401020049>
Via: SIP/2.0/UDP 192.168.0.107:5060;branch=z9hG4bKee5c5d98-bff9-4f3000002
Content-Type: application/sdp
Content-Length: 225

v=0
o=34020000001310000002 0 0 IN IP4 192.168.0.60
s=Play
c=IN IP4 192.168.0.60
t=0 0
m=video 6000 RTP/AVP 96 98 97
a=recvonly
a=rtpmap:96 PS/90000
a=rtpmap:98 H264/90000
a=rtpmap:97 MPEG4/90000
y=0100000001
f=

第二步:【客户端>>服务端】

先回复101
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.0.107:5060;branch=z9hG4bKee5c5d98-bff9-4f3000002
From: <sip:44010200492000000001@4401020049>;tag=bccedfd0111
To: <sip:34020000001110000001@4401020049>;tag=5f906952
Call-ID: helloVideo
CSeq: 1 INVITE
Server: Happytime Agent Ver 1.0
Content-Length: 0
再回复200
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.0.107:5060;branch=z9hG4bKee5c5d98-bff9-4f3000002
From: <sip:44010200492000000001@4401020049>;tag=bccedfd0111
To: <sip:34020000001110000001@4401020049>;tag=5f906952
Contact: <sip:34020000001110000001@4401020049>
Call-ID: helloVideo
CSeq: 1 INVITE
Max-Forwards: 70
Allow: ACK,BYE,CANCEL,INVITE,NOTIFY,REFER,UPDATE,INFO
Supported: timer
Session-Expires: 200;refresher=uac
Server: Happytime Agent Ver 1.0
Content-Type: application/sdp
Content-Length: 153

v=0
o=34020000001110000001 0 0 IN IP4 192.168.0.107
s=Play
c=IN IP4 192.168.0.107
t=0 0
m=video 19002 RTP/AVP 96
a=rtpmap:96 PS/90000
a=sendonly

第三步:【服务端>>客户端】回复ACK

ACK sip:34020000001310000002@4401020049 SIP/2.0
Call-ID: helloVideo
CSeq: 1 ACK
From: <sip:44010200492000000001@4401020049>;tag=bccedfd0111
To: <sip:34020000001110000001@4401020049>
Max-Forwards: 70
Via: SIP/2.0/UDP 192.168.0.107:5060;branch=z9hG4bKee5c5d98-00003
Content-Length: 0

第四步:播放码流

第五步:【服务端>>客户端】停止视频请求

BYE sip:34020000001310000002@4401020049 SIP/2.0
From: <sip:44010200492000000001@4401020049>;tag=bccedfd0111
To: sip:34020000001110000001@4401020049;tag=5f906952
CSeq: 2 BYE
Call-ID: helloVideo
Via: SIP/2.0/UDP 192.168.0.107:5060;branch=z9hG4bKee5c5d98-00004
Max-Forwards: 70
Content-Length: 0



第六步:【客户端】回应200

SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.0.107:5060;branch=z9hG4bKee5c5d98-00004
From: <sip:44010200492000000001@4401020049>;tag=bccedfd0111
To: sip:34020000001110000001@4401020049;tag=5f906952
Call-ID: helloVideo
CSeq: 2 BYE
Server: Happytime Agent Ver 1.0
Content-Length: 0


第七步:【服务端】关闭视频端口

实时视频建立_TCP


基本要求

信令流程

实时视频流点播的信令流程有两种:

  • 客户端主动发起
  • 第三方呼叫控制

联网系统可选择其中一种或两种结合的实现方式,第三方呼叫控制的第三方控制者宜采用背靠背用户代理实现

客户端主动发起实时音视频点播流程

流程

消息示范










抓包分析

【上级平台】订阅完所有的通道之后,就可以向【下级平台】发送Invite请求流了

INVITE sip:33072752001320080039@10.45.255.10:5060 SIP/2.0
Via: SIP/2.0/UDP 10.45.255.11:5060;rport;branch=z9hG4bK-469C18DE-28C36C5-T07h4NhO
From: <sip:33072700232000002456@3307270023>;tag=573748381
To: <sip:33072752001320080039@10.45.255.10:5060>
Call-ID: 743791906
CSeq: 20 INVITE
Contact: <sip:33072700232000002456@10.45.255.11:5060>
Content-Type: application/sdp
Max-Forwards: 70
User-Agent: videosvr 1.0
Subject: 33072752001320080039:1,33072700232000002456:1
Content-Length:   220

v=0
o=33072752001320080039 0 0 IN IP4 10.45.255.11
s=Play   // play表示播放
c=IN IP4 10.45.255.11
t=0 0
m=video 31000 RTP/AVP 96 98 97
a=recvonly
a=rtpmap:96 PS/90000
a=rtpmap:98 H264/90000
a=rtpmap:97 MPEG4/90000
y=0727000001

【下级平台也就是(信令服务器)】回应如下:

SIP/2.0 181 Call is being forwarded  // 181表示我已经将请求转发给下级了
CSeq: 20 INVITE
Call-ID: 743791906
From: <sip:33072700232000002456@3307270023>;tag=573748381
To: <sip:33072752001320080039@10.45.255.10:5060>
Via: SIP/2.0/UDP 10.45.255.11:5060;rport=5060;branch=z9hG4bK-469C18DE-28C36C5-T07h4NhO;received=10.45.255.11
Content-Length: 0

如何点播

点播的基本流程

  • HTTP端—>GB28181信令服务器,发起点播请求
  • GB28181信令服务器—>设备,发起Invite(携带SDP消息体)的请求
  • 设备—>GB28181信令服务器,回复200OK (携带SDP消息体)
  • GB28181信令服务器—>设备,发送ACK,成功建立一个会话
  • 设备—> 流媒体服务器,发送实时流
  • 流媒体服务器—>GB28181服务器,流改变事件
  • GB28181服务器—>设备,告知流播放地址
  • 流媒体服务器—>GB28181服务器,无人观看事件
  • GB28181服务器—>设备,发送Bye消息
  • 设备—>GB28181服务器,回复200OK

点播时可能的错误

(1)400错误

其流程如下:

  • HTTP端—>GB28181信令服务器,发起点播请求
  • GB28181信令服务器—>设备,发起Invite(携带SDP消息体)的请求
  • 设备—>GB28181信令服务器,回复400OK (携带SDP消息体)

什么原因:

  • 设备认为信令服务器发送了错误的消息给它,可能是消息不全或者错误,因此直接返回400

怎么解决:

  • 抓包
  • 直接联系设备/平台客服寻求解决

(2)500错误

什么原因:

  • 500<= code <= 600的错误码,一般是设备内部出了问题

怎么解决:

怎么解决:

  • 抓包
  • 直接联系设备/平台客服寻求解决

点播时超时

点播超时的原因大致分为两种:点播超时和收流超时。

(1)点播超时

发生在哪里?

  • 点播超时一般是因为信令超时,可能出现在“设备—>GB28181信令服务器,回复200OK (携带SDP消息体)”这一步,即我们发送了点播消息,但是设备没有回复。

可能的原因:

  • 设备内部错误,没能回复消息
  • 网络原因消息未到达设备

(2)收流超时

发生在哪里?

  • 设备—> 流媒体服务器,发送实时流
  • 流媒体服务器—>GB28181服务器,流改变事件

可能的原因:

以上是关于使用手机摄像头实现视频监控实时播放的主要内容,如果未能解决你的问题,请参考以下文章

国标28181:实时视频播放

iOS使用ffmpeg播放rstp实时监控视频数据流

WEB页面实时播放海康大华等摄像头RTSP视频流完全方案

ts格式的视频文件怎么播放?

Qt推流程序自动生成网页远程查看实时视频流(视频文件/视频流/摄像头/桌面转成流媒体rtmp+hls+webrtc)

有没有人能够在 iOS 上的单独视图中同时播放视频文件和显示实时摄像机源?