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