1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.cts; 18 19 import com.android.cts.media.R; 20 21 import android.content.Context; 22 import android.media.MediaCodec; 23 import android.media.MediaCodecInfo; 24 import android.media.MediaCodecList; 25 import android.media.MediaFormat; 26 import android.test.AndroidTestCase; 27 import android.util.Log; 28 29 import java.nio.ByteBuffer; 30 import java.util.LinkedList; 31 import java.util.List; 32 33 public class EncoderTest extends AndroidTestCase { 34 private static final String TAG = "EncoderTest"; 35 private static final boolean VERBOSE = false; 36 37 private static final int kNumInputBytes = 256 * 1024; 38 private static final long kTimeoutUs = 10000; 39 40 @Override setContext(Context context)41 public void setContext(Context context) { 42 super.setContext(context); 43 } 44 testAMRNBEncoders()45 public void testAMRNBEncoders() { 46 LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>(); 47 48 final int kBitRates[] = 49 { 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200 }; 50 51 for (int j = 0; j < kBitRates.length; ++j) { 52 MediaFormat format = new MediaFormat(); 53 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB); 54 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000); 55 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 56 format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]); 57 formats.push(format); 58 } 59 60 testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_AMR_NB, formats); 61 } 62 testAMRWBEncoders()63 public void testAMRWBEncoders() { 64 LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>(); 65 66 final int kBitRates[] = 67 { 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850 }; 68 69 for (int j = 0; j < kBitRates.length; ++j) { 70 MediaFormat format = new MediaFormat(); 71 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_WB); 72 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 16000); 73 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 74 format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]); 75 formats.push(format); 76 } 77 78 testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_AMR_WB, formats); 79 } 80 testAACEncoders()81 public void testAACEncoders() { 82 LinkedList<MediaFormat> formats = new LinkedList<MediaFormat>(); 83 84 final int kAACProfiles[] = { 85 2 /* OMX_AUDIO_AACObjectLC */, 86 5 /* OMX_AUDIO_AACObjectHE */, 87 39 /* OMX_AUDIO_AACObjectELD */ 88 }; 89 90 final int kSampleRates[] = { 8000, 11025, 22050, 44100, 48000 }; 91 final int kBitRates[] = { 64000, 128000 }; 92 93 for (int k = 0; k < kAACProfiles.length; ++k) { 94 for (int i = 0; i < kSampleRates.length; ++i) { 95 if (kAACProfiles[k] == 5 && kSampleRates[i] < 22050) { 96 // Is this right? HE does not support sample rates < 22050Hz? 97 continue; 98 } 99 for (int j = 0; j < kBitRates.length; ++j) { 100 for (int ch = 1; ch <= 2; ++ch) { 101 MediaFormat format = new MediaFormat(); 102 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC); 103 104 format.setInteger( 105 MediaFormat.KEY_AAC_PROFILE, kAACProfiles[k]); 106 107 format.setInteger( 108 MediaFormat.KEY_SAMPLE_RATE, kSampleRates[i]); 109 110 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, ch); 111 format.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[j]); 112 formats.push(format); 113 } 114 } 115 } 116 } 117 118 testEncoderWithFormats(MediaFormat.MIMETYPE_AUDIO_AAC, formats); 119 } 120 testEncoderWithFormats( String mime, List<MediaFormat> formats)121 private void testEncoderWithFormats( 122 String mime, List<MediaFormat> formats) { 123 List<String> componentNames = getEncoderNamesForType(mime); 124 125 for (String componentName : componentNames) { 126 Log.d(TAG, "testing component '" + componentName + "'"); 127 for (MediaFormat format : formats) { 128 Log.d(TAG, " testing format '" + format + "'"); 129 assertEquals(mime, format.getString(MediaFormat.KEY_MIME)); 130 testEncoder(componentName, format); 131 } 132 } 133 } 134 getEncoderNamesForType(String mime)135 private List<String> getEncoderNamesForType(String mime) { 136 LinkedList<String> names = new LinkedList<String>(); 137 138 MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 139 for (MediaCodecInfo info : mcl.getCodecInfos()) { 140 if (!info.isEncoder()) { 141 continue; 142 } 143 for (String type : info.getSupportedTypes()) { 144 if (type.equalsIgnoreCase(mime)) { 145 names.push(info.getName()); 146 break; 147 } 148 } 149 } 150 151 return names; 152 } 153 queueInputBuffer( MediaCodec codec, ByteBuffer[] inputBuffers, int index)154 private int queueInputBuffer( 155 MediaCodec codec, ByteBuffer[] inputBuffers, int index) { 156 ByteBuffer buffer = inputBuffers[index]; 157 buffer.clear(); 158 159 int size = buffer.limit(); 160 161 byte[] zeroes = new byte[size]; 162 buffer.put(zeroes); 163 164 codec.queueInputBuffer(index, 0 /* offset */, size, 0 /* timeUs */, 0); 165 166 return size; 167 } 168 dequeueOutputBuffer( MediaCodec codec, ByteBuffer[] outputBuffers, int index, MediaCodec.BufferInfo info)169 private void dequeueOutputBuffer( 170 MediaCodec codec, ByteBuffer[] outputBuffers, 171 int index, MediaCodec.BufferInfo info) { 172 codec.releaseOutputBuffer(index, false /* render */); 173 } 174 testEncoder(String componentName, MediaFormat format)175 private void testEncoder(String componentName, MediaFormat format) { 176 MediaCodec codec; 177 try { 178 codec = MediaCodec.createByCodecName(componentName); 179 } catch (Exception e) { 180 fail("codec '" + componentName + "' failed construction."); 181 return; /* does not get here, but avoids warning */ 182 } 183 try { 184 codec.configure( 185 format, 186 null /* surface */, 187 null /* crypto */, 188 MediaCodec.CONFIGURE_FLAG_ENCODE); 189 } catch (IllegalStateException e) { 190 fail("codec '" + componentName + "' failed configuration."); 191 } 192 193 codec.start(); 194 ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); 195 ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); 196 197 int numBytesSubmitted = 0; 198 boolean doneSubmittingInput = false; 199 int numBytesDequeued = 0; 200 201 while (true) { 202 int index; 203 204 if (!doneSubmittingInput) { 205 index = codec.dequeueInputBuffer(kTimeoutUs /* timeoutUs */); 206 207 if (index != MediaCodec.INFO_TRY_AGAIN_LATER) { 208 if (numBytesSubmitted >= kNumInputBytes) { 209 codec.queueInputBuffer( 210 index, 211 0 /* offset */, 212 0 /* size */, 213 0 /* timeUs */, 214 MediaCodec.BUFFER_FLAG_END_OF_STREAM); 215 216 if (VERBOSE) { 217 Log.d(TAG, "queued input EOS."); 218 } 219 220 doneSubmittingInput = true; 221 } else { 222 int size = queueInputBuffer( 223 codec, codecInputBuffers, index); 224 225 numBytesSubmitted += size; 226 227 if (VERBOSE) { 228 Log.d(TAG, "queued " + size + " bytes of input data."); 229 } 230 } 231 } 232 } 233 234 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 235 index = codec.dequeueOutputBuffer(info, kTimeoutUs /* timeoutUs */); 236 237 if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { 238 } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 239 } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 240 codecOutputBuffers = codec.getOutputBuffers(); 241 } else { 242 dequeueOutputBuffer(codec, codecOutputBuffers, index, info); 243 244 numBytesDequeued += info.size; 245 246 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 247 if (VERBOSE) { 248 Log.d(TAG, "dequeued output EOS."); 249 } 250 break; 251 } 252 253 if (VERBOSE) { 254 Log.d(TAG, "dequeued " + info.size + " bytes of output data."); 255 } 256 } 257 } 258 259 if (VERBOSE) { 260 Log.d(TAG, "queued a total of " + numBytesSubmitted + "bytes, " 261 + "dequeued " + numBytesDequeued + " bytes."); 262 } 263 264 int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); 265 int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 266 int inBitrate = sampleRate * channelCount * 16; // bit/sec 267 int outBitrate = format.getInteger(MediaFormat.KEY_BIT_RATE); 268 269 float desiredRatio = (float)outBitrate / (float)inBitrate; 270 float actualRatio = (float)numBytesDequeued / (float)numBytesSubmitted; 271 272 if (actualRatio < 0.9 * desiredRatio || actualRatio > 1.1 * desiredRatio) { 273 Log.w(TAG, "desiredRatio = " + desiredRatio 274 + ", actualRatio = " + actualRatio); 275 } 276 277 codec.release(); 278 codec = null; 279 } 280 } 281 282