代码路径
主要代码路径如下:
android/android-emu/android/camera/camera-service.cpp
android/android-emu/android/camera/camera-capture-cloud.cpp
android/android-emu/android/camera/camera-format-converters.c
初始化
代码路径:android/android-emu/android/camera/camera-service.cpp
android_camera_service_init
---_camera_service_init 初始化摄像头
---qemud_service_register 在qemu中注册服务名为camera的服务, camera service的descriptor, camera service的连接函数
---_camera_service_connect
void android_camera_service_init(void) {
static int _inited = 0;
if (!_inited) {
_camera_service_init(&_camera_service_desc);
QemudService* serv = qemud_service_register( SERVICE_NAME, 0,
&_camera_service_desc,
_camera_service_connect,
NULL,
NULL);
....
}
}
_camera_service_init
传进参数:CameraServiceDesc* csd
主要是填充camera service的descriptor CameraServiceDesc相关字段,初始化前后摄像头
--_virtualscenecamera_setup_back
--_virtualscenecamera_setup_front
static void _camera_service_init(CameraServiceDesc* csd)
{
...
_virtualscenecamera_setup_back(csd);
_virtualscenecamera_setup_front(csd);
...
}
_camera_service_connect
---camera_cloud_device_init 在camera-capture-cloud.cpp中实现
---_camera_client_create、qemud_client_new 如果client_param为空,直接调用qemud_client_new在qemu中添加camera factory 客户端,数据接收函数_factory_client_recv。
否则,根据传进来的client参数,调用_camera_client_create创建摄像头客户端,调用qemud_client_new在qemu中添加此客户端,数据接收函数_camera_client_recv。
static QemudClient*
_camera_service_connect(void* opaque,
QemudService* serv,
int channel,
const char* client_param)
{
...
#if FIXED_CAMERA_WITH_VIRTUALSCENE == 1
camera_cloud_device_init();
#endif
if (client_param == NULL || *client_param == '\0') {
/* This is an emulated camera factory client. */
client = qemud_client_new(serv, channel, client_param, csd,
_factory_client_recv, _factory_client_close,
NULL, NULL);
} else {
/* This is an emulated camera client. */
CameraClient* cc = _camera_client_create(csd, client_param);
if (cc != NULL) {
client = qemud_client_new(serv, channel, client_param, cc,
_camera_client_recv, _camera_client_close,
_camera_client_save, _camera_client_load);
}
}
return client;
}
camera_cloud_device_init
代码路径:android/android-emu/android/camera/camera-capture-cloud.cpp
主要是注册 spice回调摄像头的接口,摄像头插入、摄像头拔出、摄像头数据传输、摄像头信息清除回调函数
void camera_cloud_device_init() {
mCameraIndex = 0;
mbIsNeedCapture = false;
if (mCamInterface == NULL) {
printf("[camera] %s %d: new camera instrface\n", __func__, __LINE__);
mCamInterface = new SpiceCameraInterface();
}
mCamInterface->context = NULL;
mCamInterface->camera_plug = cameraPlugCallback;
mCamInterface->camera_unplug = cameraUnplugCallback;
mCamInterface->camera_data = cameraDataCallback;
mCamInterface->camera_clear = cameraInfoClearCallback;
RedsState *reds = (RedsState*)spice_server_get();
spice_server_set_camera_interface(reds, mCamInterface);
}
_camera_client_create
---_camera_service_get_camera_info_by_device_name 根据传进来的param的摄像头设备名字,获取摄像头相关信息
---注册摄像头操作函数。这些函数在camera-capture-cloud.cpp中实现
camera_cloud_device_open、camera_cloud_device_close:摄像头打开和关闭
camera_cloud_device_start_capturing、camera_cloud_device_stop_capturing:摄像头开始和停止capturing
camera_cloud_device_read_frame:读取摄像头数据帧的函数
camera_cloud_device_setFlashmode:设置Flashmode的函数
static CameraClient*
_camera_client_create(CameraServiceDesc* csd, const char* param)
{
ci = _camera_service_get_camera_info_by_device_name(csd, cc->device_name);
if (ci == NULL) {
E("%s: Cannot find camera info for device '%s'",
__FUNCTION__, cc->device_name);
_camera_client_free(cc);
return NULL;
}
cc->open = camera_cloud_device_open;
cc->start_capturing = camera_cloud_device_start_capturing;
cc->stop_capturing = camera_cloud_device_stop_capturing;
cc->read_frame = camera_cloud_device_read_frame;
cc->close = camera_cloud_device_close;
cc->setFlashmode = camera_cloud_device_setFlashmode;
}
摄像头数据处理
cameraDataCallback
spice会回调cameraDataCallback,把摄像头的数据传到qemu中
static void cameraDataCallback(unsigned char *data, int info_len, void *context) {
if (mFramebufferData.size() >= info_len) {
memcpy(&(mFramebufferData[0]), data, info_len);
}
}
_camera_client_recv
主要是调用了camera_client_handle_event
static void
_camera_client_recv(void* opaque,
uint8_t* msg,
int msglen,
QemudClient* client)
{
CameraClient* cc = (CameraClient*)opaque;
if (V1) {
if (!cc->eventHandlerThread.isStarted()) {
cc->eventHandlerThread.start();
}
cc->eventHandlerThread.enqueue({OPERATION, msg, msglen, client});
} else {
camera_client_handle_event(cc, msg, msglen, client);
}
}
camera_client_handle_event
根据摄像头client的请求事件,调用不同函数进行处理,其中_camera_client_query_frame就是处理摄像头的数据帧
static void
camera_client_handle_event(CameraClient* cc,
uint8_t* msg,
int msglen,
QemudClient* client) {
...
/* Dispatch the query to an appropriate handler. */
if (!strcmp(query_name, _query_frame)) {
/* A frame is queried. */
if (V1) {
_camera_client_query_frame_v1(cc, client, query_param);
} else {
_camera_client_query_frame(cc, client, query_param);
}
} else if (!strcmp(query_name, _query_connect)) {
/* Camera connection is queried. */
_camera_client_query_connect(cc, client, query_param);
} else if (!strcmp(query_name, _query_disconnect)) {
/* Camera disnection is queried. */
_camera_client_query_disconnect(cc, client, query_param);
} else if (!strcmp(query_name, _query_start)) {
/* Start capturing is queried. */
if (V1) {
_camera_client_query_start_v1(cc, client, query_param);
} else {
_camera_client_query_start(cc, client, query_param);
}
} else if (!strcmp(query_name, _query_stop)) {
/* Stop capturing is queried. */
_camera_client_query_stop(cc, client, query_param);
}else if(!strcmp(query_name,_query_flash)) {
printf("%s: Camera client query: '%s'", __FUNCTION__, (char*)msg);
_camera_client_query_flash(cc, client, query_param);
} else {
E("%s: Unknown query '%s'", __FUNCTION__, (char*)msg);
_qemu_client_reply_ko(client, "Unknown query");
}
}
_camera_client_query_frame
主要是调用cc->read_frame,也就是camera_cloud_device_read_frame
static void
_camera_client_query_frame(CameraClient* cc, QemudClient* qc, const char* param)
{
...
repeat = cc->read_frame(cc->camera, &frame, r_scale, g_scale, b_scale,
exp_comp);
...
}
camera_cloud_device_read_frame
主要是调用convert_frame对摄像头数据进行处理。
int camera_cloud_device_read_frame(CameraDevice* ccd,
ClientFrame* result_frame,
float r_scale,
float g_scale,
float b_scale,
float exp_comp) {
...
// Convert frame to the receiving buffers.
res = convert_frame(mFramebufferData.data(), CLOUD_CAMERA_PIXEL_FORMAT,
mFramebufferData.size(), mFramebufferWidth,
mFramebufferHeight, result_frame, r_scale, g_scale,
b_scale, exp_comp);
...
}
convert_frame
代码路径:android/android-emu/android/camera/camera-format-converters.c
在这个函数,我们可以调用libyuv库的相关接口对摄像头数据旋转、放大缩小、填黑边等操作