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 an abstract class EmulatedCameraDevice that defines
19 * functionality expected from an emulated physical camera device:
20 * - Obtaining and setting camera parameters
21 * - Capturing frames
22 * - Streaming video
23 * - etc.
24 */
25
26 #define LOG_NDEBUG 0
27 #define LOG_TAG "EmulatedCamera_Device"
28 #include <cutils/log.h>
29 #include <sys/select.h>
30 #include "EmulatedCameraDevice.h"
31 #include "Converters.h"
32
33 namespace android {
34
EmulatedCameraDevice(EmulatedCamera * camera_hal)35 EmulatedCameraDevice::EmulatedCameraDevice(EmulatedCamera* camera_hal)
36 : mObjectLock(),
37 mCurFrameTimestamp(0),
38 mCameraHAL(camera_hal),
39 mCurrentFrame(NULL),
40 mState(ECDS_CONSTRUCTED)
41 {
42 }
43
~EmulatedCameraDevice()44 EmulatedCameraDevice::~EmulatedCameraDevice()
45 {
46 if (mCurrentFrame != NULL) {
47 delete[] mCurrentFrame;
48 }
49 }
50
51 /****************************************************************************
52 * Emulated camera device public API
53 ***************************************************************************/
54
Initialize()55 status_t EmulatedCameraDevice::Initialize()
56 {
57 if (isInitialized()) {
58 LOGW("%s: Emulated camera device is already initialized: mState = %d",
59 __FUNCTION__, mState);
60 return NO_ERROR;
61 }
62
63 /* Instantiate worker thread object. */
64 mWorkerThread = new WorkerThread(this);
65 if (getWorkerThread() == NULL) {
66 LOGE("%s: Unable to instantiate worker thread object", __FUNCTION__);
67 return ENOMEM;
68 }
69
70 mState = ECDS_INITIALIZED;
71
72 return NO_ERROR;
73 }
74
startDeliveringFrames(bool one_burst)75 status_t EmulatedCameraDevice::startDeliveringFrames(bool one_burst)
76 {
77 LOGV("%s", __FUNCTION__);
78
79 if (!isStarted()) {
80 LOGE("%s: Device is not started", __FUNCTION__);
81 return EINVAL;
82 }
83
84 /* Frames will be delivered from the thread routine. */
85 const status_t res = startWorkerThread(one_burst);
86 LOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
87 return res;
88 }
89
stopDeliveringFrames()90 status_t EmulatedCameraDevice::stopDeliveringFrames()
91 {
92 LOGV("%s", __FUNCTION__);
93
94 if (!isStarted()) {
95 LOGW("%s: Device is not started", __FUNCTION__);
96 return NO_ERROR;
97 }
98
99 const status_t res = stopWorkerThread();
100 LOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
101 return res;
102 }
103
getCurrentPreviewFrame(void * buffer)104 status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer)
105 {
106 if (!isStarted()) {
107 LOGE("%s: Device is not started", __FUNCTION__);
108 return EINVAL;
109 }
110 if (mCurrentFrame == NULL || buffer == NULL) {
111 LOGE("%s: No framebuffer", __FUNCTION__);
112 return EINVAL;
113 }
114
115 /* In emulation the framebuffer is never RGB. */
116 switch (mPixelFormat) {
117 case V4L2_PIX_FMT_YVU420:
118 YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
119 return NO_ERROR;
120 case V4L2_PIX_FMT_YUV420:
121 YU12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
122 return NO_ERROR;
123 case V4L2_PIX_FMT_NV21:
124 NV21ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
125 return NO_ERROR;
126 case V4L2_PIX_FMT_NV12:
127 NV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
128 return NO_ERROR;
129
130 default:
131 LOGE("%s: Unknown pixel format %.4s",
132 __FUNCTION__, reinterpret_cast<const char*>(&mPixelFormat));
133 return EINVAL;
134 }
135 }
136
137 /****************************************************************************
138 * Emulated camera device private API
139 ***************************************************************************/
140
commonStartDevice(int width,int height,uint32_t pix_fmt)141 status_t EmulatedCameraDevice::commonStartDevice(int width,
142 int height,
143 uint32_t pix_fmt)
144 {
145 /* Validate pixel format, and calculate framebuffer size at the same time. */
146 switch (pix_fmt) {
147 case V4L2_PIX_FMT_YVU420:
148 case V4L2_PIX_FMT_YUV420:
149 case V4L2_PIX_FMT_NV21:
150 case V4L2_PIX_FMT_NV12:
151 mFrameBufferSize = (width * height * 12) / 8;
152 break;
153
154 default:
155 LOGE("%s: Unknown pixel format %.4s",
156 __FUNCTION__, reinterpret_cast<const char*>(&pix_fmt));
157 return EINVAL;
158 }
159
160 /* Cache framebuffer info. */
161 mFrameWidth = width;
162 mFrameHeight = height;
163 mPixelFormat = pix_fmt;
164 mTotalPixels = width * height;
165
166 /* Allocate framebuffer. */
167 mCurrentFrame = new uint8_t[mFrameBufferSize];
168 if (mCurrentFrame == NULL) {
169 LOGE("%s: Unable to allocate framebuffer", __FUNCTION__);
170 return ENOMEM;
171 }
172 LOGV("%s: Allocated %p %d bytes for %d pixels in %.4s[%dx%d] frame",
173 __FUNCTION__, mCurrentFrame, mFrameBufferSize, mTotalPixels,
174 reinterpret_cast<const char*>(&mPixelFormat), mFrameWidth, mFrameHeight);
175 return NO_ERROR;
176 }
177
commonStopDevice()178 void EmulatedCameraDevice::commonStopDevice()
179 {
180 mFrameWidth = mFrameHeight = mTotalPixels = 0;
181 mPixelFormat = 0;
182
183 if (mCurrentFrame != NULL) {
184 delete[] mCurrentFrame;
185 mCurrentFrame = NULL;
186 }
187 }
188
189 /****************************************************************************
190 * Worker thread management.
191 ***************************************************************************/
192
startWorkerThread(bool one_burst)193 status_t EmulatedCameraDevice::startWorkerThread(bool one_burst)
194 {
195 LOGV("%s", __FUNCTION__);
196
197 if (!isInitialized()) {
198 LOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
199 return EINVAL;
200 }
201
202 const status_t res = getWorkerThread()->startThread(one_burst);
203 LOGE_IF(res != NO_ERROR, "%s: Unable to start worker thread", __FUNCTION__);
204 return res;
205 }
206
stopWorkerThread()207 status_t EmulatedCameraDevice::stopWorkerThread()
208 {
209 LOGV("%s", __FUNCTION__);
210
211 if (!isInitialized()) {
212 LOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
213 return EINVAL;
214 }
215
216 const status_t res = getWorkerThread()->stopThread();
217 LOGE_IF(res != NO_ERROR, "%s: Unable to stop worker thread", __FUNCTION__);
218 return res;
219 }
220
inWorkerThread()221 bool EmulatedCameraDevice::inWorkerThread()
222 {
223 /* This will end the thread loop, and will terminate the thread. Derived
224 * classes must override this method. */
225 return false;
226 }
227
228 /****************************************************************************
229 * Worker thread implementation.
230 ***************************************************************************/
231
readyToRun()232 status_t EmulatedCameraDevice::WorkerThread::readyToRun()
233 {
234 LOGV("Starting emulated camera device worker thread...");
235
236 LOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
237 "%s: Thread control FDs are opened", __FUNCTION__);
238 /* Create a pair of FDs that would be used to control the thread. */
239 int thread_fds[2];
240 if (pipe(thread_fds) == 0) {
241 mThreadControl = thread_fds[1];
242 mControlFD = thread_fds[0];
243 LOGV("Emulated device's worker thread has been started.");
244 return NO_ERROR;
245 } else {
246 LOGE("%s: Unable to create thread control FDs: %d -> %s",
247 __FUNCTION__, errno, strerror(errno));
248 return errno;
249 }
250 }
251
stopThread()252 status_t EmulatedCameraDevice::WorkerThread::stopThread()
253 {
254 LOGV("Stopping emulated camera device's worker thread...");
255
256 status_t res = EINVAL;
257 if (mThreadControl >= 0) {
258 /* Send "stop" message to the thread loop. */
259 const ControlMessage msg = THREAD_STOP;
260 const int wres =
261 TEMP_FAILURE_RETRY(write(mThreadControl, &msg, sizeof(msg)));
262 if (wres == sizeof(msg)) {
263 /* Stop the thread, and wait till it's terminated. */
264 res = requestExitAndWait();
265 if (res == NO_ERROR) {
266 /* Close control FDs. */
267 if (mThreadControl >= 0) {
268 close(mThreadControl);
269 mThreadControl = -1;
270 }
271 if (mControlFD >= 0) {
272 close(mControlFD);
273 mControlFD = -1;
274 }
275 LOGV("Emulated camera device's worker thread has been stopped.");
276 } else {
277 LOGE("%s: requestExitAndWait failed: %d -> %s",
278 __FUNCTION__, res, strerror(-res));
279 }
280 } else {
281 LOGE("%s: Unable to send THREAD_STOP message: %d -> %s",
282 __FUNCTION__, errno, strerror(errno));
283 res = errno ? errno : EINVAL;
284 }
285 } else {
286 LOGE("%s: Thread control FDs are not opened", __FUNCTION__);
287 }
288
289 return res;
290 }
291
292 EmulatedCameraDevice::WorkerThread::SelectRes
Select(int fd,int timeout)293 EmulatedCameraDevice::WorkerThread::Select(int fd, int timeout)
294 {
295 fd_set fds[1];
296 struct timeval tv, *tvp = NULL;
297
298 const int fd_num = (fd >= 0) ? max(fd, mControlFD) + 1 :
299 mControlFD + 1;
300 FD_ZERO(fds);
301 FD_SET(mControlFD, fds);
302 if (fd >= 0) {
303 FD_SET(fd, fds);
304 }
305 if (timeout) {
306 tv.tv_sec = timeout / 1000000;
307 tv.tv_usec = timeout % 1000000;
308 tvp = &tv;
309 }
310 int res = TEMP_FAILURE_RETRY(select(fd_num, fds, NULL, NULL, tvp));
311 if (res < 0) {
312 LOGE("%s: select returned %d and failed: %d -> %s",
313 __FUNCTION__, res, errno, strerror(errno));
314 return ERROR;
315 } else if (res == 0) {
316 /* Timeout. */
317 return TIMEOUT;
318 } else if (FD_ISSET(mControlFD, fds)) {
319 /* A control event. Lets read the message. */
320 ControlMessage msg;
321 res = TEMP_FAILURE_RETRY(read(mControlFD, &msg, sizeof(msg)));
322 if (res != sizeof(msg)) {
323 LOGE("%s: Unexpected message size %d, or an error %d -> %s",
324 __FUNCTION__, res, errno, strerror(errno));
325 return ERROR;
326 }
327 /* THREAD_STOP is the only message expected here. */
328 if (msg == THREAD_STOP) {
329 LOGV("%s: THREAD_STOP message is received", __FUNCTION__);
330 return EXIT_THREAD;
331 } else {
332 LOGE("Unknown worker thread message %d", msg);
333 return ERROR;
334 }
335 } else {
336 /* Must be an FD. */
337 LOGW_IF(fd < 0 || !FD_ISSET(fd, fds), "%s: Undefined 'select' result",
338 __FUNCTION__);
339 return READY;
340 }
341 }
342
343 }; /* namespace android */
344