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