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