• 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 <log/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,int64_t * timestamp)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 
getCurrentPreviewFrame(void * buffer,int64_t * timestamp)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 
getCurrentFrame()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 
produceFrame(void * buffer,int64_t * timestamp)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 
getPrimaryBuffer()315 void* EmulatedQemuCameraDevice::getPrimaryBuffer() {
316     return &mFrameBufferPairs[0];
317 }
getSecondaryBuffer()318 void* EmulatedQemuCameraDevice::getSecondaryBuffer() {
319     return &mFrameBufferPairs[1];
320 }
321 
322 }; /* namespace android */
323