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