OSDN Git Service

Make fake camera frames resolution independent
authorBjoern Johansson <bjoernj@google.com>
Fri, 7 Oct 2016 18:25:00 +0000 (11:25 -0700)
committerBjoern Johansson <bjoernj@google.com>
Wed, 11 Jan 2017 21:03:23 +0000 (13:03 -0800)
Make the generation of the checkerboard frames resolution independent
so that the frames look the same after changing resolution. This allows
seamless switches between resolutions without any noticable differences.
This change also modifies the animation of the moving square so that it
now bounces off the edges of the frame instead of a 255x255 invisible
square. This is to ensure that the square ends up in a place that does
not depend on a fixed pixel location. Instead it will appear in a
similar location regardless of resolution. This satisfies a newly added
test in the N CTS tests that will compare preview frames at certain
resolutions with the JPEG created when taking a picture.

BUG: 31913409
Test: ran camera CTS tests
Change-Id: I12fc47aaf3ed678383b70d6e91060e05aaf41452
(cherry picked from commit 1ac0584457f60b314a90fa6233c52c0d8ebb1ade)

camera/EmulatedFakeCameraDevice.cpp
camera/EmulatedFakeCameraDevice.h

index a5f8b1d..d59cdbf 100755 (executable)
 
 namespace android {
 
+static const double kCheckXSpeed = 0.00000000096;
+static const double kCheckYSpeed = 0.00000000032;
+
+static const double kSquareXSpeed = 0.000000000096;
+static const double kSquareYSpeed = 0.000000000160;
+
+static const nsecs_t kSquareColorChangeIntervalNs = seconds(5);
+
 EmulatedFakeCameraDevice::EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal)
     : EmulatedCameraDevice(camera_hal),
       mBlackYUV(kBlack32),
@@ -38,10 +46,15 @@ EmulatedFakeCameraDevice::EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_ha
       mRedYUV(kRed8),
       mGreenYUV(kGreen8),
       mBlueYUV(kBlue8),
+      mSquareColor(&mRedYUV),
       mLastRedrawn(0),
+      mLastColorChange(0),
       mCheckX(0),
       mCheckY(0),
-      mCcounter(0)
+      mSquareX(0),
+      mSquareY(0),
+      mSquareXSpeed(kSquareXSpeed),
+      mSquareYSpeed(kSquareYSpeed)
 #if EFCD_ROTATE_FRAME
       , mLastRotatedAt(0),
         mCurrentFrameType(0),
@@ -158,6 +171,8 @@ status_t EmulatedFakeCameraDevice::startDevice(int width,
                      reinterpret_cast<const char*>(&mPixelFormat));
                 return EINVAL;
         }
+        mLastRedrawn = systemTime(SYSTEM_TIME_MONOTONIC);
+        mLastColorChange = mLastRedrawn;
         /* Number of items in a single row inside U/V panes. */
         mUVInRow = (width / 2) * mUVStep;
         mState = ECDS_STARTED;
@@ -215,11 +230,13 @@ bool EmulatedFakeCameraDevice::produceFrame(void* buffer)
 
 void EmulatedFakeCameraDevice::drawCheckerboard(void* buffer)
 {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t elapsed = now - mLastRedrawn;
     uint8_t* currentFrame = reinterpret_cast<uint8_t*>(buffer);
     uint8_t* frameU = currentFrame + mFrameUOffset;
     uint8_t* frameV = currentFrame + mFrameVOffset;
 
-    const int size = mFrameWidth / 10;
+    const int size = std::min(mFrameWidth, mFrameHeight) / 10;
     bool black = true;
 
     if (size == 0) {
@@ -228,17 +245,34 @@ void EmulatedFakeCameraDevice::drawCheckerboard(void* buffer)
         return;
     }
 
+    mCheckX += kCheckXSpeed * elapsed;
+    mCheckY += kCheckYSpeed * elapsed;
+
+    // Allow the X and Y values to transition across two checkerboard boxes
+    // before resetting it back. This allows for the gray to black transition.
+    // Note that this is in screen size independent coordinates so that frames
+    // will look similar regardless of resolution
+    if (mCheckX > 2.0) {
+        mCheckX -= 2.0;
+    }
+    if (mCheckY > 2.0) {
+        mCheckY -= 2.0;
+    }
 
-    if((mCheckX / size) & 1)
+    // Are we in the gray or black zone?
+    if (mCheckX >= 1.0)
         black = false;
-    if((mCheckY / size) & 1)
+    if (mCheckY >= 1.0)
         black = !black;
 
-    int county = mCheckY % size;
-    int checkxremainder = mCheckX % size;
+    int county = static_cast<int>(mCheckY * size) % size;
+    int checkxremainder = static_cast<int>(mCheckX * size) % size;
 
     YUVPixel adjustedWhite = YUVPixel(mWhiteYUV);
     changeWhiteBalance(adjustedWhite.Y, adjustedWhite.U, adjustedWhite.V);
+    adjustedWhite.Y = changeExposure(adjustedWhite.Y);
+    YUVPixel adjustedBlack = YUVPixel(mBlackYUV);
+    adjustedBlack.Y = changeExposure(adjustedBlack.Y);
 
     for(int y = 0; y < mFrameHeight; y++) {
         int countx = checkxremainder;
@@ -248,11 +282,10 @@ void EmulatedFakeCameraDevice::drawCheckerboard(void* buffer)
         uint8_t* V = frameV + mUVStride * (y / 2);
         for(int x = 0; x < mFrameWidth; x += 2) {
             if (current) {
-                mBlackYUV.get(Y, U, V);
+                adjustedBlack.get(Y, U, V);
             } else {
                 adjustedWhite.get(Y, U, V);
             }
-            *Y = changeExposure(*Y);
             Y[1] = *Y;
             Y += 2; U += mUVStep; V += mUVStep;
             countx += 2;
@@ -266,18 +299,35 @@ void EmulatedFakeCameraDevice::drawCheckerboard(void* buffer)
             black = !black;
         }
     }
-    mCheckX += 3;
-    mCheckY++;
 
     /* Run the square. */
-    int sqx = ((mCcounter * 3) & 255);
-    if(sqx > 128) sqx = 255 - sqx;
-    int sqy = ((mCcounter * 5) & 255);
-    if(sqy > 128) sqy = 255 - sqy;
-    const int sqsize = mFrameWidth / 10;
-    drawSquare(buffer, sqx * sqsize / 32, sqy * sqsize / 32, (sqsize * 5) >> 1,
-               (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
-    mCcounter++;
+    const int squareSize = std::min(mFrameWidth, mFrameHeight) / 4;
+    mSquareX += mSquareXSpeed * elapsed;
+    mSquareY += mSquareYSpeed * elapsed;
+    int squareX = mSquareX * mFrameWidth;
+    int squareY = mSquareY * mFrameHeight;
+    if (squareX + squareSize > mFrameWidth) {
+        mSquareXSpeed = -mSquareXSpeed;
+        squareX -= 2 * (squareX + squareSize - mFrameWidth);
+    } else if (squareX < 0) {
+        mSquareXSpeed = -mSquareXSpeed;
+        squareX = -squareX;
+    }
+    if (squareY + squareSize > mFrameHeight) {
+        mSquareYSpeed = -mSquareYSpeed;
+        squareY -= 2 * (squareY + squareSize - mFrameHeight);
+    } else if (squareY < 0) {
+        mSquareYSpeed = -mSquareYSpeed;
+        squareY = -squareY;
+    }
+
+    if (now - mLastColorChange > kSquareColorChangeIntervalNs) {
+        mLastColorChange = now;
+        mSquareColor = mSquareColor == &mRedYUV ? &mGreenYUV : &mRedYUV;
+    }
+
+    drawSquare(buffer, squareX, squareY, squareSize, mSquareColor);
+    mLastRedrawn = now;
 }
 
 void EmulatedFakeCameraDevice::drawSquare(void* buffer,
index fabe550..a3e9201 100755 (executable)
@@ -125,6 +125,7 @@ private:
     YUVPixel    mRedYUV;
     YUVPixel    mGreenYUV;
     YUVPixel    mBlueYUV;
+    YUVPixel*   mSquareColor;
 
     /* Last time the frame has been redrawn. */
     nsecs_t     mLastRedrawn;
@@ -150,14 +151,14 @@ private:
     /*
      * Checkerboard drawing related stuff
      */
-
-    int         mCheckX;
-    int         mCheckY;
-    int         mCcounter;
-
-    /* Defines time (in nanoseconds) between redrawing the checker board.
-     * We will redraw the checker board every 15 milliseconds. */
-    static const nsecs_t    mRedrawAfter = 15000000LL;
+    nsecs_t     mLastColorChange;
+
+    double      mCheckX;
+    double      mCheckY;
+    double      mSquareX;
+    double      mSquareY;
+    double      mSquareXSpeed;
+    double      mSquareYSpeed;
 
 #if EFCD_ROTATE_FRAME
     /* Frame rotation frequency in nanosec (currently - 3 sec) */