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 <cutils/log.h>
     25 #include "EmulatedFakeCamera.h"
     26 #include "EmulatedFakeCameraDevice.h"
     27 
     28 namespace android {
     29 
     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 
     49 EmulatedFakeCameraDevice::~EmulatedFakeCameraDevice()
     50 {
     51 }
     52 
     53 /****************************************************************************
     54  * Emulated camera device abstract interface implementation.
     55  ***************************************************************************/
     56 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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