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 <log/log.h>
26 #include "EmulatedQemuCamera.h"
27
28 namespace android {
29
EmulatedQemuCameraDevice(EmulatedQemuCamera * camera_hal)30 EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(
31 EmulatedQemuCamera* camera_hal)
32 : EmulatedCameraDevice(camera_hal), mQemuClient(), mPreviewFrame(NULL) {}
33
~EmulatedQemuCameraDevice()34 EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice() {
35 if (mPreviewFrame != NULL) {
36 delete[] mPreviewFrame;
37 }
38 }
39
40 /****************************************************************************
41 * Public API
42 ***************************************************************************/
43
Initialize(const char * device_name)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
connectDevice()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
disconnectDevice()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
startDevice(int width,int height,uint32_t pix_fmt,int fps)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
stopDevice()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
getCurrentPreviewFrame(void * buffer)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
inWorkerThread()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