【Camera】准备的一些Camera面试题——相机预览、拍照流程(经验尚欠,待补充)
文章目录
- 一、相机预览流程
- 二、相机拍照流程
- 三、Linux驱动分为几类
- 四、简单介绍一下V4L2
一、相机预览流程
首先,我对Camera的软件架构理解是分层解耦的,从上至下主要包括:应用层、Framework层、HAL层、Kernel层和硬件层。
应用层负责交互逻辑。
Framework层提供标准的Camera2 API。
HAL层由芯片平台实现,承上启下,将上层的服务请求翻译成对底层硬件的操作。
Kernel层通过V4L2等框架封装硬件细节,是真正操作寄存器、控制硬件的部分
1、启动相机,APP通过Android Camera API向Camera Framework发起请求。配置一个或者多个OutputStream,例如用于预览的YUV流,并开始循环下发CaptureRequest。这些Request最终会传递到Camera HAL层。
2、HAL在收到configureStreams调用后,根据Request的配置(像分辨率、格式、帧数、3A参数)选择一条合适的Pipeline去处理sensor出图,例如预览用的Realtime Pipeline,HAL会通过Kernel Driver去配置和控制Sensor以及图像处理单元,HAL通过ioctl系统调用,驱动Kernel通过I2C发送命令给Sensor驱动,控制其上下电、初始化一些用于设置分辨率、帧率、曝光、增益等寄存器。Sensor将原始图像数据通过MIPI CSI接口传送到SOC,在接收到这些数据后进行解析。
3、图像数据在IFE进行一些前端处理,LSC,AWB,AE等。再进行后端处理,如降噪、锐化、YUV到RGB等,最终输出HAL所要求的格式。这部分很多是由ISP的固件完成的,驱动这边需要正确加载固件、配置相关寄存器
4、处理完成的图像数据buffer和metadata(3A统计信息和时间戳等)会通过HAL返回给Framework,Framework再将这些数据交给APP,APP通过Surface将图像数据送显,完成预览
驱动工作在这过程中要确保sensor正确出图,以及HAL通过Kernel Driver正确地配置和控制ISP Pipeline,保证图像的稳定性。
用户启动相机APP↓
APP配置OutputStream(如预览YUV流)↓
APP循环下发CaptureRequest↓
Framework传递Request到HAL↓
┌─────────────────────────────────┐
│ HAL层关键操作 │
├─────────────────────────────────┤
│ 1. configureStreams选择Pipeline │
│ - 根据分辨率/格式/帧率等参数 │
│ - 选择Realtime Pipeline │
│ │
│ 2. 通过ioctl控制Kernel Driver │
└─────────────────────────────────┘↓
┌─────────────────────────────────┐
│ Kernel驱动层执行 │
├─────────────────────────────────┤
│ 1. 配置Sensor │
│ - 通过I2C发送命令 │
│ - 控制上下电、初始化寄存器 │
│ - 设置分辨率/帧率/曝光/增益 │
│ │
│ 2. 启动MIPI CSI数据传输 │
└─────────────────────────────────┘↓
┌─────────────────────────────────┐
│ 硬件数据处理流 │
├─────────────────────────────────┤
│ Sensor → MIPI CSI → SOC │
│ ↓ │
│ ISP处理 │
│ ┌───────────────┐ │
│ │ 前端处理(IFE) │ │
│ │ - LSC │ │
│ │ - AWB │ │
│ │ - AE │ │
│ └───────────────┘ │
│ ↓ │
│ ┌───────────────┐ │
│ │ 后端处理(IPE) │ │
│ │ - 降噪 │ │
│ │ - 锐化 │ │
│ │ - 色彩空间转换│ │
│ └───────────────┘ │
└─────────────────────────────────┘↓
处理完成的Buffer + Metadata↓
HAL → Framework → APP↓
APP通过Surface送显↓
SurfaceFlinger合成显示↓
屏幕上看到预览画面
二、相机拍照流程
拍照流程和预览最大的不同在于需要处理高分辨率数据和多帧合成。
1、首先点击拍照后,APP根据拍照模式(拍照还是多帧)下发一个或多个高分辨率的Capture Request,这个Request的配置通过Framework传递到HAL,Request配置有最大分辨率、RAW/YUV格式,3A等信息。
2、HAL会为此创建一个Snapshot Pipeline,这个Pipeline可能与预览的Realtime Pipeline不同,它通过需要配置Sensor切换到更高的输出分辨率,并预览更大的内存buffer来承载高分辨率图像。
3、切换Sensor模式。HAL会通过Kernel Driver,使用I2C命令将Sensor从预览模式切换到全分辨率模式,这会改变Sensor的时钟、输出尺寸和帧率。
执行拍照。HAL会向Kernel下发一个高优先级的Request,用于捕获单帧或多帧。对于单帧拍照,流程与预览相似,但数据会走Snapshot Pipeline,生成一张高质量的YUV或者JPEG图像;对于多帧拍照,HAL会连续、快速地下发多个Request,驱动会控制Sensor和ISP,在极短时间内以不同的曝光值连续拍摄多张RAW或YUV图像。
4、捕获的多帧图像数据会返回到HAL,HAL会调用平台内置的硬件算法,像MFNR多帧降噪、HDR融合在DSP或者专用硬件上完成合成,这一块需要驱动正确配置相关硬件单元。处理完成后的一张高质量YUV图像会被送入硬件JPEG编码器。驱动需要确保JPEG编码器被正确初始化,并将YUV数据送入编码器,最终输出JPEG码流。
5、生成的JPEG文件流会通过HAL和Framework返回APP,最后由APP写入手机存储。
开始
|
v
[APP] 点击拍照,下发高分辨率CaptureRequest
|
v
[Framework] 传递Request到HAL
|
v
[HAL] 创建Snapshot Pipeline,配置Sensor切换模式(通过I2C命令)
|
v
[HAL] 下发高优先级Request给Kernel
|
v
[Kernel] 控制Sensor和ISP捕获图像(单帧或多帧)
|
v
[HAL] 接收图像数据,若多帧则进行硬件算法合成(MFNR/HDR)
|
v
[HAL] 将合成后的YUV送入硬件JPEG编码器
|
v
[HAL] 获取JPEG码流,返回给Framework
|
v
[APP] 接收JPEG码流并保存为文件
|
v
结束
用户点击拍照↓
APP下发高分辨率CaptureRequest↓
HAL创建Snapshot Pipeline↓
┌─────────────────────────────────┐
│ 驱动核心工作区 │
├─────────────────────────────────┤
│ 1. Sensor模式切换 │
│ - 通过I2C命令 │
│ - 预览模式 → 全分辨率模式 │
│ - 改变时钟/输出尺寸 │
│ │
│ 2. 图像捕获 │
│ ├─ 单帧拍照 → 走Snapshot管道 │
│ └─ 多帧拍照 → 不同曝光值连续拍│
│ │
│ 3. 图像处理与编码 │
│ - 配置硬件算法(MFNR/HDR) │
│ - 初始化JPEG编码器 │
│ - YUV → JPEG转换 │
└─────────────────────────────────┘↓
JPEG文件流返回APP↓
保存到手机存储
三、Linux驱动分为几类
字符设备——struct file_operations: 极其重要! 这里面填充了驱动实现的各种函数指针,如 .open, .read, .write, .release 等。这是驱动与内核的“契约”
块设备——struct request_queue: 核心! 管理读/写请求的队列。驱动需要从队列中取出请求 (struct request) 并处理。
四、简单介绍一下V4L2
V4L2是Linux内核的视频设备驱动框架,它的核心目标是统一和标准化视频设备的驱动接口。
我认为理解V4L2有几个关键点:
1、它是字符设备,App通过 /dev/videoX 节点来操作它。
2、它采用了模块化设计,特别是 v4l2_subdev 的概念,把复杂的相机硬件(如传感器、镜头、ISP)拆分成独立的子设备来管理,非常清晰。
3、对于现代手机Camera,Media Controller框架至关重要,它用来管理和配置传感器到ISP的整个内部数据链路。我们常用 media-ctl 命令来查看和调试这个链路。
(4、从应用流程上看,它围绕着 ‘申请缓冲区-启动流-取数据-还缓冲区’ 这个核心循环来工作。
在我之前调试Camera传感器时,如果图像出不来,我通常会先用 media-ctl -p 检查数据链路是否连通,然后用 v4l2-ctl 测试一下基本的图像采集和参数控制,最后再通过 dmesg 和 logcat 查看底层和上层的详细日志。)