blob: 68c9179b8266d2827ecb194b7560547944fe11b9 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Contains implementation of a class EmulatedCameraFactory that manages cameras
* available for emulation.
*/
#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_Factory"
#include <cutils/log.h>
#include "EmulatedQemuCamera.h"
#include "EmulatedFakeCamera.h"
#include "EmulatedCameraFactory.h"
extern camera_module_t HAL_MODULE_INFO_SYM;
/* A global instance of EmulatedCameraFactory is statically instantiated and
* initialized when camera emulation HAL is loaded.
*/
android::EmulatedCameraFactory gEmulatedCameraFactory;
namespace android {
EmulatedCameraFactory::EmulatedCameraFactory()
: mQemuClient(),
mEmulatedCameras(NULL),
mEmulatedCameraNum(0),
mFakeCameraID(-1),
mConstructedOK(false)
{
/* If qemu camera emulation is on, try to connect to the factory service in
* the emulator. */
if (isQemuCameraEmulationOn() && mQemuClient.connectClient(NULL) == NO_ERROR) {
/* Connection has succeeded. Create emulated cameras for each camera
* device, reported by the service. */
createQemuCameras();
}
if (isFakeCameraEmulationOn()) {
/* ID fake camera with the number of created 'qemud' cameras. */
mFakeCameraID = mEmulatedCameraNum;
mEmulatedCameraNum++;
/* Make sure that array is allocated (in case there were no 'qemu'
* cameras created. */
if (mEmulatedCameras == NULL) {
mEmulatedCameras = new EmulatedCamera*[mEmulatedCameraNum];
if (mEmulatedCameras == NULL) {
LOGE("%s: Unable to allocate emulated camera array for %d entries",
__FUNCTION__, mEmulatedCameraNum);
return;
}
memset(mEmulatedCameras, 0, mEmulatedCameraNum * sizeof(EmulatedCamera*));
}
/* Create, and initialize the fake camera */
mEmulatedCameras[mFakeCameraID] =
new EmulatedFakeCamera(mFakeCameraID, &HAL_MODULE_INFO_SYM.common);
if (mEmulatedCameras[mFakeCameraID] != NULL) {
if (mEmulatedCameras[mFakeCameraID]->Initialize() != NO_ERROR) {
delete mEmulatedCameras[mFakeCameraID];
mEmulatedCameras--;
mFakeCameraID = -1;
}
} else {
mEmulatedCameras--;
mFakeCameraID = -1;
LOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
}
}
LOGV("%d cameras are being emulated. Fake camera ID is %d",
mEmulatedCameraNum, mFakeCameraID);
mConstructedOK = true;
}
EmulatedCameraFactory::~EmulatedCameraFactory()
{
if (mEmulatedCameras != NULL) {
for (int n = 0; n < mEmulatedCameraNum; n++) {
if (mEmulatedCameras[n] != NULL) {
delete mEmulatedCameras[n];
}
}
delete[] mEmulatedCameras;
}
}
/****************************************************************************
* Camera HAL API handlers.
*
* Each handler simply verifies existence of an appropriate EmulatedCamera
* instance, and dispatches the call to that instance.
*
***************************************************************************/
int EmulatedCameraFactory::cameraDeviceOpen(int camera_id, hw_device_t** device)
{
*device = NULL;
if (!isConstructedOK()) {
LOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
return -EINVAL;
}
if (camera_id >= getEmulatedCameraNum()) {
LOGE("%s: Camera id %d is out of bounds (%d)",
__FUNCTION__, camera_id, getEmulatedCameraNum());
return -EINVAL;
}
return mEmulatedCameras[camera_id]->connectCamera(device);
}
int EmulatedCameraFactory::getCameraInfo(int camera_id, struct camera_info* info)
{
if (!isConstructedOK()) {
LOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
return -EINVAL;
}
if (camera_id >= getEmulatedCameraNum()) {
LOGE("%s: Camera id %d is out of bounds (%d)",
__FUNCTION__, camera_id, getEmulatedCameraNum());
return -EINVAL;
}
return mEmulatedCameras[camera_id]->getCameraInfo(info);
}
/****************************************************************************
* Camera HAL API callbacks.
***************************************************************************/
int EmulatedCameraFactory::device_open(const hw_module_t* module,
const char* name,
hw_device_t** device)
{
/*
* Simply verify the parameters, and dispatch the call inside the
* EmulatedCameraFactory instance.
*/
if (module != &HAL_MODULE_INFO_SYM.common) {
LOGE("%s: Invalid module %p expected %p",
__FUNCTION__, module, &HAL_MODULE_INFO_SYM.common);
return -EINVAL;
}
if (name == NULL) {
LOGE("%s: NULL name is not expected here", __FUNCTION__);
return -EINVAL;
}
return gEmulatedCameraFactory.cameraDeviceOpen(atoi(name), device);
}
int EmulatedCameraFactory::get_number_of_cameras(void)
{
return gEmulatedCameraFactory.getEmulatedCameraNum();
}
int EmulatedCameraFactory::get_camera_info(int camera_id,
struct camera_info* info)
{
return gEmulatedCameraFactory.getCameraInfo(camera_id, info);
}
/********************************************************************************
* Internal API
*******************************************************************************/
/*
* Camera information tokens passed in response to the "list" factory query.
*/
/* Device name token. */
static const char lListNameToken[] = "name=";
/* Frame dimensions token. */
static const char lListDimsToken[] = "framedims=";
void EmulatedCameraFactory::createQemuCameras()
{
/* Obtain camera list. */
char* camera_list = NULL;
status_t res = mQemuClient.listCameras(&camera_list);
/* Empty list, or list containing just an EOL means that there were no
* connected cameras found. */
if (res != NO_ERROR || camera_list == NULL || *camera_list == '\0' ||
*camera_list == '\n') {
if (camera_list != NULL) {
free(camera_list);
}
return;
}
/*
* Calculate number of connected cameras. Number of EOLs in the camera list
* is the number of the connected cameras.
*/
int num = 0;
const char* eol = strchr(camera_list, '\n');
while (eol != NULL) {
num++;
eol = strchr(eol + 1, '\n');
}
/* Allocate the array for emulated camera instances. Note that we allocate
* one more entry for the fake camera emulation. */
mEmulatedCameras = new EmulatedCamera*[num + 1];
if (mEmulatedCameras == NULL) {
LOGE("%s: Unable to allocate emulated camera array for %d entries",
__FUNCTION__, num + 1);
free(camera_list);
return;
}
memset(mEmulatedCameras, 0, sizeof(EmulatedCamera*) * (num + 1));
/*
* Iterate the list, creating, and initializin emulated qemu cameras for each
* entry (line) in the list.
*/
int index = 0;
char* cur_entry = camera_list;
while (cur_entry != NULL && *cur_entry != '\0' && index < num) {
/* Find the end of the current camera entry, and terminate it with zero
* for simpler string manipulation. */
char* next_entry = strchr(cur_entry, '\n');
if (next_entry != NULL) {
*next_entry = '\0';
next_entry++; // Start of the next entry.
}
/* Find 'name', and 'framedims' tokens that are required here. */
char* name_start = strstr(cur_entry, lListNameToken);
char* dim_start = strstr(cur_entry, lListDimsToken);
if (name_start != NULL && dim_start != NULL) {
/* Advance to the token values. */
name_start += strlen(lListNameToken);
dim_start += strlen(lListDimsToken);
/* Terminate token values with zero. */
char* s = strchr(name_start, ' ');
if (s != NULL) {
*s = '\0';
}
s = strchr(dim_start, ' ');
if (s != NULL) {
*s = '\0';
}
/* Create and initialize qemu camera. */
EmulatedQemuCamera* qemu_cam =
new EmulatedQemuCamera(index, &HAL_MODULE_INFO_SYM.common);
if (NULL != qemu_cam) {
res = qemu_cam->Initialize(name_start, dim_start);
if (res == NO_ERROR) {
mEmulatedCameras[index] = qemu_cam;
index++;
} else {
delete qemu_cam;
}
} else {
LOGE("%s: Unable to instantiate EmulatedQemuCamera",
__FUNCTION__);
}
} else {
LOGW("%s: Bad camera information: %s", __FUNCTION__, cur_entry);
}
cur_entry = next_entry;
}
mEmulatedCameraNum = index;
}
bool EmulatedCameraFactory::isQemuCameraEmulationOn()
{
/* TODO: Have a boot property that controls that! */
return true;
}
bool EmulatedCameraFactory::isFakeCameraEmulationOn()
{
/* TODO: Have a boot property that controls that! */
return true;
}
/********************************************************************************
* Initializer for the static member structure.
*******************************************************************************/
/* Entry point for camera HAL API. */
struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = {
open: EmulatedCameraFactory::device_open
};
}; /* namespace android */