• 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 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