android-camera-dev
Skill2 starsChanged 35 days agoMITView on GitHub
安卓相机采集与推流开发方法论:Camera2 多摄并发限制与降级、JPEG 直出/YUV 回退、DRI 重启标记归一化、JPEG_ORIENTATION 方向跟随、相机被驱逐自愈、HAL 卡死防护、资源战 dumpsys 分析、拍照产物元数据无损嵌入(EXIF/XMP)。真机实测(小米电视/工控板/OPPO/联想 Android 16 四类设备)。
In this repository21 other files it gives its agents.
- android-device-debuggingSkill
- arch-dev-workflowSkill
- async-job-sse-upload-devSkill
- branching-workflowSkill
- edge-offline-pipeline-devSkill
- frontend-dev-workflowSkill
- git-identitySkill
- installer-bundle-designSkill
- installer-preflightSkill
- installer-target-executionSkill
- mqtt-device-gateway-devSkill
- ohos-media-devSkill
- onvif-rtsp-devSkill
- open-source-contributionSkill
- redis-stream-rpcSkill
- robot-camerasSkill
- skill-distillationSkill
- skill-refreshSkill
- subagent-parallel-devSkill
- ui-responsive-listSkill
- user-facing-errorsSkill
The file
Files
安卓相机采集与推流开发方法论
1. 采集链路选择
- JPEG 直出优先(ImageReader + ImageFormat.JPEG,帧带 EXIF 可判来源);设备不支持时回退 YUV_420_888 软压缩(YuvImage→NV21,注意 rowStride/pixelStride 语义因机型而异)
- 带 DRI 重启标记的 JPEG 帧必须重编码归一化(标记扫描:SOS 前出现 0xFFDD 即中招)——RTP-JPEG 客户端普遍不支持重启标记,直发必绿屏;BitmapFactory→compress(Q85) 一并统一 Huffman 表、去 EXIF,代价约每帧 15-30ms
- 归一化判断要逐帧做(同设备不同分辨率模式可能不同),无 DRI 直通零开销
2. 多摄与并发
getConcurrentStreamingCameraIds()(API 30+)未声明组合的 HAL,框架只允许一 app 同时开一路——第二路 openCamera 报Too many cameras already open(REJECT)- 降级策略:全部相机按最大输出面积降序抢开,先开的高分辨率相机占住 ISP(即"默认分辨率最高");开启失败的路静默跳过,全败才算失败
- 用户选择:SharedPreferences 持久化相机编号(-1=自动),界面切换即管线重启
- ONVIF/状态页只广播真实在推流的相机,相机关闭即反注册;Profile token 与相机编号严格对应(profile_{N+1}↔N),切换不影响其他相机编号
3. 方向跟随
- 加速度传感器判定摆放:横放 0°/180°、竖放 90°/270°、平放保持上次(阈值:|a|>4 且主轴超副轴 2 倍)
- 用
CaptureRequest.JPEG_ORIENTATION让 HAL 直接转正像素,快照/MJPEG/RTSP 下游零感知(不依赖 EXIF 方向标签——RTSP 生态普遍无视它) - 公式:后摄
(sensorOrientation - displayRotation + 360) % 360;前摄镜像相反(sensorOrientation + displayRotation) % 360;前后摄 sensorOrientation 常见 90/270,必须 per-camera 计算 - 映射语义以后摄 orientation=90 真机校准(参考 ohos-ipcam-streamer OrientationSensor)
- 前摄分支必须单独真机校准:常见债是前摄公式按后摄外推从未验证——实测差 180° 时补
+180(与官方两步公式的(360-r)%360镜像补偿在该 case 等价);改动只碰前摄分支,别动已校准的后摄/手机路径 - 竖屏原生面板的 pad 横屏使用(
DisplayDeviceInfo尺寸 vs UI ROTATION_90 可判自然方向):suggest→display 映射仍按竖屏原生推导,但 x 轴符号对应两个横放方向,方向争议用实测数据链定案(dumpsys sensorservice读 accel 实时值 + 快照尺寸 + 用户目检倒向),不靠记忆推符号 - 会话中途转向后已连接的 RTSP 播放器不会跟随(沿用建连时尺寸)——用户报"横竖不对"先让他重连;验证输出方向用 HTTP 快照与 ffprobe 双路对比尺寸
4. 稳定性(真机血泪)
- openCamera 的 connectDevice binder 可能被卡死的 HAL 永久阻塞(OPPO 实测主线程 ANR)→ 相机启动必须放工作线程
- 相机被高优先级客户端 EVICT(看家应用/shell 特权抢占):onDisconnected/onError 即时自愈重开并重新入册;帧停滞 >6s 看门狗兜底;连续失败升级管线重启
- 管线重启走服务内存活方式(startService 带 extra,onStartCommand 重建内部资源)——不能 stopService+延迟 startService,应用跌入 cached 态后定制 ROM 会静默丢弃后台启动
- 相机 HAL 整体卡死后(所有 app 都连不上相机)唯一恢复手段是重启设备
- 息屏/后台强停对抗:前台服务+常驻通知是底线;ROM 级冻结(OPPO Hans)代码无解需用户加白
5. 诊断命令
# 相机资源战事件流:CONNECT/DISCONNECT/EVICT/REJECT 语义判抢占与并发限制
adb shell dumpsys media.camera | grep -E "CONNECT|DISCONNECT|EVICT|REJECT|concurrent"
# 主线程 ANR 栈(卡 connectDevice = HAL 卡死实锤)
adb shell dumpsys dropbox --print data_app_anr- JPEG 结构解剖是花屏/绿屏定位第一步(python 遍历 marker):SOF 尺寸与采样因子、有无 DRI、DHT 表数——对比好帧/坏帧的段差异直接锁定根因
- 像素级验证:解码后采样统计绿像素占比(G>90 且 G>1.5×max(R,B)),比肉眼客观
6. 拍照产物元数据无损嵌入
- JPEG 走 EXIF APP1(ImageDescription)+ XMP APP1 双通道,已存在的段一律不动;两槽都被相机占用时降级写 COM 段;PNG 用 eXIf chunk + IHDR 后的 tEXt
- 元数据缺失绝不能让拍照失败:任何不支持/畸形输入都返回原图不报错——元数据是增强项不是依赖项,采集链路对它零容忍度反过来(元数据写入失败 ≠ 拍照失败)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

