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 { 34 } 35 36 EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice() 37 { 38 } 39 40 /**************************************************************************** 41 * Public API 42 ***************************************************************************/ 43 44 status_t EmulatedQemuCameraDevice::Initialize(const char* device_name) 45 { 46 /* Connect to the service. */ 47 char connect_str[256]; 48 snprintf(connect_str, sizeof(connect_str), "name=%s", device_name); 49 status_t res = mQemuClient.connectClient(connect_str); 50 if (res != NO_ERROR) { 51 return res; 52 } 53 54 /* Initialize base class. */ 55 res = EmulatedCameraDevice::Initialize(); 56 if (res == NO_ERROR) { 57 ALOGV("%s: Connected to the emulated camera service '%s'", 58 __FUNCTION__, device_name); 59 mDeviceName = device_name; 60 } else { 61 mQemuClient.queryDisconnect(); 62 } 63 64 return res; 65 } 66 67 /**************************************************************************** 68 * Emulated camera device abstract interface implementation. 69 ***************************************************************************/ 70 71 status_t EmulatedQemuCameraDevice::connectDevice() 72 { 73 ALOGV("%s", __FUNCTION__); 74 75 Mutex::Autolock locker(&mObjectLock); 76 if (!isInitialized()) { 77 ALOGE("%s: Qemu camera device is not initialized.", __FUNCTION__); 78 return EINVAL; 79 } 80 if (isConnected()) { 81 ALOGW("%s: Qemu camera device '%s' is already connected.", 82 __FUNCTION__, (const char*)mDeviceName); 83 return NO_ERROR; 84 } 85 86 /* Connect to the camera device via emulator. */ 87 const status_t res = mQemuClient.queryConnect(); 88 if (res == NO_ERROR) { 89 ALOGV("%s: Connected to device '%s'", 90 __FUNCTION__, (const char*)mDeviceName); 91 mState = ECDS_CONNECTED; 92 } else { 93 ALOGE("%s: Connection to device '%s' failed", 94 __FUNCTION__, (const char*)mDeviceName); 95 } 96 97 return res; 98 } 99 100 status_t EmulatedQemuCameraDevice::disconnectDevice() 101 { 102 ALOGV("%s", __FUNCTION__); 103 104 Mutex::Autolock locker(&mObjectLock); 105 if (!isConnected()) { 106 ALOGW("%s: Qemu camera device '%s' is already disconnected.", 107 __FUNCTION__, (const char*)mDeviceName); 108 return NO_ERROR; 109 } 110 if (isStarted()) { 111 ALOGE("%s: Cannot disconnect from the started device '%s.", 112 __FUNCTION__, (const char*)mDeviceName); 113 return EINVAL; 114 } 115 116 /* Disconnect from the camera device via emulator. */ 117 const status_t res = mQemuClient.queryDisconnect(); 118 if (res == NO_ERROR) { 119 ALOGV("%s: Disonnected from device '%s'", 120 __FUNCTION__, (const char*)mDeviceName); 121 mState = ECDS_INITIALIZED; 122 } else { 123 ALOGE("%s: Disconnection from device '%s' failed", 124 __FUNCTION__, (const char*)mDeviceName); 125 } 126 127 return res; 128 } 129 130 status_t EmulatedQemuCameraDevice::startDevice(int width, 131 int height, 132 uint32_t pix_fmt) 133 { 134 ALOGV("%s", __FUNCTION__); 135 136 Mutex::Autolock locker(&mObjectLock); 137 if (!isConnected()) { 138 ALOGE("%s: Qemu camera device '%s' is not connected.", 139 __FUNCTION__, (const char*)mDeviceName); 140 return EINVAL; 141 } 142 if (isStarted()) { 143 ALOGW("%s: Qemu camera device '%s' is already started.", 144 __FUNCTION__, (const char*)mDeviceName); 145 return NO_ERROR; 146 } 147 148 status_t res = EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt); 149 if (res != NO_ERROR) { 150 ALOGE("%s: commonStartDevice failed", __FUNCTION__); 151 return res; 152 } 153 154 /* Allocate preview frame buffer. */ 155 /* TODO: Watch out for preview format changes! At this point we implement 156 * RGB32 only.*/ 157 mPreviewFrames[0].resize(mTotalPixels); 158 mPreviewFrames[1].resize(mTotalPixels); 159 160 mFrameBufferPairs[0].first = mFrameBuffers[0].data(); 161 mFrameBufferPairs[0].second = mPreviewFrames[0].data(); 162 163 mFrameBufferPairs[1].first = mFrameBuffers[1].data(); 164 mFrameBufferPairs[1].second = mPreviewFrames[1].data(); 165 166 /* Start the actual camera device. */ 167 res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight); 168 if (res == NO_ERROR) { 169 ALOGV("%s: Qemu camera device '%s' is started for %.4s[%dx%d] frames", 170 __FUNCTION__, (const char*)mDeviceName, 171 reinterpret_cast<const char*>(&mPixelFormat), 172 mFrameWidth, mFrameHeight); 173 mState = ECDS_STARTED; 174 } else { 175 ALOGE("%s: Unable to start device '%s' for %.4s[%dx%d] frames", 176 __FUNCTION__, (const char*)mDeviceName, 177 reinterpret_cast<const char*>(&pix_fmt), width, height); 178 } 179 180 return res; 181 } 182 183 status_t EmulatedQemuCameraDevice::stopDevice() 184 { 185 ALOGV("%s", __FUNCTION__); 186 187 Mutex::Autolock locker(&mObjectLock); 188 if (!isStarted()) { 189 ALOGW("%s: Qemu camera device '%s' is not started.", 190 __FUNCTION__, (const char*)mDeviceName); 191 return NO_ERROR; 192 } 193 194 /* Stop the actual camera device. */ 195 status_t res = mQemuClient.queryStop(); 196 if (res == NO_ERROR) { 197 mPreviewFrames[0].clear(); 198 mPreviewFrames[1].clear(); 199 // No need to keep all that memory around as capacity, shrink it 200 mPreviewFrames[0].shrink_to_fit(); 201 mPreviewFrames[1].shrink_to_fit(); 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::getCurrentFrame(void* buffer, 220 uint32_t pixelFormat, 221 int64_t* timestamp) { 222 if (!isStarted()) { 223 ALOGE("%s: Device is not started", __FUNCTION__); 224 return EINVAL; 225 } 226 if (buffer == nullptr) { 227 ALOGE("%s: Invalid buffer provided", __FUNCTION__); 228 return EINVAL; 229 } 230 231 FrameLock lock(*this); 232 const void* primary = mCameraThread->getPrimaryBuffer(); 233 auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary); 234 uint8_t* frame = frameBufferPair->first; 235 236 if (frame == nullptr) { 237 ALOGE("%s: No frame", __FUNCTION__); 238 return EINVAL; 239 } 240 241 if (timestamp != nullptr) { 242 *timestamp = mCameraThread->getPrimaryTimestamp(); 243 } 244 245 return getCurrentFrameImpl(reinterpret_cast<const uint8_t*>(frame), 246 reinterpret_cast<uint8_t*>(buffer), 247 pixelFormat); 248 } 249 250 status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer, 251 int64_t* timestamp) { 252 if (!isStarted()) { 253 ALOGE("%s: Device is not started", __FUNCTION__); 254 return EINVAL; 255 } 256 if (buffer == nullptr) { 257 ALOGE("%s: Invalid buffer provided", __FUNCTION__); 258 return EINVAL; 259 } 260 261 FrameLock lock(*this); 262 const void* primary = mCameraThread->getPrimaryBuffer(); 263 auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary); 264 uint32_t* previewFrame = frameBufferPair->second; 265 266 if (previewFrame == nullptr) { 267 ALOGE("%s: No frame", __FUNCTION__); 268 return EINVAL; 269 } 270 if (timestamp != nullptr) { 271 *timestamp = mCameraThread->getPrimaryTimestamp(); 272 } 273 memcpy(buffer, previewFrame, mTotalPixels * 4); 274 return NO_ERROR; 275 } 276 277 const void* EmulatedQemuCameraDevice::getCurrentFrame() { 278 if (mCameraThread.get() == nullptr) { 279 return nullptr; 280 } 281 282 const void* primary = mCameraThread->getPrimaryBuffer(); 283 auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary); 284 uint8_t* frame = frameBufferPair->first; 285 286 return frame; 287 } 288 289 /**************************************************************************** 290 * Worker thread management overrides. 291 ***************************************************************************/ 292 293 bool EmulatedQemuCameraDevice::produceFrame(void* buffer, int64_t* timestamp) 294 { 295 auto frameBufferPair = reinterpret_cast<FrameBufferPair*>(buffer); 296 uint8_t* rawFrame = frameBufferPair->first; 297 uint32_t* previewFrame = frameBufferPair->second; 298 299 status_t query_res = mQemuClient.queryFrame(rawFrame, previewFrame, 300 mFrameBufferSize, 301 mTotalPixels * 4, 302 mWhiteBalanceScale[0], 303 mWhiteBalanceScale[1], 304 mWhiteBalanceScale[2], 305 mExposureCompensation, 306 timestamp); 307 if (query_res != NO_ERROR) { 308 ALOGE("%s: Unable to get current video frame: %s", 309 __FUNCTION__, strerror(query_res)); 310 return false; 311 } 312 return true; 313 } 314 315 void* EmulatedQemuCameraDevice::getPrimaryBuffer() { 316 return &mFrameBufferPairs[0]; 317 } 318 void* EmulatedQemuCameraDevice::getSecondaryBuffer() { 319 return &mFrameBufferPairs[1]; 320 } 321 322 }; /* namespace android */ 323