add MediaCodecTest with both video and audio encoding
bug: 10361518
Change-Id: Ie13f8b2e7cb751aa8e334f3475986ea8893aae17
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index afa34e8..d2c39f4 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -20,11 +20,15 @@
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.CodecProfileLevel;
import android.opengl.GLES20;
import android.test.AndroidTestCase;
import android.util.Log;
import android.view.Surface;
+import java.nio.ByteBuffer;
+
/**
* General MediaCodec tests.
@@ -35,13 +39,26 @@
private static final String TAG = "MediaCodecTest";
private static final boolean VERBOSE = false; // lots of logging
- // parameters for the encoder
+ // parameters for the video encoder
private static final String MIME_TYPE = "video/avc"; // H.264 Advanced Video Coding
private static final int BIT_RATE = 2000000; // 2Mbps
private static final int FRAME_RATE = 15; // 15fps
private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
private static final int WIDTH = 1280;
private static final int HEIGHT = 720;
+ // parameters for the audio encoder
+ private static final String MIME_TYPE_AUDIO = "audio/mp4a-latm";
+ private static final int AUDIO_SAMPLE_RATE = 44100;
+ private static final int AUDIO_AAC_PROFILE = 2; /* OMX_AUDIO_AACObjectLC */
+ private static final int AUDIO_CHANNEL_COUNT = 2; // mono
+ private static final int AUDIO_BIT_RATE = 128000;
+
+ private static final int TIMEOUT_USEC = 100000;
+ private static final int TIMEOUT_USEC_SHORT = 100;
+
+ private boolean mVideoEncoderHadError = false;
+ private boolean mAudioEncoderHadError = false;
+ private volatile boolean mVideoEncodingOngoing = false;
/**
* Tests:
@@ -60,7 +77,7 @@
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
try {
- encoder = MediaCodec.createByCodecName(codecInfo.getName());;
+ encoder = MediaCodec.createByCodecName(codecInfo.getName());
try {
surface = encoder.createInputSurface();
fail("createInputSurface should not work pre-configure");
@@ -222,6 +239,221 @@
}
}
+ public void testConcurrentAudioVideoEncodings() throws InterruptedException {
+ final int VIDEO_NUM_SWAPS = 100;
+ // audio only checks this and stop
+ mVideoEncodingOngoing = true;
+ final CodecInfo info = getAvcSupportedFormatInfo();
+ long start = System.currentTimeMillis();
+ Thread videoEncodingThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ runVideoEncoding(VIDEO_NUM_SWAPS, info);
+ }
+ });
+ Thread audioEncodingThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ runAudioEncoding();
+ }
+ });
+ videoEncodingThread.start();
+ audioEncodingThread.start();
+ videoEncodingThread.join();
+ mVideoEncodingOngoing = false;
+ audioEncodingThread.join();
+ assertFalse("Video encoding error. Chekc logcat", mVideoEncoderHadError);
+ assertFalse("Audio encoding error. Chekc logcat", mAudioEncoderHadError);
+ long end = System.currentTimeMillis();
+ Log.w(TAG, "Concurrent AV encoding took " + (end - start) + " ms for " + VIDEO_NUM_SWAPS +
+ " video frames");
+ }
+
+ private static class CodecInfo {
+ public int mMaxW;
+ public int mMaxH;
+ public int mFps;
+ public int mBitRate;
+ };
+
+ private static CodecInfo getAvcSupportedFormatInfo() {
+ MediaCodecInfo mediaCodecInfo = selectCodec(MIME_TYPE);
+ CodecCapabilities cap = mediaCodecInfo.getCapabilitiesForType(MIME_TYPE);
+ if (cap == null) { // not supported
+ return null;
+ }
+ CodecInfo info = new CodecInfo();
+ int highestLevel = 0;
+ for (CodecProfileLevel lvl : cap.profileLevels) {
+ if (lvl.level > highestLevel) {
+ highestLevel = lvl.level;
+ }
+ }
+ int maxW = 0;
+ int maxH = 0;
+ int bitRate = 0;
+ int fps = 0; // frame rate for the max resolution
+ switch(highestLevel) {
+ // Do not support Level 1 to 2.
+ case CodecProfileLevel.AVCLevel1:
+ case CodecProfileLevel.AVCLevel11:
+ case CodecProfileLevel.AVCLevel12:
+ case CodecProfileLevel.AVCLevel13:
+ case CodecProfileLevel.AVCLevel1b:
+ case CodecProfileLevel.AVCLevel2:
+ return null;
+ case CodecProfileLevel.AVCLevel21:
+ maxW = 352;
+ maxH = 576;
+ bitRate = 4000000;
+ fps = 25;
+ break;
+ case CodecProfileLevel.AVCLevel22:
+ maxW = 720;
+ maxH = 480;
+ bitRate = 4000000;
+ fps = 15;
+ break;
+ case CodecProfileLevel.AVCLevel3:
+ maxW = 720;
+ maxH = 480;
+ bitRate = 10000000;
+ fps = 30;
+ break;
+ case CodecProfileLevel.AVCLevel31:
+ maxW = 1280;
+ maxH = 720;
+ bitRate = 14000000;
+ fps = 30;
+ break;
+ case CodecProfileLevel.AVCLevel32:
+ maxW = 1280;
+ maxH = 720;
+ bitRate = 20000000;
+ fps = 60;
+ break;
+ case CodecProfileLevel.AVCLevel4: // only try up to 1080p
+ default:
+ maxW = 1920;
+ maxH = 1080;
+ bitRate = 20000000;
+ fps = 30;
+ break;
+ }
+ info.mMaxW = maxW;
+ info.mMaxH = maxH;
+ info.mFps = fps;
+ info.mBitRate = bitRate;
+ Log.i(TAG, "AVC Level 0x" + Integer.toHexString(highestLevel) + " bit rate " + bitRate +
+ " fps " + info.mFps + " w " + maxW + " h " + maxH);
+
+ return info;
+ }
+
+ private void runVideoEncoding(int numSwap, CodecInfo info) {
+ MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, info.mMaxW, info.mMaxH);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, info.mBitRate);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, info.mFps);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ MediaCodec encoder = null;
+ InputSurface inputSurface = null;
+ mVideoEncoderHadError = false;
+ try {
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ inputSurface = new InputSurface(encoder.createInputSurface());
+ inputSurface.makeCurrent();
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ encoder.start();
+ for (int i = 0; i < numSwap; i++) {
+ GLES20.glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ inputSurface.swapBuffers();
+ // dequeue buffers until not available
+ int index = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
+ while (index >= 0) {
+ encoder.releaseOutputBuffer(index, false);
+ // just throw away output
+ // allow shorter wait for 2nd round to move on quickly.
+ index = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC_SHORT);
+ }
+ }
+ encoder.signalEndOfInputStream();
+ } catch (Throwable e) {
+ Log.w(TAG, "runVideoEncoding got error: " + e);
+ mVideoEncoderHadError = true;
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ if (inputSurface != null) {
+ inputSurface.release();
+ }
+ }
+ }
+
+ private void runAudioEncoding() {
+ MediaFormat format = MediaFormat.createAudioFormat(MIME_TYPE_AUDIO, AUDIO_SAMPLE_RATE,
+ AUDIO_CHANNEL_COUNT);
+ format.setInteger(MediaFormat.KEY_AAC_PROFILE, AUDIO_AAC_PROFILE);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, AUDIO_BIT_RATE);
+ MediaCodec encoder = null;
+ mAudioEncoderHadError = false;
+ try {
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE_AUDIO);
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ encoder.start();
+ ByteBuffer[] inputBuffers = encoder.getInputBuffers();
+ ByteBuffer source = ByteBuffer.allocate(inputBuffers[0].capacity());
+ for (int i = 0; i < source.capacity()/2; i++) {
+ source.putShort((short)i);
+ }
+ source.rewind();
+ int currentInputBufferIndex = 0;
+ long encodingLatencySum = 0;
+ int totalEncoded = 0;
+ int numRepeat = 0;
+ while (mVideoEncodingOngoing) {
+ numRepeat++;
+ int inputIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
+ while (inputIndex == -1) {
+ inputIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
+ }
+ ByteBuffer inputBuffer = inputBuffers[inputIndex];
+ inputBuffer.rewind();
+ inputBuffer.put(source);
+ long start = System.currentTimeMillis();
+ totalEncoded += inputBuffers[inputIndex].limit();
+ encoder.queueInputBuffer(inputIndex, 0, inputBuffer.limit(), 0, 0);
+ source.rewind();
+ int index = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
+ long end = System.currentTimeMillis();
+ encodingLatencySum += (end - start);
+ while (index >= 0) {
+ encoder.releaseOutputBuffer(index, false);
+ // just throw away output
+ // allow shorter wait for 2nd round to move on quickly.
+ index = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC_SHORT);
+ }
+ }
+ Log.w(TAG, "Audio encoding average latency " + encodingLatencySum / numRepeat +
+ " ms for average write size " + totalEncoded / numRepeat +
+ " total latency " + encodingLatencySum + " ms for total bytes " + totalEncoded);
+ } catch (Throwable e) {
+ Log.w(TAG, "runAudioEncoding got error: " + e);
+ mAudioEncoderHadError = true;
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ }
+ }
+
/**
* Creates a MediaFormat with the basic set of values.
*/