Correct camera YV12 format usage

The camera code incorrectly generated and decoded YV12 encoded images.
The format requires that row strides are aligned to 16 bytes which
introduces padding at some of the resolution that the camera supports,
most notably 176x144 where half of 176 is not divisible by 16. The width
is halved because the U and V components each cover 2x2 pixel blocks so
the effective width of each row is 88 pixels, this has to be padded to 96
bytes. This change ensures that the images generated by the fake camera
have the required alignment and also that decoding the YV12 images to RGB
for the preview window correctly takes the alignment into consideration.

BUG: 30700822
Test: ran camera CTS tests
Change-Id: I16590551af59c730c0c8b024dbaee40f5c8e9ab2
(cherry picked from commit ddeced00136c1299dfca1ea5066f23b5ada2a142)
diff --git a/camera/Alignment.h b/camera/Alignment.h
new file mode 100644
index 0000000..4619d5e
--- /dev/null
+++ b/camera/Alignment.h
@@ -0,0 +1,14 @@
+#ifndef HW_EMULATOR_CAMERA_ALIGNMENT_H
+#define HW_EMULATOR_CAMERA_ALIGNMENT_H
+
+namespace android {
+
+// Align |value| to the next larger value that is divisible by |alignment|
+// |alignment| has to be a power of 2.
+inline int align(int value, int alignment) {
+    return (value + alignment - 1) & (~(alignment - 1));
+}
+
+}  // namespace android
+
+#endif  // HW_EMULATOR_CAMERA_ALIGNMENT_H
diff --git a/camera/Converters.cpp b/camera/Converters.cpp
index f63f67f..4765bf2 100755
--- a/camera/Converters.cpp
+++ b/camera/Converters.cpp
@@ -23,6 +23,8 @@
 #include <cutils/log.h>
 #include "Converters.h"
 
+#include "Alignment.h"
+
 namespace android {
 
 static void _YUV420SToRGB565(const uint8_t* Y,
@@ -31,12 +33,18 @@
                              int dUV,
                              uint16_t* rgb,
                              int width,
-                             int height)
+                             int height,
+                             int y_stride,
+                             int uv_stride)
 {
+    const uint8_t* Y_pos = Y;
     const uint8_t* U_pos = U;
     const uint8_t* V_pos = V;
 
     for (int y = 0; y < height; y++) {
+        Y = Y_pos + y_stride * y;
+        U = U_pos + uv_stride * (y / 2);
+        V = V_pos + uv_stride * (y / 2);
         for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
             const uint8_t nU = *U;
             const uint8_t nV = *V;
@@ -45,13 +53,6 @@
             *rgb = YUVToRGB565(*Y, nU, nV);
             Y++; rgb++;
         }
-        if (y & 0x1) {
-            U_pos = U;
-            V_pos = V;
-        } else {
-            U = U_pos;
-            V = V_pos;
-        }
     }
 }
 
@@ -61,12 +62,18 @@
                             int dUV,
                             uint32_t* rgb,
                             int width,
-                            int height)
+                            int height,
+                            int y_stride,
+                            int uv_stride)
 {
+    const uint8_t* Y_pos = Y;
     const uint8_t* U_pos = U;
     const uint8_t* V_pos = V;
 
     for (int y = 0; y < height; y++) {
+        Y = Y_pos + y_stride * y;
+        U = U_pos + uv_stride * (y / 2);
+        V = V_pos + uv_stride * (y / 2);
         for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
             const uint8_t nU = *U;
             const uint8_t nV = *V;
@@ -75,41 +82,51 @@
             *rgb = YUVToRGB32(*Y, nU, nV);
             Y++; rgb++;
         }
-        if (y & 0x1) {
-            U_pos = U;
-            V_pos = V;
-        } else {
-            U = U_pos;
-            V = V_pos;
-        }
     }
 }
 
+/* The YV12 and YU12 formats require that the row strides are aligned to 16 byte
+ * boundaries as per the format specification at:
+ * https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
+ *
+ * This means that we can't just use the width or assume that pixels are
+ * tightly packed, we have to calculate aligned strides and use them to find the
+ * next row.
+ */
 void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
 {
-    const int pix_total = width * height;
+    // See note above about alignment
+    const int y_stride = align(width, 16);
+    const int uv_stride = align(y_stride / 2, 16);
     const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
-    const uint8_t* U = Y + pix_total;
-    const uint8_t* V = U + pix_total / 4;
-    _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb), width, height);
+    const uint8_t* U = Y + y_stride * height;
+    const uint8_t* V = U + uv_stride * (height / 2);
+    _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb),
+                     width, height, y_stride, uv_stride);
 }
 
 void YV12ToRGB32(const void* yv12, void* rgb, int width, int height)
 {
-    const int pix_total = width * height;
+    // See note above about alignment
+    const int y_stride = align(width, 16);
+    const int uv_stride = align(y_stride / 2, 16);
     const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
-    const uint8_t* V = Y + pix_total;
-    const uint8_t* U = V + pix_total / 4;
-    _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
+    const uint8_t* V = Y + y_stride * height;
+    const uint8_t* U = V + uv_stride * (height / 2);
+    _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height,
+                    y_stride, uv_stride);
 }
 
 void YU12ToRGB32(const void* yu12, void* rgb, int width, int height)
 {
-    const int pix_total = width * height;
+    // See note above about alignment
+    const int y_stride = align(width, 16);
+    const int uv_stride = align(y_stride / 2, 16);
     const uint8_t* Y = reinterpret_cast<const uint8_t*>(yu12);
-    const uint8_t* U = Y + pix_total;
-    const uint8_t* V = U + pix_total / 4;
-    _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
+    const uint8_t* U = Y + y_stride * height;
+    const uint8_t* V = U + uv_stride * (height / 2);
+    _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height,
+                    y_stride, uv_stride);
 }
 
 /* Common converter for YUV 4:2:0 interleaved to RGB565.
@@ -122,7 +139,13 @@
                           int width,
                           int height)
 {
-    _YUV420SToRGB565(Y, U, V, 2, rgb, width, height);
+    // The UV stride for NV21 and NV12 is the same as the width because the
+    // U and V values are interleaved, making each row twice as wide even though
+    // each value covers a two pixel wide area. These formats do not require any
+    // kind of alignment.
+    int y_stride = width;
+    int uv_stride = width;
+    _YUV420SToRGB565(Y, U, V, 2, rgb, width, height, y_stride, uv_stride);
 }
 
 /* Common converter for YUV 4:2:0 interleaved to RGB32.
@@ -135,7 +158,13 @@
                          int width,
                          int height)
 {
-    _YUV420SToRGB32(Y, U, V, 2, rgb, width, height);
+    // The UV stride for NV21 and NV12 is the same as the width because the
+    // U and V values are interleaved, making each row twice as wide even though
+    // each value covers a two pixel wide area. These formats do not require any
+    // kind of alignment.
+    int y_stride = width;
+    int uv_stride = width;
+    _YUV420SToRGB32(Y, U, V, 2, rgb, width, height, y_stride, uv_stride);
 }
 
 void NV12ToRGB565(const void* nv12, void* rgb, int width, int height)
diff --git a/camera/EmulatedCameraDevice.cpp b/camera/EmulatedCameraDevice.cpp
index c8e5640..ed5a2a2 100755
--- a/camera/EmulatedCameraDevice.cpp
+++ b/camera/EmulatedCameraDevice.cpp
@@ -30,6 +30,8 @@
 #include <cmath>
 #include "EmulatedCameraDevice.h"
 
+#include "Alignment.h"
+
 namespace android {
 
 const float GAMMA_CORRECTION = 2.2f;
@@ -200,11 +202,24 @@
     switch (pix_fmt) {
         case V4L2_PIX_FMT_YVU420:
         case V4L2_PIX_FMT_YUV420:
+            // For these pixel formats the strides have to be aligned to 16 byte
+            // boundaries as per the format specification
+            // https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
+            mYStride = align(width, 16);
+            mUVStride = align(mYStride / 2, 16);
+            // The second term should use half the height but since there are
+            // two planes the multiplication with two cancels that out
+            mFrameBufferSize = mYStride * height + mUVStride * height;
+            break;
         case V4L2_PIX_FMT_NV21:
         case V4L2_PIX_FMT_NV12:
-            mFrameBufferSize = (width * height * 12) / 8;
+            mYStride = width;
+            // Because of interleaving the UV stride is the same as the Y stride
+            // since it covers two pixels, one U and one V.
+            mUVStride = mYStride;
+            // Since the U/V stride covers both U and V we don't multiply by two
+            mFrameBufferSize = mYStride * height + mUVStride * (height / 2);
             break;
-
         default:
             ALOGE("%s: Unknown pixel format %.4s",
                  __FUNCTION__, reinterpret_cast<const char*>(&pix_fmt));
diff --git a/camera/EmulatedCameraDevice.h b/camera/EmulatedCameraDevice.h
index fff11fa..da144cb 100755
--- a/camera/EmulatedCameraDevice.h
+++ b/camera/EmulatedCameraDevice.h
@@ -514,6 +514,16 @@
     /* Frame height */
     int                         mFrameHeight;
 
+    /* Defines byte distance between the start of each Y row */
+    int                         mYStride;
+
+    /* Defines byte distance between the start of each U/V row. For formats with
+     * separate U and V planes this is the distance between rows in each plane.
+     * For formats with interleaved U and V components this is the distance
+     * between rows in the interleaved plane, meaning that it's the stride over
+     * the combined U and V components. */
+    int                         mUVStride;
+
     /* Total number of pixels */
     int                         mTotalPixels;
 
diff --git a/camera/EmulatedFakeCameraDevice.cpp b/camera/EmulatedFakeCameraDevice.cpp
index 4afadc1..10e3c67 100755
--- a/camera/EmulatedFakeCameraDevice.cpp
+++ b/camera/EmulatedFakeCameraDevice.cpp
@@ -124,33 +124,29 @@
         /* Calculate U/V panes inside the framebuffer. */
         switch (mPixelFormat) {
             case V4L2_PIX_FMT_YVU420:
-                mFrameV = mCurrentFrame + mTotalPixels;
-                mFrameU = mFrameU + mTotalPixels / 4;
+                mFrameV = mCurrentFrame + mYStride * mFrameHeight;
+                mFrameU = mFrameV + mUVStride * (mFrameHeight / 2);
                 mUVStep = 1;
-                mUVTotalNum = mTotalPixels / 4;
                 break;
 
             case V4L2_PIX_FMT_YUV420:
-                mFrameU = mCurrentFrame + mTotalPixels;
-                mFrameV = mFrameU + mTotalPixels / 4;
+                mFrameU = mCurrentFrame + mYStride * mFrameHeight;
+                mFrameV = mFrameU + mUVStride * (mFrameHeight / 2);
                 mUVStep = 1;
-                mUVTotalNum = mTotalPixels / 4;
                 break;
 
             case V4L2_PIX_FMT_NV21:
                 /* Interleaved UV pane, V first. */
-                mFrameV = mCurrentFrame + mTotalPixels;
+                mFrameV = mCurrentFrame + mYStride * mFrameHeight;
                 mFrameU = mFrameV + 1;
                 mUVStep = 2;
-                mUVTotalNum = mTotalPixels / 4;
                 break;
 
             case V4L2_PIX_FMT_NV12:
                 /* Interleaved UV pane, U first. */
-                mFrameU = mCurrentFrame + mTotalPixels;
+                mFrameU = mCurrentFrame + mYStride * mFrameHeight;
                 mFrameV = mFrameU + 1;
                 mUVStep = 2;
-                mUVTotalNum = mTotalPixels / 4;
                 break;
 
             default:
@@ -257,11 +253,6 @@
 
     int county = mCheckY % size;
     int checkxremainder = mCheckX % size;
-    uint8_t* Y = mCurrentFrame;
-    uint8_t* U_pos = mFrameU;
-    uint8_t* V_pos = mFrameV;
-    uint8_t* U = U_pos;
-    uint8_t* V = V_pos;
 
     YUVPixel adjustedWhite = YUVPixel(mWhiteYUV);
     changeWhiteBalance(adjustedWhite.Y, adjustedWhite.U, adjustedWhite.V);
@@ -269,6 +260,9 @@
     for(int y = 0; y < mFrameHeight; y++) {
         int countx = checkxremainder;
         bool current = black;
+        uint8_t* Y = mCurrentFrame + mYStride * y;
+        uint8_t* U = mFrameU + mUVStride * (y / 2);
+        uint8_t* V = mFrameV + mUVStride * (y / 2);
         for(int x = 0; x < mFrameWidth; x += 2) {
             if (current) {
                 mBlackYUV.get(Y, U, V);
@@ -284,13 +278,6 @@
                 current = !current;
             }
         }
-        if (y & 0x1) {
-            U_pos = U;
-            V_pos = V;
-        } else {
-            U = U_pos;
-            V = V_pos;
-        }
         if(county++ >= size) {
             county = 0;
             black = !black;
@@ -317,14 +304,14 @@
 {
     const int square_xstop = min(mFrameWidth, x + size);
     const int square_ystop = min(mFrameHeight, y + size);
-    uint8_t* Y_pos = mCurrentFrame + y * mFrameWidth + x;
+    uint8_t* Y_pos = mCurrentFrame + y * mYStride + x;
 
     YUVPixel adjustedColor = *color;
     changeWhiteBalance(adjustedColor.Y, adjustedColor.U, adjustedColor.V);
 
     // Draw the square.
     for (; y < square_ystop; y++) {
-        const int iUV = (y / 2) * mUVInRow + (x / 2) * mUVStep;
+        const int iUV = (y / 2) * mUVStride + (x / 2) * mUVStep;
         uint8_t* sqU = mFrameU + iUV;
         uint8_t* sqV = mFrameV + iUV;
         uint8_t* sqY = Y_pos;
@@ -334,7 +321,7 @@
             sqY[1] = *sqY;
             sqY += 2; sqU += mUVStep; sqV += mUVStep;
         }
-        Y_pos += mFrameWidth;
+        Y_pos += mYStride;
     }
 }
 
@@ -345,15 +332,19 @@
     YUVPixel adjustedColor = *color;
     changeWhiteBalance(adjustedColor.Y, adjustedColor.U, adjustedColor.V);
 
-    /* All Ys are the same. */
-    memset(mCurrentFrame, changeExposure(adjustedColor.Y), mTotalPixels);
+    /* All Ys are the same, will fill any alignment padding but that's OK */
+    memset(mCurrentFrame, changeExposure(adjustedColor.Y),
+           mFrameHeight * mYStride);
 
     /* Fill U, and V panes. */
-    uint8_t* U = mFrameU;
-    uint8_t* V = mFrameV;
-    for (int k = 0; k < mUVTotalNum; k++, U += mUVStep, V += mUVStep) {
-        *U = color->U;
-        *V = color->V;
+    for (int y = 0; y < mFrameHeight / 2; ++y) {
+        uint8_t* U = mFrameU + y * mUVStride;
+        uint8_t* V = mFrameV + y * mUVStride;
+
+        for (int x = 0; x < mFrameWidth / 2; ++x, U += mUVStep, V += mUVStep) {
+            *U = color->U;
+            *V = color->V;
+        }
     }
 }
 
@@ -363,7 +354,7 @@
     const int change_color_at = mFrameHeight / 4;
     const int each_in_row = mUVInRow / mUVStep;
     uint8_t* pY = mCurrentFrame;
-    for (int y = 0; y < mFrameHeight; y++, pY += mFrameWidth) {
+    for (int y = 0; y < mFrameHeight; y++, pY += mYStride) {
         /* Select the color. */
         YUVPixel* color;
         const int color_index = y / change_color_at;
@@ -386,7 +377,7 @@
         memset(pY, changeExposure(color->Y), mFrameWidth);
 
         /* Offset of the current row inside U/V panes. */
-        const int uv_off = (y / 2) * mUVInRow;
+        const int uv_off = (y / 2) * mUVStride;
         /* Fill U, and V panes. */
         uint8_t* U = mFrameU + uv_off;
         uint8_t* V = mFrameV + uv_off;
diff --git a/camera/EmulatedFakeCameraDevice.h b/camera/EmulatedFakeCameraDevice.h
index f66f076..1c8459b 100755
--- a/camera/EmulatedFakeCameraDevice.h
+++ b/camera/EmulatedFakeCameraDevice.h
@@ -153,9 +153,6 @@
      * number of both, Us and Vs in a single row in the interleaved UV pane. */
     int         mUVInRow;
 
-    /* Total number of each, U, and V elements in the framebuffer. */
-    int         mUVTotalNum;
-
     /*
      * Checkerboard drawing related stuff
      */