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 EmulatedQemuCameraDevice that encapsulates 19 * an emulated camera device connected to the host. 20 */ 21 22 #define LOG_NDEBUG 0 23 #define LOG_TAG "EmulatedCamera_QemuDevice" 24 #include <cutils/log.h> 25 #include "EmulatedQemuCamera.h" 26 #include "EmulatedQemuCameraDevice.h" 27 28 namespace android { 29 30 EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal) 31 : EmulatedCameraDevice(camera_hal), 32 mQemuClient(), 33 mPreviewFrame(NULL) 34 { 35 } 36 37 EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice() 38 { 39 if (mPreviewFrame != NULL) { 40 delete[] mPreviewFrame; 41 } 42 } 43 44 /**************************************************************************** 45 * Public API 46 ***************************************************************************/ 47 48 status_t EmulatedQemuCameraDevice::Initialize(const char* device_name) 49 { 50 /* Connect to the service. */ 51 char connect_str[256]; 52 snprintf(connect_str, sizeof(connect_str), "name=%s", device_name); 53 status_t res = mQemuClient.connectClient(connect_str); 54 if (res != NO_ERROR) { 55 return res; 56 } 57 58 /* Initialize base class. */ 59 res = EmulatedCameraDevice::Initialize(); 60 if (res == NO_ERROR) { 61 ALOGV("%s: Connected to the emulated camera service '%s'", 62 __FUNCTION__, device_name); 63 mDeviceName = device_name; 64 } else { 65 mQemuClient.queryDisconnect(); 66 } 67 68 return res; 69 } 70 71 /**************************************************************************** 72 * Emulated camera device abstract interface implementation. 73 ***************************************************************************/ 74 75 status_t EmulatedQemuCameraDevice::connectDevice() 76 { 77 ALOGV("%s", __FUNCTION__); 78 79 Mutex::Autolock locker(&mObjectLock); 80 if (!isInitialized()) { 81 ALOGE("%s: Qemu camera device is not initialized.", __FUNCTION__); 82 return EINVAL; 83 } 84 if (isConnected()) { 85 ALOGW("%s: Qemu camera device '%s' is already connected.", 86 __FUNCTION__, (const char*)mDeviceName); 87 return NO_ERROR; 88 } 89 90 /* Connect to the camera device via emulator. */ 91 const status_t res = mQemuClient.queryConnect(); 92 if (res == NO_ERROR) { 93 ALOGV("%s: Connected to device '%s'", 94 __FUNCTION__, (const char*)mDeviceName); 95 mState = ECDS_CONNECTED; 96 } else { 97 ALOGE("%s: Connection to device '%s' failed", 98 __FUNCTION__, (const char*)mDeviceName); 99 } 100 101 return res; 102 } 103 104 status_t EmulatedQemuCameraDevice::disconnectDevice() 105 { 106 ALOGV("%s", __FUNCTION__); 107 108 Mutex::Autolock locker(&mObjectLock); 109 if (!isConnected()) { 110 ALOGW("%s: Qemu camera device '%s' is already disconnected.", 111 __FUNCTION__, (const char*)mDeviceName); 112 return NO_ERROR; 113 } 114 if (isStarted()) { 115 ALOGE("%s: Cannot disconnect from the started device '%s.", 116 __FUNCTION__, (const char*)mDeviceName); 117 return EINVAL; 118 } 119 120 /* Disconnect from the camera device via emulator. */ 121 const status_t res = mQemuClient.queryDisconnect(); 122 if (res == NO_ERROR) { 123 ALOGV("%s: Disonnected from device '%s'", 124 __FUNCTION__, (const char*)mDeviceName); 125 mState = ECDS_INITIALIZED; 126 } else { 127 ALOGE("%s: Disconnection from device '%s' failed", 128 __FUNCTION__, (const char*)mDeviceName); 129 } 130 131 return res; 132 } 133 134 status_t EmulatedQemuCameraDevice::startDevice(int width, 135 int height, 136 uint32_t pix_fmt) 137 { 138 ALOGV("%s", __FUNCTION__); 139 140 Mutex::Autolock locker(&mObjectLock); 141 if (!isConnected()) { 142 ALOGE("%s: Qemu camera device '%s' is not connected.", 143 __FUNCTION__, (const char*)mDeviceName); 144 return EINVAL; 145 } 146 if (isStarted()) { 147 ALOGW("%s: Qemu camera device '%s' is already started.", 148 __FUNCTION__, (const char*)mDeviceName); 149 return NO_ERROR; 150 } 151 152 status_t res = EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt); 153 if (res != NO_ERROR) { 154 ALOGE("%s: commonStartDevice failed", __FUNCTION__); 155 return res; 156 } 157 158 /* Allocate preview frame buffer. */ 159 /* TODO: Watch out for preview format changes! At this point we implement 160 * RGB32 only.*/ 161 mPreviewFrame = new uint32_t[mTotalPixels]; 162 if (mPreviewFrame == NULL) { 163 ALOGE("%s: Unable to allocate %d bytes for preview frame", 164 __FUNCTION__, mTotalPixels); 165 return ENOMEM; 166 } 167 168 /* Start the actual camera device. */ 169 res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight); 170 if (res == NO_ERROR) { 171 ALOGV("%s: Qemu camera device '%s' is started for %.4s[%dx%d] frames", 172 __FUNCTION__, (const char*)mDeviceName, 173 reinterpret_cast<const char*>(&mPixelFormat), 174 mFrameWidth, mFrameHeight); 175 mState = ECDS_STARTED; 176 } else { 177 ALOGE("%s: Unable to start device '%s' for %.4s[%dx%d] frames", 178 __FUNCTION__, (const char*)mDeviceName, 179 reinterpret_cast<const char*>(&pix_fmt), width, height); 180 } 181 182 return res; 183 } 184 185 status_t EmulatedQemuCameraDevice::stopDevice() 186 { 187 ALOGV("%s", __FUNCTION__); 188 189 Mutex::Autolock locker(&mObjectLock); 190 if (!isStarted()) { 191 ALOGW("%s: Qemu camera device '%s' is not started.", 192 __FUNCTION__, (const char*)mDeviceName); 193 return NO_ERROR; 194 } 195 196 /* Stop the actual camera device. */ 197 status_t res = mQemuClient.queryStop(); 198 if (res == NO_ERROR) { 199 if (mPreviewFrame == NULL) { 200 delete[] mPreviewFrame; 201 mPreviewFrame = NULL; 202 } 203 EmulatedCameraDevice::commonStopDevice(); 204 mState = ECDS_CONNECTED; 205 ALOGV("%s: Qemu camera device '%s' is stopped", 206 __FUNCTION__, (const char*)mDeviceName); 207 } else { 208 ALOGE("%s: Unable to stop device '%s'", 209 __FUNCTION__, (const char*)mDeviceName); 210 } 211 212 return res; 213 } 214 215 /**************************************************************************** 216 * EmulatedCameraDevice virtual overrides 217 ***************************************************************************/ 218 219 status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer) 220 { 221 ALOGW_IF(mPreviewFrame == NULL, "%s: No preview frame", __FUNCTION__); 222 if (mPreviewFrame != NULL) { 223 memcpy(buffer, mPreviewFrame, mTotalPixels * 4); 224 return 0; 225 } else { 226 return EmulatedCameraDevice::getCurrentPreviewFrame(buffer); 227 } 228 } 229 230 /**************************************************************************** 231 * Worker thread management overrides. 232 ***************************************************************************/ 233 234 bool EmulatedQemuCameraDevice::inWorkerThread() 235 { 236 /* Wait till FPS timeout expires, or thread exit message is received. */ 237 WorkerThread::SelectRes res = 238 getWorkerThread()->Select(-1, 1000000 / mEmulatedFPS); 239 if (res == WorkerThread::EXIT_THREAD) { 240 ALOGV("%s: Worker thread has been terminated.", __FUNCTION__); 241 return false; 242 } 243 244 /* Query frames from the service. */ 245 status_t query_res = mQemuClient.queryFrame(mCurrentFrame, mPreviewFrame, 246 mFrameBufferSize, 247 mTotalPixels * 4, 248 mWhiteBalanceScale[0], 249 mWhiteBalanceScale[1], 250 mWhiteBalanceScale[2], 251 mExposureCompensation); 252 if (query_res == NO_ERROR) { 253 /* Timestamp the current frame, and notify the camera HAL. */ 254 mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); 255 mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this); 256 return true; 257 } else { 258 ALOGE("%s: Unable to get current video frame: %s", 259 __FUNCTION__, strerror(query_res)); 260 mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED); 261 return false; 262 } 263 } 264 265 }; /* namespace android */ 266