• Home
  • History
  • Annotate
  • 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 <cutils/log.h>
26  #include "EmulatedFakeCamera.h"
27  
28  namespace android {
29  
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  
58  EmulatedFakeCameraDevice::~EmulatedFakeCameraDevice() {}
59  
60  /****************************************************************************
61   * Emulated camera device abstract interface implementation.
62   ***************************************************************************/
63  
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  
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  
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  
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  
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  
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  
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  
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  
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  
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