• 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 EmulatedFakeCameraDevice that encapsulates
19  * fake camera device.
20  */
21 
22 #define LOG_NDEBUG 0
23 #define LOG_TAG "EmulatedCamera_FakeDevice"
24 #include <cutils/log.h>
25 #include "EmulatedFakeCamera.h"
26 #include "EmulatedFakeCameraDevice.h"
27 
28 namespace android {
29 
EmulatedFakeCameraDevice(EmulatedFakeCamera * camera_hal)30 EmulatedFakeCameraDevice::EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal)
31     : EmulatedCameraDevice(camera_hal),
32       mBlackYUV(kBlack32),
33       mWhiteYUV(kWhite32),
34       mRedYUV(kRed8),
35       mGreenYUV(kGreen8),
36       mBlueYUV(kBlue8),
37       mLastRedrawn(0),
38       mCheckX(0),
39       mCheckY(0),
40       mCcounter(0)
41 #if EFCD_ROTATE_FRAME
42       , mLastRotatedAt(0),
43         mCurrentFrameType(0),
44         mCurrentColor(&mWhiteYUV)
45 #endif  // EFCD_ROTATE_FRAME
46 {
47 }
48 
~EmulatedFakeCameraDevice()49 EmulatedFakeCameraDevice::~EmulatedFakeCameraDevice()
50 {
51 }
52 
53 /****************************************************************************
54  * Emulated camera device abstract interface implementation.
55  ***************************************************************************/
56 
connectDevice()57 status_t EmulatedFakeCameraDevice::connectDevice()
58 {
59     LOGV("%s", __FUNCTION__);
60 
61     Mutex::Autolock locker(&mObjectLock);
62     if (!isInitialized()) {
63         LOGE("%s: Fake camera device is not initialized.", __FUNCTION__);
64         return EINVAL;
65     }
66     if (isConnected()) {
67         LOGW("%s: Fake camera device is already connected.", __FUNCTION__);
68         return NO_ERROR;
69     }
70 
71     /* There is no device to connect to. */
72     mState = ECDS_CONNECTED;
73 
74     return NO_ERROR;
75 }
76 
disconnectDevice()77 status_t EmulatedFakeCameraDevice::disconnectDevice()
78 {
79     LOGV("%s", __FUNCTION__);
80 
81     Mutex::Autolock locker(&mObjectLock);
82     if (!isConnected()) {
83         LOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
84         return NO_ERROR;
85     }
86     if (isStarted()) {
87         LOGE("%s: Cannot disconnect from the started device.", __FUNCTION__);
88         return EINVAL;
89     }
90 
91     /* There is no device to disconnect from. */
92     mState = ECDS_INITIALIZED;
93 
94     return NO_ERROR;
95 }
96 
startDevice(int width,int height,uint32_t pix_fmt)97 status_t EmulatedFakeCameraDevice::startDevice(int width,
98                                                int height,
99                                                uint32_t pix_fmt)
100 {
101     LOGV("%s", __FUNCTION__);
102 
103     Mutex::Autolock locker(&mObjectLock);
104     if (!isConnected()) {
105         LOGE("%s: Fake camera device is not connected.", __FUNCTION__);
106         return EINVAL;
107     }
108     if (isStarted()) {
109         LOGE("%s: Fake camera device is already started.", __FUNCTION__);
110         return EINVAL;
111     }
112 
113     /* Initialize the base class. */
114     const status_t res =
115         EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
116     if (res == NO_ERROR) {
117         /* Calculate U/V panes inside the framebuffer. */
118         switch (mPixelFormat) {
119             case V4L2_PIX_FMT_YVU420:
120                 mFrameV = mCurrentFrame + mTotalPixels;
121                 mFrameU = mFrameU + mTotalPixels / 4;
122                 mUVStep = 1;
123                 mUVTotalNum = mTotalPixels / 4;
124                 break;
125 
126             case V4L2_PIX_FMT_YUV420:
127                 mFrameU = mCurrentFrame + mTotalPixels;
128                 mFrameV = mFrameU + mTotalPixels / 4;
129                 mUVStep = 1;
130                 mUVTotalNum = mTotalPixels / 4;
131                 break;
132 
133             case V4L2_PIX_FMT_NV21:
134                 /* Interleaved UV pane, V first. */
135                 mFrameV = mCurrentFrame + mTotalPixels;
136                 mFrameU = mFrameV + 1;
137                 mUVStep = 2;
138                 mUVTotalNum = mTotalPixels / 4;
139                 break;
140 
141             case V4L2_PIX_FMT_NV12:
142                 /* Interleaved UV pane, U first. */
143                 mFrameU = mCurrentFrame + mTotalPixels;
144                 mFrameV = mFrameU + 1;
145                 mUVStep = 2;
146                 mUVTotalNum = mTotalPixels / 4;
147                 break;
148 
149             default:
150                 LOGE("%s: Unknown pixel format %.4s", __FUNCTION__,
151                      reinterpret_cast<const char*>(&mPixelFormat));
152                 return EINVAL;
153         }
154         /* Number of items in a single row inside U/V panes. */
155         mUVInRow = (width / 2) * mUVStep;
156         mState = ECDS_STARTED;
157     } else {
158         LOGE("%s: commonStartDevice failed", __FUNCTION__);
159     }
160 
161     return res;
162 }
163 
stopDevice()164 status_t EmulatedFakeCameraDevice::stopDevice()
165 {
166     LOGV("%s", __FUNCTION__);
167 
168     Mutex::Autolock locker(&mObjectLock);
169     if (!isStarted()) {
170         LOGW("%s: Fake camera device is not started.", __FUNCTION__);
171         return NO_ERROR;
172     }
173 
174     mFrameU = mFrameV = NULL;
175     EmulatedCameraDevice::commonStopDevice();
176     mState = ECDS_CONNECTED;
177 
178     return NO_ERROR;
179 }
180 
181 /****************************************************************************
182  * Worker thread management overrides.
183  ***************************************************************************/
184 
inWorkerThread()185 bool EmulatedFakeCameraDevice::inWorkerThread()
186 {
187     /* Wait till FPS timeout expires, or thread exit message is received. */
188     WorkerThread::SelectRes res =
189         getWorkerThread()->Select(-1, 1000000 / mEmulatedFPS);
190     if (res == WorkerThread::EXIT_THREAD) {
191         LOGV("%s: Worker thread has been terminated.", __FUNCTION__);
192         return false;
193     }
194 
195     /* Lets see if we need to generate a new frame. */
196     if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRedrawn) >= mRedrawAfter) {
197         /*
198          * Time to generate a new frame.
199          */
200 
201 #if EFCD_ROTATE_FRAME
202         const int frame_type = rotateFrame();
203         switch (frame_type) {
204             case 0:
205                 drawCheckerboard();
206                 break;
207             case 1:
208                 drawStripes();
209                 break;
210             case 2:
211                 drawSolid(mCurrentColor);
212                 break;
213         }
214 #else
215         /* Draw the checker board. */
216         drawCheckerboard();
217 
218 #endif  // EFCD_ROTATE_FRAME
219 
220         mLastRedrawn = systemTime(SYSTEM_TIME_MONOTONIC);
221     }
222 
223     /* Timestamp the current frame, and notify the camera HAL about new frame. */
224     mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
225     mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
226 
227     return true;
228 }
229 
230 /****************************************************************************
231  * Fake camera device private API
232  ***************************************************************************/
233 
drawCheckerboard()234 void EmulatedFakeCameraDevice::drawCheckerboard()
235 {
236     const int size = mFrameWidth / 10;
237     bool black = true;
238 
239     if((mCheckX / size) & 1)
240         black = false;
241     if((mCheckY / size) & 1)
242         black = !black;
243 
244     int county = mCheckY % size;
245     int checkxremainder = mCheckX % size;
246     uint8_t* Y = mCurrentFrame;
247     uint8_t* U_pos = mFrameU;
248     uint8_t* V_pos = mFrameV;
249     uint8_t* U = U_pos;
250     uint8_t* V = V_pos;
251 
252     for(int y = 0; y < mFrameHeight; y++) {
253         int countx = checkxremainder;
254         bool current = black;
255         for(int x = 0; x < mFrameWidth; x += 2) {
256             if (current) {
257                 mBlackYUV.get(Y, U, V);
258             } else {
259                 mWhiteYUV.get(Y, U, V);
260             }
261             Y[1] = *Y;
262             Y += 2; U += mUVStep; V += mUVStep;
263             countx += 2;
264             if(countx >= size) {
265                 countx = 0;
266                 current = !current;
267             }
268         }
269         if (y & 0x1) {
270             U_pos = U;
271             V_pos = V;
272         } else {
273             U = U_pos;
274             V = V_pos;
275         }
276         if(county++ >= size) {
277             county = 0;
278             black = !black;
279         }
280     }
281     mCheckX += 3;
282     mCheckY++;
283 
284     /* Run the square. */
285     int sqx = ((mCcounter * 3) & 255);
286     if(sqx > 128) sqx = 255 - sqx;
287     int sqy = ((mCcounter * 5) & 255);
288     if(sqy > 128) sqy = 255 - sqy;
289     const int sqsize = mFrameWidth / 10;
290     drawSquare(sqx * sqsize / 32, sqy * sqsize / 32, (sqsize * 5) >> 1,
291                (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
292     mCcounter++;
293 }
294 
drawSquare(int x,int y,int size,const YUVPixel * color)295 void EmulatedFakeCameraDevice::drawSquare(int x,
296                                           int y,
297                                           int size,
298                                           const YUVPixel* color)
299 {
300     const int square_xstop = min(mFrameWidth, x + size);
301     const int square_ystop = min(mFrameHeight, y + size);
302     uint8_t* Y_pos = mCurrentFrame + y * mFrameWidth + x;
303 
304     // Draw the square.
305     for (; y < square_ystop; y++) {
306         const int iUV = (y / 2) * mUVInRow + (x / 2) * mUVStep;
307         uint8_t* sqU = mFrameU + iUV;
308         uint8_t* sqV = mFrameV + iUV;
309         uint8_t* sqY = Y_pos;
310         for (int i = x; i < square_xstop; i += 2) {
311             color->get(sqY, sqU, sqV);
312             sqY[1] = *sqY;
313             sqY += 2; sqU += mUVStep; sqV += mUVStep;
314         }
315         Y_pos += mFrameWidth;
316     }
317 }
318 
319 #if EFCD_ROTATE_FRAME
320 
drawSolid(YUVPixel * color)321 void EmulatedFakeCameraDevice::drawSolid(YUVPixel* color)
322 {
323     /* All Ys are the same. */
324     memset(mCurrentFrame, color->Y, mTotalPixels);
325 
326     /* Fill U, and V panes. */
327     uint8_t* U = mFrameU;
328     uint8_t* V = mFrameV;
329     for (int k = 0; k < mUVTotalNum; k++, U += mUVStep, V += mUVStep) {
330         *U = color->U;
331         *V = color->V;
332     }
333 }
334 
drawStripes()335 void EmulatedFakeCameraDevice::drawStripes()
336 {
337     /* Divide frame into 4 stripes. */
338     const int change_color_at = mFrameHeight / 4;
339     const int each_in_row = mUVInRow / mUVStep;
340     uint8_t* pY = mCurrentFrame;
341     for (int y = 0; y < mFrameHeight; y++, pY += mFrameWidth) {
342         /* Select the color. */
343         YUVPixel* color;
344         const int color_index = y / change_color_at;
345         if (color_index == 0) {
346             /* White stripe on top. */
347             color = &mWhiteYUV;
348         } else if (color_index == 1) {
349             /* Then the red stripe. */
350             color = &mRedYUV;
351         } else if (color_index == 2) {
352             /* Then the green stripe. */
353             color = &mGreenYUV;
354         } else {
355             /* And the blue stripe at the bottom. */
356             color = &mBlueYUV;
357         }
358 
359         /* All Ys at the row are the same. */
360         memset(pY, color->Y, mFrameWidth);
361 
362         /* Offset of the current row inside U/V panes. */
363         const int uv_off = (y / 2) * mUVInRow;
364         /* Fill U, and V panes. */
365         uint8_t* U = mFrameU + uv_off;
366         uint8_t* V = mFrameV + uv_off;
367         for (int k = 0; k < each_in_row; k++, U += mUVStep, V += mUVStep) {
368             *U = color->U;
369             *V = color->V;
370         }
371     }
372 }
373 
rotateFrame()374 int EmulatedFakeCameraDevice::rotateFrame()
375 {
376     if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRotatedAt) >= mRotateFreq) {
377         mLastRotatedAt = systemTime(SYSTEM_TIME_MONOTONIC);
378         mCurrentFrameType++;
379         if (mCurrentFrameType > 2) {
380             mCurrentFrameType = 0;
381         }
382         if (mCurrentFrameType == 2) {
383             LOGD("********** Rotated to the SOLID COLOR frame **********");
384             /* Solid color: lets rotate color too. */
385             if (mCurrentColor == &mWhiteYUV) {
386                 LOGD("----- Painting a solid RED frame -----");
387                 mCurrentColor = &mRedYUV;
388             } else if (mCurrentColor == &mRedYUV) {
389                 LOGD("----- Painting a solid GREEN frame -----");
390                 mCurrentColor = &mGreenYUV;
391             } else if (mCurrentColor == &mGreenYUV) {
392                 LOGD("----- Painting a solid BLUE frame -----");
393                 mCurrentColor = &mBlueYUV;
394             } else {
395                 /* Back to white. */
396                 LOGD("----- Painting a solid WHITE frame -----");
397                 mCurrentColor = &mWhiteYUV;
398             }
399         } else if (mCurrentFrameType == 0) {
400             LOGD("********** Rotated to the CHECKERBOARD frame **********");
401         } else {
402             LOGD("********** Rotated to the STRIPED frame **********");
403         }
404     }
405 
406     return mCurrentFrameType;
407 }
408 
409 #endif  // EFCD_ROTATE_FRAME
410 
411 }; /* namespace android */
412