• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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