super buffer 在 qcamera2\hal 层的使用
super buffer 是高通hal1中常用的概念,对应的数据结构是:mm_camera_super_buf_t
/** mm_camera_super_buf_t: super buf structure for bundled
* stream frames
* @camera_handle : camera handler to uniquely identify
* a camera object
* @ch_id : channel handler to uniquely ideentify a channel
* object
* @num_bufs : number of buffers in the super buf, should not
* exceeds MAX_STREAM_NUM_IN_BUNDLE
* @bufs : array of buffers in the bundle
**/
typedef struct {
uint32_t camera_handle;
uint32_t ch_id;
uint32_t num_bufs;
uint8_t bUnlockAEC;
uint8_t bReadyForPrepareSnapshot;
mm_camera_buf_def_t* bufs[MAX_STREAM_NUM_IN_BUNDLE];
} mm_camera_super_buf_t;
很明显mm_camera_super_buf_t 是由mm_camera_buf_def_t 组合而成。
其中 mm_camera_buf_def_t 是具体管理图像数据并且和v4l2交互的:
/** mm_camera_buf_def_t: structure for stream frame buf
* @stream_id : stream handler to uniquely identify a stream
* object
* @buf_idx : index of the buf within the stream bufs, to be
* filled during mem allocation
* @timespec_ts : time stamp, to be filled when DQBUF is
* called
* @frame_idx : frame sequence num, to be filled when DQBUF
* @plane_buf : Frame plane definition
* @fd : file descriptor of the frame buffer, to be filled
* during mem allocation
* @buffer : pointer to the frame buffer, to be filled during
* mem allocation
* @frame_len : length of the whole frame, to be filled during
* mem allocation
* @mem_info : user specific pointer to additional mem info
* @flags: v4l2_buffer flags, used to report error in data buffers
* @cache_flags: Stores cache related read/write flags
**/
typedef struct mm_camera_buf_def {
uint32_t stream_id;
cam_stream_type_t stream_type;
cam_stream_buf_type buf_type;
uint32_t buf_idx;
uint8_t is_uv_subsampled;
struct timespec ts;
uint32_t frame_idx;
union {
mm_camera_plane_buf_def_t planes_buf;
mm_camera_user_buf_def_t user_buf;
};
int fd;
void *buffer;
size_t frame_len;
void *mem_info;
uint32_t flags;
uint32_t cache_flags;
} mm_camera_buf_def_t;
super buffer广泛用于 stream 和 channel 的回调函数中:
图片源自高通开源代码QCamera2HWI.h
stream 和 channel 都需要 super buffer,他们不同之处在于:
- stream 回调用来处理实时性较强的场景:如Preview。
2.channel 回调用来处理 需要从多个 stream 中取出数据的任务,例如:Snapshot 场景会用到图像数据和metadata 数据。
这些回调函数拿到 super buffer 后会进一步会取出自己需要的子buffer(也就是上文中提到的mm_camera_buf_def_t* bufs[])。例如 Preview 回调中:
void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t *super_frame,
QCameraStream * stream,
void *userdata)
{
......
/*只需要取到预览buffer bufs[0] 就可以*/
QCameraGrallocMemory *memory = (QCameraGrallocMemory *)super_frame->bufs[0]->mem_info;
......
mm_camera_buf_def_t *frame = super_frame->bufs[0];
......
}
void QCamera2HardwareInterface::zsl_channel_cb(mm_camera_super_buf_t *recvd_frame,
void *userdata)
{
......
......
}
Snapshot 回调则毕竟复杂这里不做展开。
综上可见 super buffer 是用来给 stream 以及 channel 的回调函数提供统一接口。
super buffer 在 mm-camera-interface 层中的管理
上述回调函数会在 mm-camera-interface 中调用。也就是说 mm-camera-interface 会管理 super buffer 并且给这些回调函数传参。
阅读 mm_camera_channel.c 源码:
/*===========================================================================
* FUNCTION : mm_channel_superbuf_queue_init
*
* DESCRIPTION: initialize superbuf queue in the channel
*
* PARAMETERS :
* @queue : ptr to superbuf queue to be initialized
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue)
{
return cam_queue_init(&queue->que);
}
static inline int32_t cam_queue_init(cam_queue_t *queue)
{
pthread_mutex_init(&queue->lock, NULL);
cam_list_init(&queue->head.list);
queue->size = 0;
return 0;
}
可见 super buffer 是放在队列中管理。队列又是由链表实现。
高通代码很贴心的把 super buffer 的队列操作放在一起:
/* channel super queue functions */
int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_comp_and_enqueue(mm_channel_t *ch_obj,
mm_channel_queue_t * queue,
mm_camera_buf_info_t *buf);
mm_channel_queue_node_t* mm_channel_superbuf_dequeue(
mm_channel_queue_t * queue, mm_channel_t *ch_obj);
super buffer队列操作在下面函数中:
int32_t mm_channel_start(mm_channel_t *my_obj)
{
......
//队列初始化
mm_channel_superbuf_queue_init(&my_obj->bundle.superbuf_queue);
......
//使用下面两个函数来负责super buffer分发,填充,入队和出队
mm_camera_cmd_thread_launch(&my_obj->cb_thread,
mm_channel_dispatch_super_buf,
(void*)my_obj);
mm_camera_cmd_thread_launch(&my_obj->cmd_thread,
mm_channel_process_stream_buf,
(void*)my_obj);
......
}
其中大部分事件接收后的业务逻辑都放在 mm_channel_process_stream_buf 函数:
/*===========================================================================
* FUNCTION : mm_channel_process_stream_buf
*
* DESCRIPTION: handle incoming buffer from stream in a bundle. In this function,
* matching logic will be performed on incoming stream frames.
* Will depends on the bundle attribute, either storing matched frames
* in the superbuf queue, or sending matched superbuf frames to upper
* layer through registered callback.
*
* PARAMETERS :
* @cmd_cb : ptr storing matched super buf information
* @userdata: user data ptr
*
* RETURN : none
*==========================================================================*/
static void mm_channel_process_stream_buf(mm_camera_cmdcb_t * cmd_cb,
void *user_data)
{
......
if (MM_CAMERA_CMD_TYPE_DATA_CB == cmd_cb->cmd_type) {
/* comp_and_enqueue */
//mm_channel_superbuf_comp_and_enqueue 把buffer加入stream 队列中,再填充 组装
mm_channel_superbuf_comp_and_enqueue(
ch_obj,
&ch_obj->bundle.superbuf_queue,
&cmd_cb->u.buf);
......
/* dequeue */
//创建info对象用来储存buffer并且发给上层
mm_channel_node_info_t info;
......
// dequeue buffer 并且填充给 info
node = mm_channel_superbuf_dequeue_frame_internal(
ch_queue, match_frame);
if (node != NULL) {
info.ch_obj[info.num_nodes] = fs.ch_obj[j];
info.node[info.num_nodes] = node;
......
/* dispatch superbuf */
//将 info 发送出去
mm_channel_send_super_buf(&info);