Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /* |
| 18 | * Contains implementation of a class CameraFactory that manages cameras |
| 19 | * available |
| 20 | */ |
| 21 | |
| 22 | #define LOG_NDEBUG 0 |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 23 | #define CONFIG_FILE "/etc/camera.cfg" |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 24 | #define LOG_TAG "Camera_Factory" |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 25 | |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 26 | #include <cutils/log.h> |
| 27 | #include <cutils/properties.h> |
| 28 | #include "CameraFactory.h" |
| 29 | |
| 30 | extern camera_module_t HAL_MODULE_INFO_SYM; |
| 31 | |
| 32 | /* A global instance of CameraFactory is statically instantiated and |
| 33 | * initialized when camera HAL is loaded. |
| 34 | */ |
| 35 | android::CameraFactory gCameraFactory; |
| 36 | |
| 37 | namespace android { |
| 38 | |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 39 | CameraFactory::CameraFactory() |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 40 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 41 | ALOGD("CameraFactory::CameraFactory"); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 42 | mCamera = NULL; |
| 43 | mCameraDevices = NULL; |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 44 | mCameraFacing = NULL; |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 45 | mCameraOrientation = NULL; |
| 46 | parseConfig(CONFIG_FILE); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | CameraFactory::~CameraFactory() |
| 50 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 51 | ALOGD("CameraFactory::~CameraFactory"); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 52 | for (int i=0; i < getCameraNum(); i++) { |
| 53 | delete mCamera[i]; |
Chih-Wei Huang | 3aeaabb | 2019-03-22 15:29:19 +0800 | [diff] [blame] | 54 | free(mCameraDevices[i]); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 55 | } |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 56 | free(mCamera); |
Chih-Wei Huang | 3aeaabb | 2019-03-22 15:29:19 +0800 | [diff] [blame] | 57 | free(mCameraDevices); |
| 58 | free(mCameraFacing); |
| 59 | free(mCameraOrientation); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | /**************************************************************************** |
| 63 | * Camera HAL API handlers. |
| 64 | * |
| 65 | * Each handler simply verifies existence of an appropriate Camera |
| 66 | * instance, and dispatches the call to that instance. |
| 67 | * |
| 68 | ***************************************************************************/ |
| 69 | |
| 70 | int CameraFactory::cameraDeviceOpen(const hw_module_t* module,int camera_id, hw_device_t** device) |
| 71 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 72 | ALOGD("CameraFactory::cameraDeviceOpen: id = %d", camera_id); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 73 | |
| 74 | *device = NULL; |
| 75 | |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 76 | if (!mCamera || camera_id < 0 || camera_id >= getCameraNum()) { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 77 | ALOGE("%s: Camera id %d is out of bounds (%d)", |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 78 | __FUNCTION__, camera_id, getCameraNum()); |
| 79 | return -EINVAL; |
| 80 | } |
| 81 | |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 82 | if (!mCamera[camera_id]) { |
| 83 | mCamera[camera_id] = new CameraHardware(module, mCameraDevices[camera_id]); |
| 84 | } |
| 85 | return mCamera[camera_id]->connectCamera(device); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | /* Returns the number of available cameras */ |
| 89 | int CameraFactory::getCameraNum() |
| 90 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 91 | ALOGD("CameraFactory::getCameraNum: %d", mCameraNum); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 92 | return mCameraNum; |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 93 | } |
| 94 | |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 95 | int CameraFactory::getCameraInfo(int camera_id, struct camera_info* info) |
| 96 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 97 | ALOGD("CameraFactory::getCameraInfo: id = %d, info = %p", camera_id, info); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 98 | |
| 99 | if (camera_id < 0 || camera_id >= getCameraNum()) { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 100 | ALOGE("%s: Camera id %d is out of bounds (%d)", |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 101 | __FUNCTION__, camera_id, getCameraNum()); |
| 102 | return -EINVAL; |
| 103 | } |
| 104 | |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 105 | return CameraHardware::getCameraInfo(info, mCameraFacing[camera_id], |
| 106 | mCameraOrientation[camera_id]); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 107 | } |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 108 | |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 109 | // Parse a simple configuration file |
| 110 | void CameraFactory::parseConfig(const char* configFile) |
| 111 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 112 | ALOGD("CameraFactory::parseConfig: configFile = %s", configFile); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 113 | |
| 114 | FILE* config = fopen(configFile, "r"); |
| 115 | if (config != NULL) { |
| 116 | char line[128]; |
| 117 | char arg1[128]; |
| 118 | char arg2[128]; |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 119 | int arg3; |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 120 | |
| 121 | while (fgets(line, sizeof line, config) != NULL) { |
| 122 | int lineStart = strspn(line, " \t\n\v" ); |
| 123 | |
| 124 | if (line[lineStart] == '#') |
| 125 | continue; |
| 126 | |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 127 | sscanf(line, "%s %s %d", arg1, arg2, &arg3); |
| 128 | if (arg3 != 0 && arg3 != 90 && arg3 != 180 && arg3 != 270) |
| 129 | arg3 = 0; |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 130 | |
Alberto Panizzo | 5e3ac0d | 2013-07-07 09:19:40 +0200 | [diff] [blame] | 131 | if (strcmp(arg1, "front") == 0) { |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 132 | newCameraConfig(CAMERA_FACING_FRONT, arg2, arg3); |
Alberto Panizzo | 5e3ac0d | 2013-07-07 09:19:40 +0200 | [diff] [blame] | 133 | } else if (strcmp(arg1, "back") == 0) { |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 134 | newCameraConfig(CAMERA_FACING_BACK, arg2, arg3); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 135 | } else { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 136 | ALOGD("CameraFactory::parseConfig: Unrecognized config line '%s'", line); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 137 | } |
| 138 | } |
| 139 | } else { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 140 | ALOGD("%s not found, using camera configuration defaults", CONFIG_FILE); |
Chih-Wei Huang | 4e2b731 | 2019-03-22 23:53:23 +0800 | [diff] [blame] | 141 | char camera_node[] = "/dev/video0"; |
| 142 | char camera_prop[] = "hal.camera.0"; |
| 143 | char prop[PROPERTY_VALUE_MAX] = ""; |
Chih-Wei Huang | cdab626 | 2020-05-05 10:01:40 +0800 | [diff] [blame] | 144 | bool no_prop = true; |
Chih-Wei Huang | 4e2b731 | 2019-03-22 23:53:23 +0800 | [diff] [blame] | 145 | while (camera_node[10] <= '9' && mCameraNum < 3) { |
| 146 | if (!access(camera_node, F_OK)) { |
| 147 | int facing = mCameraNum, orientation = 0; |
| 148 | if (property_get(camera_prop, prop, "")) { |
Chih-Wei Huang | cdab626 | 2020-05-05 10:01:40 +0800 | [diff] [blame] | 149 | no_prop = false; |
Chih-Wei Huang | 4e2b731 | 2019-03-22 23:53:23 +0800 | [diff] [blame] | 150 | sscanf(prop, "%d,%d", &facing, &orientation); |
| 151 | ALOGI("%s got facing=%d orient=%d from property %s", __FUNCTION__, facing, orientation, camera_prop); |
| 152 | } |
| 153 | newCameraConfig(facing, camera_node, orientation); |
| 154 | } |
| 155 | camera_node[10]++, camera_prop[11]++; |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 156 | } |
Chih-Wei Huang | 4e2b731 | 2019-03-22 23:53:23 +0800 | [diff] [blame] | 157 | |
| 158 | // If there is only one camera, assume its facing is front |
Chih-Wei Huang | cdab626 | 2020-05-05 10:01:40 +0800 | [diff] [blame] | 159 | if (mCameraNum == 1 && no_prop) { |
Chih-Wei Huang | 4e2b731 | 2019-03-22 23:53:23 +0800 | [diff] [blame] | 160 | mCameraFacing[0] = CAMERA_FACING_FRONT; |
Chih-Wei Huang | cdab626 | 2020-05-05 10:01:40 +0800 | [diff] [blame] | 161 | ALOGI("%s assume %s is front", __FUNCTION__, mCameraDevices[0]); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 162 | } |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | // Although realloc could be a costly operation, we only execute this function usually 2 times |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 167 | void CameraFactory::newCameraConfig(int facing, const char* location, int orientation) |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 168 | { |
Chih-Wei Huang | 342584c | 2018-06-20 18:04:58 +0800 | [diff] [blame] | 169 | V4L2Camera camera; |
| 170 | if (camera.Open(location) || !camera.getBestPreviewFmt().getFps()) { |
| 171 | ALOGW("ignore invalid camera: %s", location); |
| 172 | return; |
| 173 | } |
| 174 | |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 175 | // Keep track of cameras |
| 176 | mCameraNum++; |
| 177 | |
| 178 | // Grow the information arrays |
| 179 | mCamera = (CameraHardware**) realloc(mCamera, mCameraNum * sizeof(CameraHardware*)); |
| 180 | mCameraDevices = (char**) realloc(mCameraDevices, mCameraNum * sizeof(char*)); |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 181 | mCameraFacing = (int*) realloc(mCameraFacing, mCameraNum * sizeof(int)); |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 182 | mCameraOrientation = (int*) realloc(mCameraOrientation, mCameraNum * sizeof(int)); |
| 183 | |
| 184 | // Store the values for each camera_id |
| 185 | mCamera[mCameraNum - 1] = NULL; |
| 186 | mCameraDevices[mCameraNum - 1] = strdup(location); |
Alberto Panizzo | bbbfb37 | 2013-07-06 18:23:53 +0200 | [diff] [blame] | 187 | mCameraFacing[mCameraNum - 1] = facing; |
| 188 | mCameraOrientation[mCameraNum - 1] = orientation; |
| 189 | ALOGD("CameraFactory::newCameraConfig: %d -> %s (%d)", |
| 190 | mCameraFacing[mCameraNum - 1], mCameraDevices[mCameraNum - 1], |
| 191 | mCameraOrientation[mCameraNum - 1]); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | /**************************************************************************** |
| 195 | * Camera HAL API callbacks. |
| 196 | ***************************************************************************/ |
| 197 | |
| 198 | int CameraFactory::device_open(const hw_module_t* module, |
| 199 | const char* name, |
| 200 | hw_device_t** device) |
| 201 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 202 | ALOGD("CameraFactory::device_open: name = %s", name); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 203 | |
| 204 | /* |
| 205 | * Simply verify the parameters, and dispatch the call inside the |
| 206 | * CameraFactory instance. |
| 207 | */ |
| 208 | |
| 209 | if (module != &HAL_MODULE_INFO_SYM.common) { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 210 | ALOGE("%s: Invalid module %p expected %p", |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 211 | __FUNCTION__, module, &HAL_MODULE_INFO_SYM.common); |
| 212 | return -EINVAL; |
| 213 | } |
| 214 | if (name == NULL) { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 215 | ALOGE("%s: NULL name is not expected here", __FUNCTION__); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 216 | return -EINVAL; |
| 217 | } |
| 218 | |
Andres Rodriguez | 937775c | 2012-04-19 23:38:00 +0800 | [diff] [blame] | 219 | int camera_id = atoi(name); |
| 220 | return gCameraFactory.cameraDeviceOpen(module, camera_id, device); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | int CameraFactory::get_number_of_cameras(void) |
| 224 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 225 | ALOGD("CameraFactory::get_number_of_cameras"); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 226 | return gCameraFactory.getCameraNum(); |
| 227 | } |
| 228 | |
| 229 | int CameraFactory::get_camera_info(int camera_id, |
| 230 | struct camera_info* info) |
| 231 | { |
Chih-Wei Huang | df9613f | 2013-02-20 15:46:19 +0800 | [diff] [blame] | 232 | ALOGD("CameraFactory::get_camera_info"); |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 233 | return gCameraFactory.getCameraInfo(camera_id, info); |
| 234 | } |
| 235 | |
| 236 | /******************************************************************************** |
| 237 | * Initializer for the static member structure. |
| 238 | *******************************************************************************/ |
| 239 | |
| 240 | /* Entry point for camera HAL API. */ |
| 241 | struct hw_module_methods_t CameraFactory::mCameraModuleMethods = { |
Chih-Wei Huang | 3277dcd | 2019-02-26 18:08:29 +0800 | [diff] [blame] | 242 | .open = CameraFactory::device_open |
Chih-Wei Huang | 0d92eda | 2012-02-07 16:55:49 +0800 | [diff] [blame] | 243 | }; |
| 244 | |
| 245 | }; /* namespace android */ |