Android旧手机DIY WiFi局域网监控:Camera2+MediaCodec+RTSP实现指南 简介这是一套面向Android开发初学者与物联网实践者的局域网视频监控项目源码基于UDP协议实现WIFI内两部安卓手机间的实时视频流传输——一部作为摄像头采集端另一部作为监控显示端解决无服务器依赖下的轻量级远程监看需求。资源包共77个文件含15个核心Java类涵盖Camera2采集、UDP发送/接收、SurfaceView渲染等模块、16个XML布局与权限配置文件、16张UI图标PNG资源以及Gradle构建脚本、ProGuard混淆规则、本地环境配置等工程必需文件整体仅961KB结构精简、便于快速编译运行。已有1309人学习下载配套CSDN博文详细解析了UDP帧封装策略、预览尺寸适配逻辑、丢包应对机制及局域网IP自动发现技巧源码目录层次清晰app模块独立完整适合用于课程设计、毕业项目或嵌入式视觉通信场景的二次开发参考。 每次出差住酒店我都会习惯性看一眼房间角落有没有什么可疑的小设备。后来干脆自己动手用闲置的旧安卓手机做了一套WiFi局域网内的视频监控系统手机镜头对着门口电脑或另一台手机在同一网络下实时查看画面就这么用了一年多。这篇文章就把这套Android项目源码的完整实现思路、关键代码段和踩坑记录整理出来给想自己DIY一套局域网监控方案的朋友做个参考。先说清楚这套东西能做什么它本质上是把一台安卓手机变成IP摄像头视频流通过WiFi局域网传输另一端用浏览器、VLC或者自写的播放器实时查看。场景可以很灵活——临时代替家用摄像头看宠物、看孩子房间、监控门口快递或者把手机当成电脑的监视器用。适合有Android开发基础、想玩Camera2和MediaCodec的开发者也适合想快速搭一套私有监控系统的折腾党。1. 整体设计与方案选型1.1 为什么选择“手机做服务端局域网直连”的架构最开始我考虑过两种方案一是手机录像后上传云服务器再通过公网拉流二是手机作为RTSP服务端在局域网内直接推流。前者依赖外网带宽和服务器的转码能力成本高、延迟大而且隐私数据过了一遍第三方链路心里总觉得不踏实。后者就简单直接——手机自带摄像头和编码器WiFi路由器做数据交换同一个局域网内的播放器直接拉流延迟能做到几百毫秒内完全够用。选局域网直连还有一个现实原因家用的普通路由器NAT转发能力有限如果走公网中转1080P的视频流上传带宽至少要4Mbps很多家庭的上行带宽根本扛不住。而局域网内是交换机级别的数据交换千兆路由下跑满手机编码器的码率毫无压力稳定性和画质都更有保障。这个架构的关键角色有三个采集端旧安卓手机、传输通道WiFi路由器、播放端电脑/VLC/另一台手机。采集端负责图像采集、编码、封包推送传输通道负责数据包转发播放端负责接收、解码和渲染。系统设计的核心就是把这个链条上的每一环都做对。1.2 技术选型Camera2 MediaCodec 硬编码 RTSP协议摄像头采集这块老项目还在用Camera1 API但新设备上Camera1的兼容性已经越来越差很多手机上会被系统标记为deprecated。所以我直接用Camera2来做虽然它的回调模型复杂一点但能拿到底层的ImageReader数据配合MediaCodec做硬编码非常顺。编码器选MediaCodec直接用手机自带的H.264硬编。这里有个重要概念硬编码和软编码的区别就像“用单反直出JPG”和“用电脑Lightroom批量转JPG”前者效率和功耗都完胜。旧手机做监控要7x24小时跑软编码不仅费电发热降频后画面会卡到没法看硬编码则轻松控制在比较低的功耗水平。传输协议我对比过RTSP、RTMP和裸TCP流。RTMP要经过Adobe的协议栈主要面向直播客户端播放器支持面窄裸TCP流实现简单但自己写的播放器兼容性是个大坑投屏到其他设备就没法看了。最后选了RTSP——它是一个文本会话控制协议配合RTP承载音视频数据VLC、ffmpeg、PotPlayer全都原生支持手机端抓包调试也方便。1.3 客户端播放器选择与兼容性测试播放端的选型直接决定了你调试的效率。我实测下来电脑上用VLC是最省事的打开网络串流输入rtsp://192.168.1.100:8554/live就能看到画面。安卓手机上用VLC的安卓版或者MX Player都能拉流。如果你要自己写播放器建议不要重复造轮子直接用VLC的libVLC库或者谷歌的ExoPlayer后者对H.264的硬解支持非常完善。这里有个重要提示项目源码中也需要附上一份客户端播放Demo方便使用者快速验证服务端是否正常工作。我自己的项目里就带了一个简单的播放器模块用MediaPlayer配合自定义的RTSP数据源虽然不如VLC的兼容性强但至少能保证全链路是通的。2. 核心模块拆解与关键技术实现2.1 摄像头采集模块Camera2的回调与旋转处理摄像头采集是整个项目的源头图像质量好不好、数据到得及不及时全看这一步。Camera2的核心是建立CameraCaptureSession然后通过ImageReader获取每一帧的YUV数据。这里有几个关键参数需要认真配置预览尺寸我选1280x720而不是1920x1080因为720P在监控场景下清晰度够用但数据量比1080P少了将近一半编码压力和网络占用都小很多实测对延迟的改善非常明显。30fps的帧率是底线低于这个值画面就会有明显的顿挫感。旋转问题必须处理。手机竖着放但摄像头传感器输出的图像是横向的所以每帧数据要旋转90度或270度才能得到正立的画面。这个操作如果放在Java层逐像素做性能会崩掉我都是在编码前通过MediaCodec的setInputBuffer阶段配合transform参数矩阵处理的。源码里我封装了一个CameraController类统一管理前后摄像头切换、旋转角度、对焦模式每次新设备适配只需要改一个配置项。2.2 编码模块H.264硬编码的MediaCodec配置MediaCodec配置是整个项目最需要耐心的部分。首先要确认设备支持H.264编码可以通过MediaCodecList查询编码器能力然后创建一个MediaFormat设置MIMETYPE_VIDEO_AVC接下来是几个对实时性影响巨大的参数。关键帧间隔KEY_I_FRAME_INTERVAL我设置为1秒。这里要说明一下H.264的视频流由I帧和P帧组成I帧是完整的图像P帧只记录变化如果关键帧间隔太长播放端从中间开始拉流时必须等到下一个I帧才能出画面延迟会明显增加。监控场景下1秒一次的I帧是比较激进的设置但换来的好处是播放端秒开画面连接中断后的恢复速度也快。码率建议设置为码率 分辨率 × 系数。720P情况下我取2Mbps1080P则建议4Mbps。设置太高会超出WiFi的稳定传输能力太低又会出现马赛克。我封装了一个码率自适应逻辑根据手机的电量和WiFi信号强度动态调整实测在信号不稳定的环境中可以明显减少画面花屏。2.3 传输模块RTSP会话和RTP分包RTSP协议本身不算复杂它建立的是客户端与服务端之间的会话控制通道实际的视频数据走RTP通道。整体流程是客户端发送OPTIONS询问服务端能力服务端响应客户端发送DESCRIBE获取流描述SDP服务端返回视频编码格式、分辨率等客户端发送SETUP建立RTP通道客户端发送PLAY服务端开始推流。RTP分包是这里的核心技术点。每个H.264的NALU网络抽象层单元大小不一如果超过MTU最大传输单元通常为1500字节就要拆成多个RTP包发送。源码中我实现了一个RtpPacketizer按FU-A分片方式切包每个RTP包头部带上序列号和时间戳接收端才能正确拼装和播放。这个模块麻雀虽小五脏俱全写的时候特别容易出bug建议先用VLC做联调不断对比协议状态直到播放器不报错为止。2.4 线程模型采集、编码、推流的流水线设计很多人做这类项目卡死原因不是摄像头打不开而是线程模型直接写崩了。监控是典型的实时数据流场景采集、编码、网络推送这三个环节必须用三个独立线程中间用队列连接组成一条流水线。我的设计是CameraThread负责从ImageReader取帧投递到编码队列EncodeThread从队列取数据送给MediaCodec编码完成后产出H.264数据PushThread负责将编码后的数据按RTP协议封包并发送到客户端。这三个线程之间的队列都要设置上限比如10帧满了就丢弃旧帧、保留新帧——监控画面实时性第一宁可跳帧也不积累延迟。还有一点网络推送线程一定要使用阻塞式socket并设置超时避免客户端断开后线程永远卡死。源码里我写了一个心跳检测机制客户端超过3秒没发RTSP指令服务端就主动回收会话资源。3. 从零搭建到跑通完整实操记录3.1 开发环境与工程初始化项目用的是Android StudioSDK版本建议compileSdk 34minSdk 21。Android 9.0以上默认禁止明文HTTP流量但RTSP协议用的是明文传输所以必须在AndroidManifest.xml中给application节点加上android:usesCleartextTraffictrue否则RTSP握手会直接被系统拦截。这个坑我调了整整一下午才发现一定要提前配好。依赖方面我不建议引入重型第三方库。摄像头采集用系统API编码用MediaCodecRTSP协议栈可以自己写也可以引入开源的libstreaming库。我最终选择自己写协议层因为libstreaming停更好多年了在新系统上问题很多而且自己掌握协议层之后后期想加双向语音、云台控制都方便。3.2 权限配置与动态申请权限有两个层次AndroidManifest里声明运行时再动态申请。需要以下几个权限android.permission.CAMERA摄像头访问运行时权限android.permission.INTERNET网络通信安装权限android.permission.ACCESS_WIFI_STATE和ACCESS_NETWORK_STATE获取WiFi状态用于显示IP和信号强度Android 6.0以上必须动态申请CAMERA权限这个不复杂但要注意必须在用户授权后才能打开摄像头否则摄像头会直接抛异常。更隐蔽的问题是把摄像头权限授权给前台服务时如果用户从最近任务列表划掉了App权限可能被系统回收导致后台监控中断。我的方案是启动一个foreground service并且把服务通知常驻这样既保证了进程存活也让用户明确知道摄像头正在工作。3.3 服务端启动与核心代码骨架服务端启动的核心逻辑如下。第一步扫描本机所有网络接口取出WiFi的IP地址第二步启动RTSP服务器监听8554端口第三步初始化Camera2和MediaCodec最后将编码器输出和RTSP服务器连接起来。// RtspServer.java - 核心启动逻辑 public void start() { String ip getWifiIpAddress(); int port 8554; serverSocket new ServerSocket(port); executorService new ThreadPoolExecutor(4, 8, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue(100)); // 每个客户端连接建立独立会话 while (isRunning) { Socket client serverSocket.accept(); executorService.execute(new RtspSession(client, this)); } } private String getWifiIpAddress() { WifiManager wm (WifiManager) context.getSystemService(Context.WIFI_SERVICE); int ipInt wm.getConnectionInfo().getIpAddress(); return Formatter.formatIpAddress(ipInt); }3.4 编码器初始化与Camera2采集对接编码器初始化的关键代码不多但每个参数都有讲究。我特别说明几个容易被忽略的// VideoEncoder.java - MediaCodec配置 MediaFormat format MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible); format.setInteger(MediaFormat.KEY_BIT_RATE, 2_000_000); // 2Mbps format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); // 30fps format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 1秒一个I帧 format.setInteger(MediaFormat.KEY_CAPI_FRAME_INTERVAL, 1); // 实时编码模式 mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);其中KEY_CAPI_FRAME_INTERVAL是Google API 21之后新增的关键参数它控制编码器的延迟模式。默认值负数是“极致延迟优化”但某些设备上会导致编码器丢帧所以这里设置为1表示“允许一帧的缓冲”既能保证流畅度又不会堆积延迟。Camera2和编码器的数据对接属于整个项目里最容易搞砸的部分。Camera2通过ImageReader.OnImageAvailableListener回调拿到Image对象然后转成ByteBuffer投递给编码器。这里有几个性能要点第一复用ImageReader分配的缓冲区不要每帧都new一个新buffer第二在编码器和采集线程之间加一个有界队列用ArrayBlockingQueue来削峰填谷第三一定不要在主线程处理图像数据否则GC压力会直接拖垮整个App。3.5 推流线程和播放端地址预览推流线程的核心就是循环从编码器输出队列拿数据然后按RTP协议打包发送。为了控制延迟我给这个线程设置了发送缓冲上限如果客户端消费速度跟不上就直接丢弃最旧的帧。很多延迟和花屏问题其实都出在“服务端发送了自己觉得没问题、但客户端根本来不及处理”的过量数据上。测试的时候电脑上打开VLC媒体菜单打开网络串流输入rtsp://你的手机IP:8554/live点播放就能看到画面。这里有几个小技巧先用浏览器访问http://手机IP:8554看服务端是否响应再用VLC看能否拉到流最后才轮到你自己写的播放器调试。一层一层排查能省很多时间。4. 常见问题、延迟优化与实战心得4.1 画面延迟高的三大原因和解决路径局域网内最大的敌人是延迟。我测试过同一环境下三种情况的延迟表现情况延迟原因720P/30fps硬编约200-300ms编码和传输开销小基本可接受1080P/30fps硬编约400-500ms码率翻倍路由器转发压力上升开启WiFi省电模式800ms以上手机CPU降频导致编码和推送掉队降低延迟第一件事是关掉手机的省电策略App里通过PowerManager.WakeLock维持CPU常亮。第二件事是把分辨率从1080P降到720P肉眼在手机上几乎看不出差别但延迟立刻下降。第三件事是合理设置I帧间隔切到1秒后播放端从连接到出画面的时间能控制在500ms内。4.2 采集端频繁断流、画面花屏的处理花屏最常见的两个原因一是码率设置超过WiFi实际承载能力导致丢包二是设备的硬编解码器对特定分辨率支持不完整。排查方法先看编码器生成的SPS/PPS参数然后用VLC播放时打开统计信息实时观察丢包率。如果码率正常但还是花屏我遇到过一种情况是手机的MTU设置为1400而路由器默认MTU是1500出现IP分片导致乱序。解决办法是把RTP包大小设置为1200字节低于常见MTU阈值同时封包时保证每个UDP包是独立的不做跨包分片。这个细节在路由器和手机兼容性复杂的场景下尤其重要能解决大量“玄学花屏”问题。4.3 手机发热降频导致丢帧这是用手机做7x24小时监控绕不过去的坎。手机散热能力有限长时间录像发热后SoC会主动降频MediaCodec的编码帧率会从30fps掉到15fps甚至更低然后就出现画面卡顿和延迟上升。我的经验是不要把监控手机放在被子里或者封闭柜子里保证空气流通如果长时间吊装可以考虑用散热背夹实测能稳住帧率不掉还有一个取巧的办法是把分辨率降到640x480帧率降到15fps发热量小很多在一些只需要看清有没有人经过的场景下完全够用。4.4 新设备适配和抓包调试的经验Android的碎片化在这类项目上体现得淋漓尽致。我手上的测试机里小米的Camera2回调格式和三星的不完全一样华为的MediaCodec硬编输出在某些分辨率下会多出奇怪的padding字节这些都只能靠真机适配时逐一处理。建议在做兼容性适配时把所有机型相关的特殊逻辑都集中放到一个DeviceCompat类里每个新设备只需要加一个分支。抓包调试协议时我强烈推荐用Wireshark。电脑端开启抓包过滤条件填rtsp || rtp完整地看一遍握手和推流流程问题基本一眼就能定位。有一次VLC一直连不上抓包发现是服务端返回的SDP里把PT动态负载类型写成了96而媒体数据用的PT是97两边对不上播放器自然不认。这种事光看代码根本看不出来。4.5 安全性问题局域网不等于绝对安全做了监控系统安全问题必须多说几句。这套方案默认只在WiFi局域网内运行数据不会出路由器但不代表没有风险。同一个WiFi网络下的其他设备如果有技术能力理论上是可以发RTSP请求拉流的。我做了三层防护第一层是RTSP的URL加访问凭证只有携带正确token的客户端才允许拉流第二层是在应用层对RTP数据做AES加密代价是多耗一点点CPU但数据即使被抓包也无法直接解码第三层是只允许服务端主动推流不接受外部主动连入请求。虽然是局域网环境该有的底线还是要有。5. 项目扩展思路从单机监控到房间级系统跑通最基础的“手机当摄像头”之后可以往两个方向扩展。一个方向是增加移动端能力——让监控的手机端App支持监听麦克风实现声音采集或者加一个反向通道播放端可以触发手机端的报警音这样有人闯入时就能远程警告。另一个方向是系统化——如果你手上有几台旧手机可以分别放在不同房间每台都跑同一套服务端然后在电脑上用一个多窗口播放器同时查看多个视频流这就是一个低成本的多房间监控矩阵。再往深了做可以对服务端做本地录像功能用MediaMuxer把H.264裸流封装成MP4文件存到手机本地再配上简单的文件管理界面就变成了一个带记录回放功能的监控系统。虽然局域网内不能随时随地远程查看但回到同一个WiFi下历史录像随时可以调取作为家庭监控已经相当能打了。我自己还把其中一台旧手机改造成了“床头监控家庭NAS辅助”同一台设备上同时跑着视频服务和一个轻量级的文件共享服务稳定性出乎意料地好已经连续跑了三个多月没重启过。事实证明旧手机并不旧给它一段合适的代码它仍然能发挥相当大的价值。这套Android WiFi局域网监控方案从技术原理来说覆盖了Camera2、MediaCodec、RTSP/RTP三大块每一块单拆出来都是Android开发的硬核知识点串在一起就是一个能真正落地的产品。如果你手里也有一台吃灰的旧安卓手机不妨按照这个思路动手试试整个过程踩坑是必然的但当你第一次在电脑上看到手机镜头里的实时画面时那种成就感是任何模拟器都替代不了的。本文还有配套的精品资源点击获取