Home | History | Annotate | Download | only in camera
      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 
     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