blob: c416454a95f2879998b57d0ab0deb530058c473e [file] [log] [blame]
keunyoung8a946832013-03-08 12:28:03 -08001/*
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"
huans005c10e2018-07-06 16:12:30 -070024#include <log/log.h>
keunyoung8a946832013-03-08 12:28:03 -080025#include "EmulatedQemuCamera.h"
26#include "EmulatedQemuCameraDevice.h"
27
28namespace android {
29
30EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal)
31 : EmulatedCameraDevice(camera_hal),
Bjoern Johanssond9753c92016-09-19 15:49:24 -070032 mQemuClient()
keunyoung8a946832013-03-08 12:28:03 -080033{
34}
35
36EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice()
37{
keunyoung8a946832013-03-08 12:28:03 -080038}
39
40/****************************************************************************
41 * Public API
42 ***************************************************************************/
43
44status_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
71status_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. */
Huan Songaa09f3f2018-01-29 21:57:17 +000087 const status_t res = mQemuClient.queryConnect();
keunyoung8a946832013-03-08 12:28:03 -080088 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
100status_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
130status_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.*/
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700157 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();
keunyoung8a946832013-03-08 12:28:03 -0800165
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
183status_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) {
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700197 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
keunyoung8a946832013-03-08 12:28:03 -0800203 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
Bjoern Johansson6ab39a62016-11-18 12:28:12 -0800219status_t EmulatedQemuCameraDevice::getCurrentFrame(void* buffer,
Tim Psiakice4ce402017-11-27 18:19:19 -0800220 uint32_t pixelFormat,
221 int64_t* timestamp) {
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700222 if (!isStarted()) {
223 ALOGE("%s: Device is not started", __FUNCTION__);
224 return EINVAL;
keunyoung8a946832013-03-08 12:28:03 -0800225 }
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700226 if (buffer == nullptr) {
227 ALOGE("%s: Invalid buffer provided", __FUNCTION__);
228 return EINVAL;
229 }
230
231 FrameLock lock(*this);
Bjoern Johanssond17319e2016-09-27 11:05:15 -0700232 const void* primary = mCameraThread->getPrimaryBuffer();
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700233 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 }
Tim Psiakice4ce402017-11-27 18:19:19 -0800240
241 if (timestamp != nullptr) {
242 *timestamp = mCameraThread->getPrimaryTimestamp();
243 }
244
Bjoern Johansson2d473c22016-12-06 11:08:09 -0800245 return getCurrentFrameImpl(reinterpret_cast<const uint8_t*>(frame),
246 reinterpret_cast<uint8_t*>(buffer),
247 pixelFormat);
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700248}
249
Tim Psiakice4ce402017-11-27 18:19:19 -0800250status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer,
251 int64_t* timestamp) {
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700252 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);
Bjoern Johanssond17319e2016-09-27 11:05:15 -0700262 const void* primary = mCameraThread->getPrimaryBuffer();
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700263 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 }
Tim Psiakice4ce402017-11-27 18:19:19 -0800270 if (timestamp != nullptr) {
271 *timestamp = mCameraThread->getPrimaryTimestamp();
272 }
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700273 memcpy(buffer, previewFrame, mTotalPixels * 4);
274 return NO_ERROR;
275}
276
277const void* EmulatedQemuCameraDevice::getCurrentFrame() {
Bjoern Johanssond17319e2016-09-27 11:05:15 -0700278 if (mCameraThread.get() == nullptr) {
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700279 return nullptr;
280 }
281
Bjoern Johanssond17319e2016-09-27 11:05:15 -0700282 const void* primary = mCameraThread->getPrimaryBuffer();
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700283 auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
284 uint8_t* frame = frameBufferPair->first;
285
286 return frame;
keunyoung8a946832013-03-08 12:28:03 -0800287}
288
289/****************************************************************************
290 * Worker thread management overrides.
291 ***************************************************************************/
292
Tim Psiakice4ce402017-11-27 18:19:19 -0800293bool EmulatedQemuCameraDevice::produceFrame(void* buffer, int64_t* timestamp)
keunyoung8a946832013-03-08 12:28:03 -0800294{
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700295 auto frameBufferPair = reinterpret_cast<FrameBufferPair*>(buffer);
296 uint8_t* rawFrame = frameBufferPair->first;
297 uint32_t* previewFrame = frameBufferPair->second;
keunyoung8a946832013-03-08 12:28:03 -0800298
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700299 status_t query_res = mQemuClient.queryFrame(rawFrame, previewFrame,
keunyoung8a946832013-03-08 12:28:03 -0800300 mFrameBufferSize,
301 mTotalPixels * 4,
302 mWhiteBalanceScale[0],
303 mWhiteBalanceScale[1],
304 mWhiteBalanceScale[2],
Tim Psiakice4ce402017-11-27 18:19:19 -0800305 mExposureCompensation,
306 timestamp);
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700307 if (query_res != NO_ERROR) {
keunyoung8a946832013-03-08 12:28:03 -0800308 ALOGE("%s: Unable to get current video frame: %s",
309 __FUNCTION__, strerror(query_res));
keunyoung8a946832013-03-08 12:28:03 -0800310 return false;
311 }
Bjoern Johanssond9753c92016-09-19 15:49:24 -0700312 return true;
313}
314
315void* EmulatedQemuCameraDevice::getPrimaryBuffer() {
316 return &mFrameBufferPairs[0];
317}
318void* EmulatedQemuCameraDevice::getSecondaryBuffer() {
319 return &mFrameBufferPairs[1];
keunyoung8a946832013-03-08 12:28:03 -0800320}
321
322}; /* namespace android */