mediav2 CTS: Improve failure diagnostic messages - 3
Add provision to dump output of component under test if possible.
Bug: 220100512
Test: atest android.mediav2.cts
Change-Id: Ic68ade5489bae92c1e92e47b6d274fa7ce6e27ff
diff --git a/tests/media/common/src/android/mediav2/common/cts/OutputManager.java b/tests/media/common/src/android/mediav2/common/cts/OutputManager.java
index 5d879c65..d59f432 100644
--- a/tests/media/common/src/android/mediav2/common/cts/OutputManager.java
+++ b/tests/media/common/src/android/mediav2/common/cts/OutputManager.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.graphics.ImageFormat;
import android.graphics.Rect;
@@ -25,6 +26,8 @@
import android.media.Image;
import android.media.MediaCodec;
+import java.io.File;
+import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
@@ -38,9 +41,17 @@
* in memory and outPtsList fields of this class. For video decoders, the decoded information can
* be overwhelming as it is uncompressed YUV. For them we compute the CRC32 checksum of the
* output image and buffer and store it instead.
+ *
+ * ByteBuffer output of encoder/decoder components can be written to disk by setting ENABLE_DUMP
+ * to true. Exercise CAUTION while running tests with ENABLE_DUMP set to true as this will crowd
+ * the storage with files. These files are configured to be deleted on exit. So, in order to see
+ * the captured output, File.deleteOnExit() needs to be be commented. Also it might be necessary
+ * to set option name="cleanup-apks" to "false" in AndroidTest.xml.
*/
public class OutputManager {
private static final String LOG_TAG = OutputManager.class.getSimpleName();
+ private static final boolean ENABLE_DUMP = false;
+
private byte[] mMemory;
private int mMemIndex;
private final CRC32 mCrc32UsingImage;
@@ -49,6 +60,11 @@
private final ArrayList<Long> mOutPtsList;
private final StringBuilder mErrorLogs;
private final StringBuilder mSharedErrorLogs;
+ private File mOutFileYuv;
+ private boolean mAppendToYuvFile;
+ private File mOutFileY;
+ private boolean mAppendToYFile;
+ private File mOutFileDefault;
public OutputManager() {
this(new StringBuilder());
@@ -170,6 +186,9 @@
offset += stride;
}
mCrc32UsingBuffer.update(bb, 0, width * height * bytesPerSample);
+ if (ENABLE_DUMP) {
+ dumpY(bb, 0, width * height * bytesPerSample);
+ }
} else {
mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
}
@@ -184,6 +203,9 @@
offset += stride;
}
mCrc32UsingBuffer.update(bb, 0, width * height * bytesPerSample);
+ if (ENABLE_DUMP) {
+ dumpY(bb, 0, width * height * bytesPerSample);
+ }
buf.position(pos);
} else {
int pos = buf.position();
@@ -282,6 +304,9 @@
buf.position(base);
}
mCrc32UsingImage.update(bb, 0, width * height * bytesPerSample);
+ if (ENABLE_DUMP) {
+ dumpYuv(bb, 0, width * height * bytesPerSample);
+ }
}
}
@@ -316,6 +341,18 @@
mSharedErrorLogs.setLength(0);
mErrorLogs.setLength(0);
mErrorLogs.append("################## Error Details ####################\n");
+ cleanUp();
+ }
+
+ public void cleanUp() {
+ if (mOutFileYuv != null && mOutFileYuv.exists()) mOutFileYuv.delete();
+ mOutFileYuv = null;
+ mAppendToYuvFile = false;
+ if (mOutFileY != null && mOutFileY.exists()) mOutFileY.delete();
+ mOutFileY = null;
+ mAppendToYFile = false;
+ if (mOutFileDefault != null && mOutFileDefault.exists()) mOutFileDefault.delete();
+ mOutFileDefault = null;
}
public float getRmsError(Object refObject, int audioFormat) {
@@ -418,6 +455,16 @@
mCrc32UsingImage.getValue()));
mSharedErrorLogs.append(String.format("Test CRC32 checksum value is %d \n",
that.mCrc32UsingImage.getValue()));
+ if (ENABLE_DUMP) {
+ mSharedErrorLogs.append(String.format("Decoded Ref YUV file is at : %s \n",
+ mOutFileYuv.getAbsolutePath()));
+ mSharedErrorLogs.append(String.format("Decoded Test YUV file is at : %s \n",
+ that.mOutFileYuv.getAbsolutePath()));
+ } else {
+ mSharedErrorLogs.append("As the reference YUV and test YUV are different, try "
+ + "re-running the test by changing ENABLE_DUMP of OutputManager class to "
+ + "'true' to dump the decoded YUVs for further analysis. \n");
+ }
}
if (mCrc32UsingBuffer.getValue() != that.mCrc32UsingBuffer.getValue()) {
isEqual = false;
@@ -427,6 +474,30 @@
mCrc32UsingBuffer.getValue()));
mSharedErrorLogs.append(String.format("Test CRC32 checksum value is %d \n",
that.mCrc32UsingBuffer.getValue()));
+ if (ENABLE_DUMP) {
+ if (mOutFileY != null) {
+ mSharedErrorLogs.append(String.format("Decoded Ref Y file is at : %s \n",
+ mOutFileY.getAbsolutePath()));
+ }
+ if (that.mOutFileY != null) {
+ mSharedErrorLogs.append(String.format("Decoded Test Y file is at : %s \n",
+ that.mOutFileY.getAbsolutePath()));
+ }
+ if (mMemIndex > 0) {
+ mSharedErrorLogs.append(
+ String.format("Output Ref ByteBuffer is dumped at : %s \n",
+ dumpBuffer()));
+ }
+ if (that.mMemIndex > 0) {
+ mSharedErrorLogs.append(
+ String.format("Output Test ByteBuffer is dumped at : %s \n",
+ that.dumpBuffer()));
+ }
+ } else {
+ mSharedErrorLogs.append("As the output of the component is not consistent, try "
+ + "re-running the test by changing ENABLE_DUMP of OutputManager class to "
+ + "'true' to dump the outputs for further analysis. \n");
+ }
if (mMemIndex == that.mMemIndex) {
int count = 0;
StringBuilder msg = new StringBuilder();
@@ -459,4 +530,58 @@
public String getErrMsg() {
return (mErrorLogs.toString() + mSharedErrorLogs.toString());
}
+
+ public void dumpYuv(byte[] mem, int offset, int size) {
+ try {
+ if (mOutFileYuv == null) {
+ mOutFileYuv = File.createTempFile(LOG_TAG + "YUV", ".bin");
+ mOutFileYuv.deleteOnExit();
+ }
+ try (FileOutputStream outputStream = new FileOutputStream(mOutFileYuv,
+ mAppendToYuvFile)) {
+ outputStream.write(mem, offset, size);
+ mAppendToYuvFile = true;
+ }
+ } catch (Exception e) {
+ fail("Encountered IOException during output image write. Exception is" + e);
+ }
+ }
+
+ public void dumpY(byte[] mem, int offset, int size) {
+ try {
+ if (mOutFileY == null) {
+ mOutFileY = File.createTempFile(LOG_TAG + "Y", ".bin");
+ mOutFileY.deleteOnExit();
+ }
+ try (FileOutputStream outputStream = new FileOutputStream(mOutFileY, mAppendToYFile)) {
+ outputStream.write(mem, offset, size);
+ mAppendToYFile = true;
+ }
+ } catch (Exception e) {
+ fail("Encountered IOException during output image write. Exception is" + e);
+ }
+ }
+
+ public String dumpBuffer() {
+ if (ENABLE_DUMP) {
+ try {
+ if (mOutFileDefault == null) {
+ mOutFileDefault = File.createTempFile(LOG_TAG + "OUT", ".bin");
+ mOutFileDefault.deleteOnExit();
+ }
+ try (FileOutputStream outputStream = new FileOutputStream(mOutFileDefault)) {
+ outputStream.write(mMemory, 0, mMemIndex);
+ }
+ } catch (Exception e) {
+ fail("Encountered IOException during output buffer write. Exception is" + e);
+ }
+ return mOutFileDefault.getAbsolutePath();
+ }
+ return "file not dumped yet, re-run the test by changing ENABLE_DUMP of OutputManager "
+ + "class to 'true' to dump the buffer";
+ }
+
+ public String getOutYuvFileName() {
+ return (mOutFileYuv != null) ? mOutFileYuv.getAbsolutePath() : null;
+ }
}