http://www.cnblogs.com/eustoma/archive/2012/05/24/2516830.html dump
转自 : http://blog.csdn.net/zirconsdu/article/details/8969749
ION 驱动文件路径: drivers/staging/android/ion/
ION将内核态形形色色的内存分配纳入统一的管理接口之中,更重要的设计意图是为内存在不同用户态进程之间传递和访问提供了支持。
每个ion_buffer与一个struct file关联,其handle纳入进程file desc空间而不是/dev/ion设备内单独的handle空间,方便之处如下:
每个buffer一个handle,便于更灵活地细粒度地控制每个buffer的使用周期;
向用户进程输出fd,细粒度地对每个buffer进行mmap;
使用struct file可以重用已有struct file_operations进行mmap;
在binder driver中以BINDER_TYPE_FD类型为不同进程传递提供支撑,并借助fget/fput从struct file级别进行kref控制;
当不需要在用户态访问时,是不需要与struct file关联的,内核结构ion_handle/ion_buffer唯一的表征了该buffer,所以与struct file关联的工作是在ioctl(ion, ION_IOC_SHARE/ION_ION_MAP, &share)中完成并输出的,用于后续的mmap调用;或者该进程不需要mmap而是仅仅向别的进程binder transfer,这就实现了用户态进行buffer流转控制,而内核态完成buffer数据流转。
ION概念:
ION是Google的下一代内存管理器,用来支持不同的内存分配机制,如CARVOUT(PMEM),物理连续内存(kmalloc), 虚拟地址连续但物理不连续内存(vmalloc), IOMMU等。
用户空间和内核空间都可以使用ION,用户空间是通过/dev/ion来创建client的。
说到client, 顺便看下ION相关比较重要的几个概念。
Heap: 用来表示内存分配的相关信息,包括id, type, name等。用struct ion_heap表示。
Client: Ion的使用者,用户空间和内核控件要使用ION的buffer,必须先创建一个client,一个client可以有多个buffer,用struct ion_buffer表示。
Handle: 将buffer该抽象出来,可以认为ION用handle来管理buffer,一般用户直接拿到的是handle,而不是buffer。 用struct ion_handle表示。
heap类型:
由于ION可以使用多种memory分配机制,例如物理连续和不连续的,所以ION使用enum ion_heap_type表示。
不同的type使用对应的分配memory函数。不同type的heap需要不同的method去分配,不过都是用struct ion_heap_ops来表示的。
- * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc
- * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
- * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved
- * carveout heap, allocations are physically
- * contiguous
- * @ION_HEAP_TYPE_IOMMU: IOMMU memory
- * @ION_HEAP_TYPE_CP: memory allocated from a prereserved
- * carveout heap, allocations are physically
- * contiguous. Used for content protection.
- * @ION_HEAP_TYPE_DMA: memory allocated via DMA API
Heap ID:
同一种type的heap上当然可以分为若该干个chunk供用户使用,所以ION又使用ID来区分了。例如在type为ION_HEAP_TYPE_CARVEOUT的heap上,audio和display部分都需要使用,ION就用ID来区分。
Heap id用enumion_heap_ids表示。
- ION_CAMERA_HEAP_ID = 20, /* 8660 only */
- ION_SF_HEAP_ID = 24,
- ION_IOMMU_HEAP_ID = 25,
ION Handle:
当Ion client分配buffer时,相应的一个唯一的handle也会被指定,当然client可以多次申请ion buffer。申请好buffer之后,返回的是一个ion handle, 不过要知道Ion buffer才和实际的内存相关,包括size, address等信息。Struct ion_handle和struct ion_buffer如下:
- * ion_handle - a client local reference to a buffer
- * @ref: reference count
- * @client: back pointer to the client the buffer resides in
- * @buffer: pointer to the buffer ---- 实际的内存相关
ION Client:
用户空间和内核空间都可以成为client,不过创建的方法稍稍有点区别,先了解下基本的操作流程吧。
内核空间:
先创建client:
<span style="color:#009900;">struct ion_client *ion_client_create(struct ion_device *dev,
unsigned int heap_mask,
const char *name)</span>
heap_mask: 可以分配的heap type,如carveout,system heap, iommu等。
高通使用msm_ion_client_create函数封装了下。
有了client之后就可以分配内存:
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
size_t align, unsigned int flags)
flags: 分配的heap id.
有了handle也就是buffer之后就准备使用了,不过还是物理地址,需要map:
unsigned long flags)
用户空间如果想使用ION,也必须先要创建client,不过它是打开/dev/ion,实际上它最终也会调用ion_client_create。
不过和内核空间创建client的一点区别是,用户空间不能选择heap type(使用预订的heap id隐含heap type),但是内核空间却可以。
另外,用户空间是通过IOCTL来分配内存的,cmd为ION_IOC_ALLOC.
<span style="color:#009900;">ion_fd = open("/dev/ion", O_ RDONLY | O_SYNC);
ioctl(ion_fd, <span style="color:#ff0000;">ION_IOC_ALLOC</span>, alloc); </span>
alloc为struct ion_allocation_data,len是申请buffer的长度,flags是heap id。
<span style="color:#009900;">/**
* struct ion_allocation_data - metadata passed from userspace for allocations
* @len: size of the allocation
* @align: required alignment of the allocation
* @flags: flags passed to heap
* @handle: pointer that will be populated with a cookie to use to refer
* to this allocation
*
* Provided by userspace as an argument to the ioctl
*/
struct ion_allocation_data {
size_t len;
size_t align;
unsigned int flags;
struct ion_handle *handle;
};</span>
分配好了buffer之后,如果用户空间想使用buffer,先需要mmap. ION是通过先调用IOCTL中的ION_IOC_SHARE / ION_IOC_MAP来得到可以mmap的fd,然后再执行mmap得到bufferaddress.
然后,你也可以将此fd传给另一个进程,如通过binder传递。在另一个进程中通过 ION_IOC_IMPORT 这个IOCTL来得到这块共享buffer了。
看看高通 camera HAL 实现的一个例子:
QCameraMemory::allocaOneBuffer(&memInfo , heap_id --> ION_HEAP (ION_CAMERA_HEAP_ID or ION_IOMMU_HEAP_ID) , size) ->一个buffer 一个buffer地分配
int main_ion_fd = open("dev/ion", R_RDONLY); 通过打开 ION 来创建 client
ioctl(main_ion_fd, ION_IOC_ALLOC,&alloc); 分配内存 , alloc 是 ion_allocation_data 类型,包含分配的 len align, m_bCached 信息
ioctl(main_ion_fd, ION_IOC_SHARE, &ion_info_fd); 得到ion_info_fd ,将 ion_info_fd.fd 保存到 memInfo.fd 中
void * vaddr = mmap(NULL, mMemInfo[i].size,PROT_READ | PROT_WRITE,MAP_SHARED,mMemInfo[i].fd,0); 执行 mmap 得到buffer的地址
mPtr[i] = vaddr; 将地址保存到每个stream (preview shapshot video metadata 等) 的私有成员中
在daemon 进程中通过下面操作得到这块buffer:
QCamera2HWI: [KPI Perf] static int qcamera::QCamera2HardwareInterface::start_preview(camera_device*): E PROFILE_START_PREVIEW -- 准备预览
QCamera2HWI: preparePreview: E mCameraId=0
HAL call mm_camera_add_channel() then mm_camera.c will call mm_channel_init()
QCamera2HWI: int32_t qcamera::QCamera2HardwareInterface::addZSLChannel(): add ZSL channel -- 添加通道
mm-camera-intf: mm_camera_add_channel:810] ch_idx = 0
mm-camera-intf: mm_channel_init : Launch data poll thread in channel open --- 添加数据 poll 线程,在打开设备的时候已经添加 poll 事件线程
mm-camera-intf: mm_camera_poll_thread_launch: poll_type = 1, read fd = 59, write fd = 60 timeout = -1
HAL add streamToChannel call allocateStreamInfoBuf(streamType) 申请内存保存buffer 信息
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): use reserved mm heap memory mBufferCount = 0 count = 1 new_bufCnt = 1 heap_id= 33554432 size = 912 --- 申请内存
QCameraHWI_Mem: Ion dev open success: main_ion_fd = 61 mbVdisOCRMode = 0
HAL call pChannel-> addStream()
mm-camera-intf: mm_camera_intf_add_stream : E handle = 1536 ch_id = 1792 --- 添加 stream 到通道
mm-camera-intf: mm_channel_add_stream : stream handle = 2048
QCameraStream: virtual int32_t qcamera::QCameraStream::init(qcamera::QCameraHeapMemory*, uint8_t, qcamera::stream_cb_routine, void*, bool) map_stream_buf INFO
HAL call map buf info: (只是映射刚刚申请到的buffer info,这里还没有申请buffer给数据)
mm_camera_intf_map_stream_buf :E camera_handle = 1536, ch_id = 1792, s_id = 2048, buf_idx = 0, plane_idx = -1
mm-camera-intf: mm_camera_map_stream_buf:1471 fd=62, size = 4096 buf_type = 3 buf_idx= 0stream_id=2048ch_id=1792 plane_idx = -1
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 3 fd = 62 stream_idx = 1 size = 4096 frame_idx = 0
mm_camera_socket_sendmsg:fd = 49 sendfd = 62 cmsg data=62 --- 通过socket 传送 fd = 49 到daemon
mm-camera: main: DS event call fd[0] = 30 ret = 1 -- server.c
mm-camera: server_process_hal_ds_packet:320,fd = 30 map buf_type =3 msg_fd = 42 stream_id = 1 size = 4096 frame_idx = 0 --- 读到的 fd = 42, 但是是没有关系的
mm-camera: mct_pipeline_map_buf , calling mct_stream mmap_buf msg->buf_type= 3 ---snapshot
mm-camera: mct_stream_map_buf: Mapping stream_info with mmap msg->fd = 42 msg->size = 4096
mm-camera: mct_pipeline_map_buf: OFFLINE_INPUT_BUF STREAM_INFO STREAM_BUF ,fd=42 size=4096 CHECK_INDEX = 0 msg->stream= 1 stream_id=1 frame_id = 0
mm-camera: main: PIPE event call fd[0] = 28 ret = 1 ---- MCT 操作结束
mm-camera: server_process_mct_msg:381, MCT_PROCESS_RET_SERVER_MSG mct_ret.u.serv_msg_ret.msg.msg_type = 0
mm-camera: main: return true,proc_ret.ret_to_hal.ret return type 1 ---- mmap 结束
mm-camera-intf: mm_camera_poll_fn: mm_camera_evt_notify i = 1 ---- 注册的poll 事件立即响应到
mm-camera-intf: mm_camera_event_notify:176] CAM_EVENT_TYPE_MAP_UNMAP_DONE
mm-camera-intf: mm_camera_util_sendmsg send success and sent size = 32 send_fd = 62 buf_size = 32 line = 1657
mm-camera-intf: mm_camera_intf_map_stream_buf :X rc = 0
HAL call config:
mm-camera-intf: mm_camera_intf_config_stream :mm_camera_intf_config_streamstream_id = 2048
mm-camera-intf: mm_channel_config_stream : E stream ID = 2048 -------设置回调及FMT
mm-camera-intf: mm_stream_fsm_acquired: E, my_handle = 0x800, fd = 63, state = 2 evt = 2
mm-camera-intf: mm_stream_config: E, my_handle = 0x800, fd = 63, state = 2
mm-camera-intf: mm_stream_set_fmt
mm-camera-intf: mm_stream_get_v4l2_fmt: fmt=78, val =0
以上是在 preparedPreview 中初始化一个channel ,并添加3个stream到channel 之后
QCamera2HWI: preparePreview: X mCameraId=0 ---------- QcameraStateMachine 调用
QCamera2HWI: startPreview: E mCameraId=0 ------------ QCameraStateMachine 调用
QCamera2HWI: startChannel: m_channels[ch_type], ch_type=0 --------启动channel,会涉及到 buffer 的申请
QCameraChannel: virtual int32_t qcamera::QCameraChannel::start(): E
mm-camera-intf: mm_camera_intf_get_bundle_info :E ch_id = 1792
QCameraChannel: QCameraChannel::start(): bundleInfo.num_of_streams=2 ---- metadata 不在bundle 里面,捆绑的只有preview 和 snapshot
QCameraChannel: virtual int32_t qcamera::QCameraChannel::start(): stream type =1 i = 0 stream_ids[i] = 2
mm-camera-intf: mm_camera_intf_set_stream_parms :E camera_handle = 1536,ch_id = 1792,s_id = 2305
QCameraChannel: virtual int32_t qcamera::QCameraChannel::start(): stream type =3 i = 1 stream_ids[i] = 3
mm-camera-intf: mm_camera_intf_set_stream_parms :E camera_handle = 1536,ch_id = 1792,s_id = 2562
mm-camera-intf: mm_camera_intf_set_stream_parms :E camera_handle = 1536,ch_id = 1792,s_id = 2305
mm-camera-sensor: sensor_util_bundle_list_print_traverse_func:504 bundle:num_streams=2
mm-camera-sensor: sensor_util_bundle_list_print_traverse_func:508 bundle:steram[0]=2
mm-camera-sensor: sensor_util_bundle_list_print_traverse_func:508 bundle:steram[1]=3
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:486 stream:bundle_id=1792
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:487 stream:identity=0x20002
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:488 stream:dim=1280x720 ----preview
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:489 ---------------------------------------------------------------
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:486 stream:bundle_id=1792
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:487 stream:identity=0x20003
mm-camera-sensor: sensor_util_stream_list_print_traverse_func:488 stream:dim=3264x1836 ---- snapshot
mm-camera: isp_util_set_bundle: stream_id = 2, stream_idx = 0, hal_bundling_mask= 0x1 --- 1 表示数据类型 review
mm-camera: isp_util_set_bundle: stream_id = 3, stream_idx = 1, hal_bundling_mask= 0x3 ---- 3 表示数据类型 snapshot
QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): E
W/QCameraChannel( 244): QCameraChannel::start(): bundleInfo.num_of_streams=2
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream type =1 i = 0 stream_ids[i] = 2
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream setParameter for set bundle success
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream type =3 i = 1 stream_ids[i] = 3
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream setParameter for set bundle success
上面主要是对捆绑在一起的 2个Stream 设置参数
QCameraChannel::start() 中调用 mSteams[i] -> start(); 不只是捆绑的stream,所有stream都调用,这里有3个(medadata preview snapshot)
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream[0]
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream[1]
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): stream[2]
E/QCameraChannel( 244): virtual int32_t qcamera::QCameraChannel::start(): X
主要是为了创建下面的线程: mProcTh.launch(dataProcRoutine, this); 三个stream (medadata preview snapshot) 都有一个自己的线程
QCameraStream: static void* qcamera::QCameraStream::dataProcRoutine(void*): E
QCameraStream: static void* qcamera::QCameraStream::dataProcRoutine(void*): E
QCameraStream: static void* qcamera::QCameraStream::dataProcRoutine(void*): E
然后调用m_camOps -> start_channel() , 先启动2个线程
mm-camera-intf: mm_camera_start_channel:1043] ch_id = 1792
mm-camera-intf: mm_channel_start:num_streams_to_start = 3
mm-camera-intf: mm_camera_cmd_thread_launch:532 -------mm_camera_cmd_thread_launch(mm_channel_dispatch_super_buf)
--------------主要用于调用 mm_channel_init() 时设置的 my_obj->bundle.super_buf_notify_cb = channel_cb 对应 QC2HWICB 中的 zsl_channel_cb() 回调函数
mm-camera-intf: mm_camera_cmd_thread_launch:532 -------mm_camera_cmd_thread_launch(mm_channel_process_stream_buf)
-------------- 主要用于 ZSL 拍照 -> mm_camera.c -> mct_pipeline.c -> module_sensor.c
然后根据 stream 的数量 (共3个),分别依次进行 allocate buf 分配内存, reg buf 邀请kernel分配内存并注册到kernel, start stream 开启数据流 操作
1. metadata ---20 buffers
1.1 allocat buf
mm-camera-intf: mm_stream_init_bufs: E, my_handle = 0x800, fd = 63, state = 3
QCameraStream: getBufs: [MEM_DBG] Enter: mDynBufAlloc: 0 numBufAlloc = 20
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): use reserved mm heap memory mBufferCount = 0 count = 20 new_bufCnt = 20 heap_id= 33554432 size = 286420
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): start use iommu sys heap memory : 0
QCameraHWI_Mem: Ion dev open success: main_ion_fd = 70 mbVdisOCRMode = 0
QCameraHWI_Mem: size before align: 286420 0x45ed4
QCameraHWI_Mem: size after align: 286720 0x46000
.....
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): use reserved mm heap memory mBufferCount = 0 count = 20 new_bufCnt = 20 heap_id= 33554432 size = 286420
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): start use iommu sys heap memory : 19
上面共调用20次,申请20 个buffer用于 metadata 数据,申请完同一个stream 所有buffer 之后调用 map_buf 函数映射到 daemon
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 2 fd = 71 stream_idx = 1 size = 286720 frame_idx = 0
mm-camera-intf: mm_camera_socket_sendmsg:fd = 49 sendfd = 71 cmsg data=71
mm-camera: server_process_hal_ds_packet:320,fd = 30 map buf_type =2 msg_fd = 45 stream_id = 1 size = 286720 frame_idx = 0
mm-camera: mct_pipeline_map_buf , calling mct_stream mmap_buf msg->buf_type= 2
mct_stream_create_buffers: Mapping msg->fd = 45 msg->size = 286720 num plane --- 1
.......
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 2 fd = 109 stream_idx = 1 size = 286720 frame_idx = 19
mm-camera-intf: mm_camera_socket_sendmsg:fd = 49 sendfd = 109 cmsg data=109
mm-camera: main: DS event call fd[0] = 30 ret = 1
mm-camera: server_process_hal_ds_packet:320,fd = 30 map buf_type =2 msg_fd = 64 stream_id = 1 size = 286720 frame_idx = 19
mm-camera: mct_pipeline_map_buf , calling mct_stream mmap_buf msg->buf_type= 2
mm-camera: mct_stream_create_buffers: Mapping msg->fd = 64 msg->size = 286720 num plane --- 1
mm-camera: main: PIPE event call fd[0] = 28 ret = 1--- MCT 操作完成
mm-camera: server_process_mct_msg:413,msg->session = 2 msg->stream = 1 msg->index = 19 (unsigned int)msg->buf_type = 2
mm-camera: main: return true,proc_ret.ret_to_hal.ret return type 1
mm-camera-intf: mm_camera_poll_fn: mm_camera_evt_notify i = 1
mm-camera-intf: mm_camera_event_notify:176] CAM_EVENT_TYPE_MAP_UNMAP_DONE ---- evt poll camera.c 返回
mm-camera-intf: mm_camera_util_sendmsg send success and sent size = 32 send_fd = 109 buf_size = 32 line = 1657
1.2 reg to kernel
映射完之后向kernel申请buffer,并注册到kernel
mm-camera-intf: mm_stream_request_buf: buf_num = 20, stream type = 7
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=2048,fd=71,frame idx=0,num_planes = 1, offset = 0, data_offset = 0 ----- 只有一个 plane
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=2048,fd=71,frame idx=0,num_planes = 1, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_reg_buf: VIDIOC_QBUF rc = 0 buf_num = 20
循环调用 ioctl(VIDIOC_QBUF) 20 次
1.3
mm-camera-intf: mm_camera_cmd_thread_launch:532 --- mm_camera_cmd_thread_launch(mm_stream_dispatch_app_data) --- 打开一个poll data 线程
mm-camera-intf: mm_stream_streamon: E, my_handle = 0x800, fd = 63, state = 6 -->ioctl(VIDIOC_STREAMON)
mm-camera-intf: mm_camera_poll_thread_add_poll_fd: handler 2048 (0) poll_cb->type = 1 ----> mm_camera_poll_thread_add_poll_fd(mm_stream_data_notify) ->
----------- 通过这里调用 mm_stream_read_msm_frame() -> ioctl(VIDIOC_DQBUF) , mm_stream_handle_rcvd_buf() 在里面做判断,
如果 is_bunfled 为真:
则先将数据进队到 my_obj->cmd_thread.cmd_queue , 并释放 my_obj->ch_obj->cmd_thread.cmd_sem 信号到 mm_camera_thread.c -> mm_camera_channel.c
否则直接进队到 my_obj->cmd_thread.cmd_queue ,然后释放 my_obj->cmd_thread.cmd_sem信号
mm-camera-intf: mm_camera_poll_proc_pipe: read_fd = 59, read_len = 12, expect_len = 12 cmd = 0
mm-camera-intf: mm_camera_poll_sig: begin IN mutex write done, len = 12
2.preview -- 10 buffers
2.1--allocat buffer
QCameraHWI_Mem: DBG_PATCH:void qcamera::QCameraGrallocMemory::setWindowInfo(preview_stream_ops_t*, int, int, int) mWindow=0xb88550f0
CameraHWI_Mem: virtual int qcamera::QCameraGrallocMemory::allocate(int, int): usage = 1073872896, geometry: 0xb88550f0, 1280, 720, 17
QCameraHWI_Mem: virtual int qcamera::QCameraGrallocMemory::allocate(int, int): idx = 0, fd = 132, size = 1384448, offset = 0
....
QCameraHWI_Mem: virtual int qcamera::QCameraGrallocMemory::allocate(int, int): idx = 9, fd = 169, size = 1384448, offset = 0
2.2 map buffer to daemon
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 2 fd = 132 stream_idx = 2 size = 1384448 frame_idx = 0
mm-camera: server_process_hal_ds_packet:320,fd = 30 map buf_type =2 msg_fd = 65 stream_id = 2 size = 1384448 frame_idx = 0
mm-camera: mct_stream_create_buffers: Mapping fuhao msg->fd = 65 msg->size = 1384448 num plane --- 2 --- plane 存储形式
.....
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 2 fd = 169 stream_idx = 2 size = 1384448 frame_idx = 9
mm-camera: server_process_hal_ds_packet:320,fd = 30 map buf_type =2 msg_fd = 75 stream_id = 2 size = 1384448 frame_idx = 9
mm-camera: mct_stream_create_buffers: Mapping fuhao msg->fd = 75 msg->size = 1384448 num plane --- 2 ----- plane = 2, Y 一个plane, UV 一个plane,二维
mm-camera: mct_stream_map_buf: Mapping stream_buf with mmap msg->fd = 75 msg->size = 1384448
2.3
映射完了之后邀请kernel 申请buffer,并注册到kernel
mm-camera-intf: mm_stream_request_buf: buf_num = 10, stream type = 1
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=2305,fd=137,frame idx=1,num_planes = 2, offset = 0, data_offset = 0 ------ preview , snapshot 都有2个plane
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=2305,fd=137,frame idx=1,num_planes = 2, offset = 921600, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=2305,fd=141,frame idx=2,num_planes = 2, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=2305,fd=141,frame idx=2,num_planes = 2, offset = 921600, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=2305,fd=169,frame idx=9,num_planes = 2, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=2305,fd=169,frame idx=9,num_planes = 2, offset = 921600, data_offset = 0
进队到kernel完之后,打开一个线程,打开数据流
mm-camera-intf: mm_camera_cmd_thread_launch:532 ----mm_stream_dispatch_app_data() --- poll 到数据后就会调用这个函数
----mm_camera_cmd_thread_launch() ->
cmd_thread->cb = mm_stream_dispatch_app_data, 然后在 mm_camera_cmt_thread() 中接收到cmd_thread->cmd_sem 信号之后调用 cmd_thread->cb() ,
即调到 mm_stream_dispatch_app_data() 函数中,再在这个函数中根据user_data 调用HAL实现的 每个不同stream 的回调函数
mm-camera-intf: mm_stream_streamon: E, my_handle = 0x901, fd = 66, state = 6
mm-camera-intf: mm_camera_poll_thread_add_poll_fd: handler 2305 (1) poll_cb->type = 1
mm-camera-sensor: module_sensor_module_process_event:3936 E STATEDBG MCT_EVENT_CONTROL_STREAMON
mm-camera-sensor: port_sensor_handle_stream_on:505 type 1 ide 20002 w 1280 h 720 stream on 0
3. snapshot -- 3 buffers (另外 6个buffer 动态需要的时候申请)
3.1 allcate buffers
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): use reserved mm heap memory mBufferCount = 0 count = 3 new_bufCnt = 3 heap_id= 33554432 size = 9011200
QCameraHWI_Mem: int qcamera::QCameraMemory::alloc(int, int, int): start use iommu sys heap memory : 0
QCameraHWI_Mem: Ion dev open success: main_ion_fd = 171 mbVdisOCRMode = 0
QCameraHWI_Mem: size before align: 9011200 0x898000
QCameraHWI_Mem: size after align: 9011200 0x898000
QCameraStream: getBufs: [MEM_DBG] frame_len: 9011200, numBufAlloc: 3 ---------只分配3个buffer,剩下6个动态分配
QCameraStream: getBufs: [MEM_DBG] All mNumBufs: 9
3.2 map buf
mm-camera-intf: mm_camera_socket_sendmsg:fd = 49 sendfd = 172 cmsg data=172
mm-camera: server_process_hal_ds_packet:320,fd = 30 map buf_type =2 msg_fd = 76 stream_id = 3 size = 9011200 frame_idx = 0
mm-camera: mct_pipeline_map_buf , calling mct_stream mmap_buf msg->buf_type= 2
mm-camera: mct_stream_create_buffers: Mapping fuhao msg->fd = 76 msg->size = 9011200num plane --- 2
mm-camera: mct_stream_create_buffers: plane idx = 0, offset 0, stride 3264, scanline = 1840
mm-camera: mct_stream_create_buffers: plane idx = 1, offset 0, stride 3264, scanline = 920
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 2 fd = 174 stream_idx = 3 size = 9011200 frame_idx = 1
mm-camera: server_process_mct_msg:413,msg->session = 2 msg->stream = 3 msg->index = 1 (unsigned int)msg->buf_type = 2
mm-camera-intf: mm_stream_map_buf: MAP BUF buf_type = 2 fd = 176 stream_idx = 3 size = 9011200 frame_idx = 2
mm-camera: main: return true,proc_ret.ret_to_hal.ret return type 1
mm-camera-intf: mm_camera_poll_fn: mm_camera_evt_notify i = 1
mm-camera-intf: mm_camera_event_notify:176] CAM_EVENT_TYPE_MAP_UNMAP_DONE ------- daemon mmap 完成,向HAL层返回相应消息
mm-camera-intf: mm_camera_util_sendmsg send success and sent size = 32 send_fd = 176 buf_size = 32 line = 1657
3.3 REG buffer to kernel
mm-camera-intf: mm_stream_request_buf: buf_num = 9, stream type = 3
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=2562,fd=172,frame idx=0,num_planes = 2, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=2562,fd=172,frame idx=0,num_planes = 2, offset = 6005760, data_offset = 0
mm-camera-intf: mm_stream_qbuf: qbuf idx:0, rc:0
....
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=2562,fd=176,frame idx=2,num_planes = 2, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=2562,fd=176,frame idx=2,num_planes = 2, offset = 6005760, data_offset = 0
mm-camera-intf: mm_stream_qbuf: qbuf idx:2, rc:0
mm-camera-intf: mm_stream_reg_buf: VIDIOC_QBUF rc = 0 buf_num = 9
只注册 3个buffer到kernel ,下面运行一个线程
mm-camera-intf: mm_camera_cmd_thread_launch:532 --- mm_stream_dispatch_app_data() ---- mm_camera_thread.c poll 返回数据后都会调用这个函数
mm-camera-intf: mm_stream_streamon: E, my_handle = 0xa02, fd = 69, state = 6
-------------------------------------------------------------------------------------------------------------------
mm_camera_poll_thread_add_poll_fd 只有3个地方,一个是mm_camera_thread.c 实现,一个在 mm_camera.c 做evt poll,一个在 mm_camera_stream.c 做data poll
--- 调用 mm_camera_poll_thread_add_poll_fd(&my_obj->ch_obj->poll_thread[0],mm_stream_data_notify, ) --------- 用于poll 每个stream 的data
---mm_camera_evt_sub() -> mm_camera_poll_thread_add_poll_fd(my_obj->evt_poll_thread, mm_camera_event_notify) ----------- 用于 poll evt ,主要是daemon返回的
-------------------------------------------------------------------------------------------------------------------
mm-camera-intf: mm_camera_poll_thread_add_poll_fd: fuhao handler 2562 (2) poll_cb->type = 1
mm-camera: isp_ch_util_dump_channel_planes: sess_id = 2, channel_id = 2, width = 1280, height = 720, fmt = 2, num_planes = 2
mm-camera: isp_ch_util_dump_channel_planes: sess_id = 2, channel_id = 2, idx = 0,stride = 1280, scanline = 720, len = 921600, offset = 0
mm-camera: isp_ch_util_dump_channel_planes: sess_id = 2, channel_id = 2, idx = 1,stride = 1280, scanline = 360, len = 460800, offset = 0
mm-camera: isp_ch_util_convert_crop_to_stream: identy = 0x20003, first_pix = NaNirst_line - -3408, width = 1224, height = 688x = 816, y = 459, crop_x = -1333745164, crop_y = -1231138568
mm-camera: isp_ch_util_convert_crop_to_stream: identy = 0x20003, first_pix = NaNirst_line - -3408, width = 1224, height = 688x = 816, y = 459, crop_x = 1, crop_y = -1231119716
对应 preview log:
mm-camera-intf: mm_camera_poll_fn: mm_stream_data_notify i = 2 -------- 每一个 stream都设置的一个回调函数,处理 poll返回 data的情况
mm-camera-intf: mm_stream_data_notify: E, my_handle = 0x401, fd = 65, state = 6 ---- 调用 mm_stream_read_msm_frame & mm_stream_handle_rcvd_buf
mm-camera-intf: mm_stream_read_msm_frame: E, my_handle = 0x401, fd = 65, state = 6 ----获取 frame
mm-camera-intf: mm_stream_read_msm_frame: VIDIOC_DQBUF buf_index 4, frame_idx 74,stream type 1, time stamp 64 236973000 vb.lengh = 2 ----- 1表示preview
mm-camera-intf: mm_stream_read_msm_frame :X rc = 0
mm-camera-intf: mm_stream_handle_rcvd_buf: E, my_handle = 0x401, fd = 65, state = 6 ----- 释放my_obj->ch_obj->cmd_thread.cmd.sem 信号
mm-camera-intf: mm_channel_process_stream_buf:206] type 0 ---- 通过mm_camera_cmd_thread_lauch()创建的线程,也是channel 等待 cmd_sem 信号
mm-camera-intf: mm_channel_superbuf_comp_and_enqueue: E -----super buf E
mm-camera-intf: mm_channel_handle_metadata: Stream Object for stream_id = 1025
mm-camera-intf: mm_channel_superbuf_comp_and_enqueue: X --- super buf X
mm-camera-intf: mm_channel_superbuf_bufdone_overflow: before match_cnt=3, water_mark=2
mm-camera-intf: mm_stream_fsm_fn: E, my_handle = 0x300, fd = 62, state = 6 evt = 9
mm-camera-intf: mm_stream_fsm_active: E, my_handle = 0x300, fd = 62, state = 6 evt = 9
mm-camera-intf: mm_stream_buf_done: E, my_handle = 0x300, fd = 62, state = 6 frame_idx=72
mm-camera-intf: <DEBUG> : Buf done for buffer:7 stream type=7
mm-camera-intf: mm_stream_qbuf: E, my_handle = 0x300, fd = 62, state = 6
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=768,fd=84,frame idx=7,num_planes = 1, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=768,fd=84,frame idx=7,num_planes = 1, offset = 0, data_offset = 0
mm-camera-intf: mm_stream_qbuf: qbuf idx:7, rc:0
mm-camera-intf: mm_stream_fsm_active :X rc = 0
mm-camera-intf: mm_stream_fsm_fn : X rc =0
mm-camera-intf: mm_stream_fsm_fn: E, my_handle = 0x401, fd = 65, state = 6 evt = 9
mm-camera-intf: mm_stream_fsm_active: E, my_handle = 0x401, fd = 65, state = 6 evt = 9
mm-camera-intf: mm_stream_buf_done: E, my_handle = 0x401, fd = 65, state = 6 frame_idx=72
mm-camera-intf: <DEBUG> : Still ref count pending count :1
mm-camera-intf: <DEBUG> : for buffer:0xb8854c1c:9 stream type=1
mm-camera-intf: mm_stream_fsm_active :X rc = 0
mm-camera-intf: mm_stream_fsm_fn : X rc =0
mm-camera-intf: mm_stream_fsm_fn: E, my_handle = 0x502, fd = 68, state = 6 evt = 9
mm-camera-intf: mm_stream_fsm_active: E, my_handle = 0x502, fd = 68, state = 6 evt = 9
mm-camera-intf: mm_stream_buf_done: E, my_handle = 0x502, fd = 68, state = 6 frame_idx=72
mm-camera-intf: <DEBUG> : Buf done for buffer:5 stream type=3
mm-camera-intf: mm_stream_qbuf: E, my_handle = 0x502, fd = 68, state = 6
mm-camera-intf: mm_stream_qbuf:plane 0: stream_hdl=1282,fd=184,frame idx=5,num_planes = 2, offset = 0, data_offset = 0
D al_algo0: [awb_al_process_rear] bv:lock:led_est_state:aec_settled:use_led_estimation:0.340306,0,0,0,0
mm-camera-intf: mm_stream_qbuf:plane 1: stream_hdl=1282,fd=184,frame idx=5,num_planes = 2, offset = 6005760, data_offset = 0
mm-camera-intf: mm_stream_qbuf: qbuf idx:5, rc:0
mm-camera-intf: mm_stream_fsm_active :X rc = 0
mm-camera-intf: mm_stream_fsm_fn : X rc =0
mm-camera-intf: mm_channel_superbuf_bufdone_overflow: after match_cnt=2, water_mark=2
mm-camera-intf: mm_channel_process_stream_buf: Super Buffer received, pending_cnt=0
mm-camera-intf: mm_stream_dispatch_app_data: E, my_handle = 0x401, fd = 65, state = 6 ---- mm_camera_stream.c,也是在在mm_stream_handle_rcvd_buf中调用
mm-camera-intf: mm_stream_dispatch_app_data: i = 0 cmd_type (0) for dataCB ------- > 回调到 HAL层
QCameraStream: static void qcamera::QCameraStream::dataNotifyCB(mm_camera_super_buf_t*, void*):
QCameraStream: virtual int32_t qcamera::QCameraStream::processDataNotify(mm_camera_super_buf_t*):----- HAL 回调都是用这个注册,根据不同 stream 对象调用
mm-camera-intf: mm_stream_buf_done: E, my_handle = 0x401, fd = 65, state = 6 frame_idx=74
mm-camera-intf: <DEBUG> : Still ref count pending count :2
mm-camera-intf: <DEBUG> : for buffer:0xb8854c1c:4 stream type=1
QCameraStream: static void* qcamera::QCameraStream::dataProcRoutine(void*): Do next job
QCamera2HWI: [KPI Perf] static void qcamera::QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t*, qcamera::QCameraStream*, void*) : E BEGIN
-------------------------------------------------------- 以上是 Preview 的回调流程,下面重现整理一下回调函数的注册和调用 ------------------------------------------------------
mm_camera_cmd_thread_launch (mm_camera_cmd_thread_t *, mm_camera_cmd_cb_t , void* user_data) -- 参数包含线程,回调函数,用户所有者
一共有四个地方调用 -> 通过 pthread_create 创建 mm_camera_cmd_thread() 线程:
1.mm_camera_channel --2次调用 都是在 channel start 的时候调用:
1.1launch cb thread for dispatching super buf through cb -> ( my_obj->cb_thread() ,mm_channel_dispatch_super_buf() ,(void*) my_obj ----mm_channel_t )
1.2launch cmd thread for super buf dataCB -> -> my_obj->cmd_thread (mm_channel_t),mm_channel_process_stream_buf() ,(void*) my_obj ----mm_channel_t )
第二个回调函数是在mm_stream_handle_rcvd_buf 中通过释放 (my_obj->ch_obj->cmd_thread.cmd_sem)来唤醒,并把相关frame 保存到队列 super buffer
第一个回调函数是在mm_channel_process_stream_buf() 中调用
mm-camera-intf: mm_channel_process_stream_buf: Super Buffer received, pending_cnt=0
mm-camera-intf: mm_camera_cmd_thread:node->cmd_type = 3 call cb ---------- 命令是 MM_CAMERA_CMD_TYPE_REQ_DATA_CB
mm-camera-intf: mm_channel_process_stream_buf:206] type 3
mm-camera-intf: mm_channel_process_stream_buf:216] pending cnt 1 ------- 大于0,可以调用 mm_channel_dispatch_super_buf()
mm-camera-intf: mm_channel_process_stream_buf: takePicture called to mm-camera-interface
mm-camera-intf: mm_channel_superbuf_bufdone_overflow: before match_cnt=2, water_mark=2
mm-camera-intf: mm_channel_superbuf_bufdone_overflow: after match_cnt=2, water_mark=2
mm-camera-intf: mm_channel_process_stream_buf: Super Buffer received, pending_cnt=1
mm-camera-intf: mm_channel_process_stream_buf: Super Buffer received, Call client callback, pending_cnt=1
mm-camera-intf: mm_channel_process_stream_buf:314] received all frames requested, send takepicturedone
mm-camera-intf: mm_channel_process_stream_buf: Send superbuf to HAL, pending_cnt=0 frame_idx=265 ------ 发送 ch_obj->cb_thread.cmd_sem 信号
mm-camera-intf: mm_camera_cmd_thread:node->cmd_type = 4 call cb
mm-camera-intf: mm_channel_dispatch_super_buf:169] type 4 --------- 收到信号,处理回调 在拍照情况会调用,录像、预览及录像时拍照都不会调用
QCamera2HWI: [KPI Perf] zsl_channel_cb: E ---------- mm_channel_dispatch_super_buf() 会调用 super_buf_notify_cb,该指针是在mm_channel_init 的时候初始化
初始化的值就是 HAL层实现的 回调函数zsl_channel_cb ,这里没有经过stream 通用的回调函数,直接调用
QCamera2HWI: [KPI Perf] static void qcamera::QCamera2HardwareInterface::zsl_channel_cb(mm_camera_super_buf_t*, void*): superbuf frame_idx 265 recvd_frame->num_bufs = 3
QCamera2HWI: zsl_channel_cb:109] ###[LED_FLASH_DBG] (buf idx, frame idx, type) (2 265 7) (7 265 1) (0 265 3)
QCamera2HWI: zsl_channel_cb : start post process~
QCamera2HWI: bool qcamera::QCamera2HardwareInterface::needReprocess(): need do reprocess for ZSL WNR or min PP reprocess ----------发送到 CPP
QCameraPostProc: processData: need reprocess
QCamera2HWI: [KPI Perf] zsl_channel_cb : X
QCameraPostProc: dataProcessRoutine: Do next job, active is 1
2.mm_camera_stream.c -- 1 次调用 ,mm_stream_fsm_reg () {MM_STREAM_EVT_START} 时候注册回调函数,注册完后调用mm_stream_streamon() 打开数据流
2.1 mm_camera_cmd_thread_luanch(&my_obj->cmd_thread,mm_stream_dispatch_app_data,(void*) my_obj --- mm_stream_t ) ;
2.2 mm_stream_streamon 函数 通过mm_camera_poll_thrad_add_pol_fd(my_obj->ch_obj->poll_thread[0] , , ,mm_stream_data_notify , (void*)my_obj) 添加监听
每一个数据流有一个监听,他们存在于不同的线程中,当 mm_camera_poll_fn (mm_camera_thrad.c) 查询到data 消息后调用 mm_stream_data_notify() ->
mm_stream_read_msm_frame() 读取帧数据 , mm_stream_handle_rcvd_buf() 处理帧数据,这个函数会释放2个信号my_obj->ch_obj->cmd_thread.cmd_sem和
my_obj->cmd_thread.cmd_sem 分别唤醒 mm_channel_process_stream_buf 和 mm_stream_dispatch_app_data (因为在QCamera2HWI 中只注册preview 和
metadata 数据类型的处理 , snapshot 是在 pChannel->init() 的时候就调用,因此这里不处理 snaphot 的回调,其另行处理,可以查看上面 )
3. mm_camera.c -1次调用在mm_camera_open 的时候创建,并添加事件的轮询
Launch evt thread in Cam Open------>mm_camera_cmd_thread_launch(my_obj->evt_thread,mm_camera_dispatch_app_event,(void*) my_obj) -- 创建事件回调分发线程
Launch evt poll thread in cam open ---> mm_camera_poll_thread_launch(my_obj->evt_poll_thread, M_CAMERA_POLL_TYPE_EVT) -------- 创建事件轮询线程
mm_camera_evt_sub(my_onj ,true) -- > ioctl(VIDIOC_UNSUBSCRIBE_EVENT ) 注册监听到kernel , mm_camera_poll_thread_add_poll_fd(mm_camera_event_notify)
添加轮询返回事件的处理,这个函数会获取kernel事件,然后调用分发的回调函数,再调用到HAL的事件回调处理函数,主要处理 daemon 返回的事件。
来看一个例子:
进程A:
int ionfd = open("/dev/ion", O_RDONLY | O_DSYNC);
alloc_data.len = 0x1000;
alloc_data.align = 0x1000;
alloc_data.flags = ION_HEAP(ION_CP_MM_HEAP_ID);
rc = ioctl(ionfd,ION_IOC_ALLOC, &alloc_data);
fd_data.handle = alloc_data.handle;
rc = ioctl(ionfd,ION_IOC_SHARE,&fd_data);
shared_fd = fd_data.fd;
进程B:
fd_data.fd = shared_fd;
rc = ioctl(ionfd,ION_IOC_IMPORT,&fd_data);