用安卓手机实现视频监控
程序员文章站
2022-07-06 22:53:47
...
现代手机更新换代如此之快,以至于家中往往有闲置不用的手机。本APP用一部闲置手机作为监控相机,在另一部手机上实现远程监控。
作为监控摄像机的手机称为服务器端,观看监控视频的手机称为客户端。
对于使用环境的要求是服务器端通过无线路由器WIFI接入互联网,客户端通过互联网远程访问服务器端。
路由器需要进行简单设置:
- DHCP静态IP分配,使服务端在局域网内的地址固定下来。
- 端口转发,将路由器的指定端口与服务器端的内网IP地址绑定,使客户端可以从外部访问服务器端。
使用时,需要在客户端输入路由器的外网IP地址,家庭用户路由器的IP地址通常是电信运营商动态分配的,时时会发生变化,客户端获取路由器IP地址的方法有两种:
- 在客户端安装路由器管理APP,路由器厂商通常都会提供路由器管理APP。通过路由器管理APP可以实时查看路由器的IP地址。
- 在花生壳上用内网计算机注册私有域名,私有域名与路由器绑定。在客户端安装花生壳管理APP,通过APP可以实时查看私有域名的IP地址,这个IP地址就是路由器的地址。如果不使用花生壳,其他域名解析提供者也有类似工具。
由于服务器端和客户端都需要发送信息到对方,因此用TCP协议实现服务器端和客户端的双工通信。
服务器端构成
图中所示为构成服务器端的主要类:
- MainActivity 用户交互主页面
- SettingsActivity 参数设置页面,可以设置编码器的图像分辨率和视频编码标准。
- AutoFitTextureView 服务器端的视频显示组件
- MainViewModel Android官方推荐使用MVVM架构,ViewModel是MVVM架构的重要组件,它负责为UI/View准备数据,它与外部通信通过LiveData进行。
- CameraIntentService 提供与客户端的通信服务,接收客户端的通信请求。通信连接成功后,建立服务器通信线程。
- ServerThread 服务器通信线程,发送编码后的视频数据流,接收客户端的字符信息。
- MediaCodecCallback 编码器采用异步工作模式,必须对编码器的各个回调函数重载,以实现本系统所需视频编码功能。
- ByteBufferTransfer 承载视频编码后得到的数据以及解码器需要的相关情报,它的每个实例代表一帧图像,经过通信连接,以数据流发送到客户端。
服务器端将镜头拍摄的视频信号经编码后逐帧传送给客户端,由于视频拍摄和信号传输各自具有不同的时序,因此使用异步方式实现协同动作。
服务器端的技术要点
-
视频编码数据获取
在android camera2的基础上,使用所推荐的流程控制相机。
为了取得相机帧数据,以下代码把编码器的InputSurface添加到CameraRequest的targets列表中,
在预览过程中,CameraDevice返回的帧数据就能够送到编码器中。val encoderInputSurface = MediaCodec.createPersistentInputSurface() mediaCodec.setInputSurface(encoderInputSurface) mediaCodec.start() previewRequestBuilder.addTarget(encoderInputSurface)
-
视频编码器参数
视频编码器需要设置的参数如下:
- videoCodecMime(编码格式) 可以在SettingsActivity中选择,本系统仅有H264和H265可以选择,注意!老的手机往往不支持H265。
- videoCodecSize(采样分辨率) 可以在SettingsActivity中选择,是手机常用的分辨率。
- KEY_FRAME_RATE(帧率) 这个参数在程序中固定为30。
- KEY_COLOR_FORMAT(颜色格式) 这个参数在程序中固定为MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface。
- KEY_I_FRAME_INTERVAL(关键帧间隔) 单位是秒,这个参数用于指定帧间预测所需关键帧在码流中的间隔,间隔越大,数据压缩率越高。但为了画面流畅,设为零,也就是没有用帧间预测。
- KEY_BIT_RATE(比特率) 比特率 = 分辨率宽 x 分辨率高 x 比特率系数。比特率系数是固定值,H264为14,H265为10,因为H265有更高的压缩率。
-
双工通信
收到客户端的请求后,建立服务器通信线程。在线程中建立并行的两个循环,一个用Loop+Handler实现,Handler负责接收视频编码器的输出,送入objectOutputStream,发送到客户端。
另一个用While实现,从objectInputStream中读取来自客户端的数据,根据数据的类别进行相应处理。
客户器端构成
图中所示为构成客户端的主要类:
- MainActivity 主页面容器
- SettingsActivity参数设置页面,仅用来设置服务器端的IP地址。
- MainFragment 用户交互主页面
- MainViewModel 是MVVM架构的重要组件,它负责为UI/View准备数据,它与外部通信通过LiveData进行。
- ClientThread 通信用客户端线程
- MonitorTextureView 客户端的视频显示组件
- MediaCodecAction 包装了解码器的静态操作方法
- DecoderCallback 解码器的回调函数
- ByteBufferTransfer 服务器端发送过来的实例,解码后得到帧图像。
接收到服务器端发送的视频码流,经解码后把视频信号交给视频显示组件。
客户端的技术要点
-
指定解码器输出
取得显示View的surface,
val surface = Surface(super@MonitorTextureView.getSurfaceTexture())
设置解码器时,把surface作为参数传给mediaCodec.configure()方法即可。
-
视频解码器参数
- mime(编码格式) 服务器发送过来的ByteBufferTransfer的实例中,包含此参数,不需单独设置。
- size(采样分辨率) 服务器发送过来的ByteBufferTransfer的实例中,包含此参数,不需单独设置。
- csd(Codec-specific数据) 服务器端编码时产生该数据,包含在ByteBufferTransfer的实例中。
-
双工通信
与服务器端相似,在线程中建立并行的两个循环,一个用来接收,另一个用来发送。
在测试中,服务器端和客户端均使用联通的网络时,视频传输比较流畅。
但是服务器端使用联通网络,客户端使用移动网络时,卡顿非常严重,原因不得而知,也许运营商之间有壁垒。
源程序代码公开,欢迎同行的指摘、建议,如有需要改进之处,我当尽力为之。
有任何问题,请联系。邮箱:aaa@qq.com
推荐阅读
-
安卓手机版PPTV聚力怎么下载电影以及电视剧?PPTV缓存视频方法介绍
-
互盾安卓恢复大师怎么用?互盾安卓恢复大师找回手机数据的三种模式
-
安卓音、视频播放功能简单实现 --Android基础
-
安卓手机QQ语音消息SLK文件用什么软件打开播放
-
iphone怎么用蓝牙传东西给安卓(手机用蓝牙传照片的方法)
-
安卓移动软件开发:手机防火墙的实现
-
大四应届生用Python实现了远程监控!压根就不需要女友开视频!
-
微博宣布支持HDR视频:iPhone 12可拍摄上传 安卓手机无缘
-
安卓底部导航栏的实现以及用TabLayout+ViewPager+Fragment实现页面滑动切换
-
华为:鸿蒙系统不是给手机的 继续用安卓