Merge "mediav2: fix ByteBuffer mode image comparison"
diff --git a/tests/media/jni/NativeCodecDecoderTest.cpp b/tests/media/jni/NativeCodecDecoderTest.cpp
index 754ccb3..0b17d7e 100644
--- a/tests/media/jni/NativeCodecDecoderTest.cpp
+++ b/tests/media/jni/NativeCodecDecoderTest.cpp
@@ -228,8 +228,18 @@
         if (mSaveToMem) {
             size_t buffSize;
             uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, bufferIndex, &buffSize);
-            if (mIsAudio) mOutputBuff->saveToMemory(buf, info);
-            mOutputBuff->updateChecksum(buf, info);
+            if (mIsAudio) {
+                mOutputBuff->saveToMemory(buf, info);
+                mOutputBuff->updateChecksum(buf, info);
+            } else {
+                AMediaFormat* format =
+                    mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat() : mOutFormat;
+                int32_t width, height, stride;
+                AMediaFormat_getInt32(format, "width", &width);
+                AMediaFormat_getInt32(format, "height", &height);
+                AMediaFormat_getInt32(format, "stride", &stride);
+                mOutputBuff->updateChecksum(buf, info, width, height, stride);
+            }
         }
         mOutputBuff->saveOutPTS(info->presentationTimeUs);
         mOutputCount++;
@@ -360,17 +370,17 @@
             if (validateFormat) {
                 if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
                                         : !mSignalledOutFormatChanged) {
-                    ALOGE(log, "not received format change");
+                    ALOGE("%s%s", log, "not received format change");
                     isPass = false;
                 } else if (!isFormatSimilar(mInpDecFormat, mIsCodecInAsyncMode
                                                                    ? mAsyncHandle.getOutputFormat()
                                                                    : mOutFormat)) {
-                    ALOGE(log, "configured format and output format are not similar");
+                    ALOGE("%s%s", log, "configured format and output format are not similar");
                     isPass = false;
                 }
             }
             if (checksum != ref->getChecksum()) {
-                ALOGE(log, "sdk output and ndk output differ");
+                ALOGE("%s%s", log, "sdk output and ndk output differ");
                 isPass = false;
             }
             loopCounter++;
@@ -500,12 +510,12 @@
         if (validateFormat) {
             if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
                                     : !mSignalledOutFormatChanged) {
-                ALOGE(log, "not received format change");
+                ALOGE("%s%s", log, "not received format change");
                 isPass = false;
             } else if (!isFormatSimilar(mInpDecFormat, mIsCodecInAsyncMode
                                                                ? mAsyncHandle.getOutputFormat()
                                                                : mOutFormat)) {
-                ALOGE(log, "configured format and output format are not similar");
+                ALOGE("%s%s", log, "configured format and output format are not similar");
                 isPass = false;
             }
         }
@@ -632,12 +642,12 @@
                 if (validateFormat) {
                     if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
                                             : !mSignalledOutFormatChanged) {
-                        ALOGE(log, "not received format change");
+                        ALOGE("%s%s", log, "not received format change");
                         isPass = false;
                     } else if (!isFormatSimilar(mInpDecFormat,
                                                 mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat()
                                                                     : mOutFormat)) {
-                        ALOGE(log, "configured format and output format are not similar");
+                        ALOGE("%s%s", log, "configured format and output format are not similar");
                         isPass = false;
                     }
                 }
diff --git a/tests/media/jni/NativeCodecTestBase.cpp b/tests/media/jni/NativeCodecTestBase.cpp
index 4e13e9c..d84e4d1 100644
--- a/tests/media/jni/NativeCodecTestBase.cpp
+++ b/tests/media/jni/NativeCodecTestBase.cpp
@@ -204,6 +204,31 @@
     return result;
 }
 
+void OutputManager::updateChecksum(
+        uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride) {
+    uint8_t flattenInfo[16];
+    int pos = 0;
+    if (width <= 0 || height <= 0 || stride <= 0) {
+        flattenField<int32_t>(flattenInfo, &pos, info->size);
+    }
+    flattenField<int32_t>(flattenInfo, &pos,
+                          info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
+    flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
+    crc32value = crc32(crc32value, flattenInfo, pos);
+    if (width > 0 && height > 0 && stride > 0) {
+        // Only checksum Y plane
+        std::vector<uint8_t> tmp(width * height, 0u);
+        size_t offset = 0;
+        for (int i = 0; i < height; ++i) {
+            memcpy(tmp.data() + (i * width), buf + offset, width);
+            offset += stride;
+        }
+        crc32value = crc32(crc32value, tmp.data(), width * height);
+    } else {
+        crc32value = crc32(crc32value, buf, info->size);
+    }
+}
+
 bool OutputManager::isOutPtsListIdenticalToInpPtsList(bool requireSorting) {
     bool isEqual = true;
     std::sort(inpPtsArray.begin(), inpPtsArray.end());
diff --git a/tests/media/jni/NativeCodecTestBase.h b/tests/media/jni/NativeCodecTestBase.h
index 87a46f9..4282e4a 100644
--- a/tests/media/jni/NativeCodecTestBase.h
+++ b/tests/media/jni/NativeCodecTestBase.h
@@ -103,18 +103,13 @@
     bool isPtsStrictlyIncreasing(int64_t lastPts);
     bool isOutPtsListIdenticalToInpPtsList(bool requireSorting);
     void saveToMemory(uint8_t* buf, AMediaCodecBufferInfo* info) {
-        memory.insert(memory.end(), buf + info->offset, buf + info->size);
+        memory.insert(memory.end(), buf, buf + info->size);
     }
     void updateChecksum(uint8_t* buf, AMediaCodecBufferInfo* info) {
-        crc32value = crc32(crc32value, buf + info->offset, info->size);
-        uint8_t flattenInfo[16];
-        int pos = 0;
-        flattenField<int32_t>(flattenInfo, &pos, info->size);
-        flattenField<int32_t>(flattenInfo, &pos,
-                              info->flags & ~AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
-        flattenField<int64_t>(flattenInfo, &pos, info->presentationTimeUs);
-        crc32value = crc32(crc32value, flattenInfo, sizeof(flattenInfo));
+        updateChecksum(buf, info, 0, 0, 0);
     }
+    void updateChecksum(
+            uint8_t* buf, AMediaCodecBufferInfo* info, int width, int height, int stride);
     uLong getChecksum() { return crc32value; }
     void reset() {
         inpPtsArray.clear();
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 1350d6f..e7527bb7 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -283,11 +283,37 @@
     }
 
     void checksum(ByteBuffer buf, int size) {
+        checksum(buf, size, 0, 0, 0);
+    }
+
+    void checksum(ByteBuffer buf, int size, int width, int height, int stride) {
         int cap = buf.capacity();
         assertTrue("checksum() params are invalid: size = " + size + " cap = " + cap,
                 size > 0 && size <= cap);
         if (buf.hasArray()) {
-            mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
+            if (width > 0 && height > 0 && stride > 0) {
+                int offset = buf.position() + buf.arrayOffset();
+                byte[] bb = new byte[width * height];
+                for (int i = 0; i < height; ++i) {
+                    System.arraycopy(buf.array(), offset, bb, i * width, width);
+                    offset += stride;
+                }
+                mCrc32UsingBuffer.update(bb, 0, width * height);
+            } else {
+                mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
+            }
+        } else if (width > 0 && height > 0 && stride > 0) {
+            // Checksum only the Y plane
+            int pos = buf.position();
+            int offset = pos;
+            byte[] bb = new byte[width * height];
+            for (int i = 0; i < height; ++i) {
+                buf.position(offset);
+                buf.get(bb, i * width, width);
+                offset += stride;
+            }
+            mCrc32UsingBuffer.update(bb, 0, width * height);
+            buf.position(pos);
         } else {
             int pos = buf.position();
             final int rdsize = Math.min(4096, size);
@@ -1039,8 +1065,11 @@
         return format.containsKey("csd-0");
     }
 
-    void flattenBufferInfo(MediaCodec.BufferInfo info) {
-        flatBuffer.putInt(info.size).putInt(info.flags & ~MediaCodec.BUFFER_FLAG_END_OF_STREAM)
+    void flattenBufferInfo(MediaCodec.BufferInfo info, boolean isAudio) {
+        if (isAudio) {
+            flatBuffer.putInt(info.size);
+        }
+        flatBuffer.putInt(info.flags & ~MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                 .putLong(info.presentationTimeUs);
         flatBuffer.flip();
     }
@@ -1111,14 +1140,20 @@
     void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
         if (info.size > 0 && mSaveToMem) {
             ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
-            mOutputBuff.checksum(buf, info.size);
-            flattenBufferInfo(info);
+            flattenBufferInfo(info, mIsAudio);
             mOutputBuff.checksum(flatBuffer, flatBuffer.limit());
             if (mIsAudio) {
+                mOutputBuff.checksum(buf, info.size);
                 mOutputBuff.saveToMemory(buf, info);
             } else {
                 // tests both getOutputImage and getOutputBuffer. Can do time division
                 // multiplexing but lets allow it for now
+                MediaFormat format = mCodec.getOutputFormat();
+                int width = format.getInteger(MediaFormat.KEY_WIDTH);
+                int height = format.getInteger(MediaFormat.KEY_HEIGHT);
+                int stride = format.getInteger(MediaFormat.KEY_STRIDE);
+                mOutputBuff.checksum(buf, info.size, width, height, stride);
+
                 Image img = mCodec.getOutputImage(bufferIndex);
                 assertTrue(img != null);
                 mOutputBuff.checksum(img);