• 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 <cutils/log.h>
25 #include "EmulatedQemuCamera.h"
26 #include "EmulatedQemuCameraDevice.h"
27 
28 namespace android {
29 
EmulatedQemuCameraDevice(EmulatedQemuCamera * camera_hal)30 EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal)
31     : EmulatedCameraDevice(camera_hal),
32       mQemuClient()
33 {
34 }
35 
~EmulatedQemuCameraDevice()36 EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice()
37 {
38 }
39 
40 /****************************************************************************
41  * Public API
42  ***************************************************************************/
43 
Initialize(const char * device_name)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 
connectDevice()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 
disconnectDevice()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 
startDevice(int width,int height,uint32_t pix_fmt)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 
stopDevice()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 
getCurrentFrame(void * buffer,uint32_t pixelFormat)219 status_t EmulatedQemuCameraDevice::getCurrentFrame(void* buffer,
220                                                    uint32_t pixelFormat) {
221     if (!isStarted()) {
222         ALOGE("%s: Device is not started", __FUNCTION__);
223         return EINVAL;
224     }
225     if (buffer == nullptr) {
226         ALOGE("%s: Invalid buffer provided", __FUNCTION__);
227         return EINVAL;
228     }
229 
230     FrameLock lock(*this);
231     const void* primary = mCameraThread->getPrimaryBuffer();
232     auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
233     uint8_t* frame = frameBufferPair->first;
234 
235     if (frame == nullptr) {
236         ALOGE("%s: No frame", __FUNCTION__);
237         return EINVAL;
238     }
239     return getCurrentFrameImpl(reinterpret_cast<const uint8_t*>(frame),
240                                reinterpret_cast<uint8_t*>(buffer),
241                                pixelFormat);
242 }
243 
getCurrentPreviewFrame(void * buffer)244 status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer) {
245     if (!isStarted()) {
246         ALOGE("%s: Device is not started", __FUNCTION__);
247         return EINVAL;
248     }
249     if (buffer == nullptr) {
250         ALOGE("%s: Invalid buffer provided", __FUNCTION__);
251         return EINVAL;
252     }
253 
254     FrameLock lock(*this);
255     const void* primary = mCameraThread->getPrimaryBuffer();
256     auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
257     uint32_t* previewFrame = frameBufferPair->second;
258 
259     if (previewFrame == nullptr) {
260         ALOGE("%s: No frame", __FUNCTION__);
261         return EINVAL;
262     }
263     memcpy(buffer, previewFrame, mTotalPixels * 4);
264     return NO_ERROR;
265 }
266 
getCurrentFrame()267 const void* EmulatedQemuCameraDevice::getCurrentFrame() {
268     if (mCameraThread.get() == nullptr) {
269         return nullptr;
270     }
271 
272     const void* primary = mCameraThread->getPrimaryBuffer();
273     auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
274     uint8_t* frame = frameBufferPair->first;
275 
276     return frame;
277 }
278 
279 /****************************************************************************
280  * Worker thread management overrides.
281  ***************************************************************************/
282 
produceFrame(void * buffer)283 bool EmulatedQemuCameraDevice::produceFrame(void* buffer)
284 {
285     auto frameBufferPair = reinterpret_cast<FrameBufferPair*>(buffer);
286     uint8_t* rawFrame = frameBufferPair->first;
287     uint32_t* previewFrame = frameBufferPair->second;
288 
289     status_t query_res = mQemuClient.queryFrame(rawFrame, previewFrame,
290                                                  mFrameBufferSize,
291                                                  mTotalPixels * 4,
292                                                  mWhiteBalanceScale[0],
293                                                  mWhiteBalanceScale[1],
294                                                  mWhiteBalanceScale[2],
295                                                  mExposureCompensation);
296     if (query_res != NO_ERROR) {
297         ALOGE("%s: Unable to get current video frame: %s",
298              __FUNCTION__, strerror(query_res));
299         return false;
300     }
301     return true;
302 }
303 
getPrimaryBuffer()304 void* EmulatedQemuCameraDevice::getPrimaryBuffer() {
305     return &mFrameBufferPairs[0];
306 }
getSecondaryBuffer()307 void* EmulatedQemuCameraDevice::getSecondaryBuffer() {
308     return &mFrameBufferPairs[1];
309 }
310 
311 }; /* namespace android */
312