1 /* 2 * Copyright (C) 2013 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 package android.media.cts; 17 18 import android.content.pm.PackageManager; 19 import android.cts.util.MediaUtils; 20 import android.media.MediaCodec; 21 import android.media.MediaCodecInfo; 22 import android.media.MediaCodecInfo.AudioCapabilities; 23 import android.media.MediaCodecInfo.CodecCapabilities; 24 import android.media.MediaCodecInfo.CodecProfileLevel; 25 import android.media.MediaCodecInfo.VideoCapabilities; 26 import static android.media.MediaCodecInfo.CodecProfileLevel.*; 27 import android.media.MediaCodecList; 28 import android.media.MediaFormat; 29 import static android.media.MediaFormat.MIMETYPE_VIDEO_AVC; 30 import static android.media.MediaFormat.MIMETYPE_VIDEO_H263; 31 import static android.media.MediaFormat.MIMETYPE_VIDEO_HEVC; 32 import static android.media.MediaFormat.MIMETYPE_VIDEO_MPEG4; 33 import static android.media.MediaFormat.MIMETYPE_VIDEO_VP8; 34 import static android.media.MediaFormat.MIMETYPE_VIDEO_VP9; 35 import android.media.MediaPlayer; 36 import android.os.Build; 37 import android.util.Log; 38 39 import java.io.IOException; 40 import java.util.HashSet; 41 import java.util.Set; 42 import java.util.Arrays; 43 import java.util.Vector; 44 45 /** 46 * Basic sanity test of data returned by MediaCodeCapabilities. 47 */ 48 public class MediaCodecCapabilitiesTest extends MediaPlayerTestBase { 49 50 private static final String TAG = "MediaCodecCapabilitiesTest"; 51 private static final int PLAY_TIME_MS = 30000; 52 private static final int TIMEOUT_US = 1000000; // 1 sec 53 private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames 54 55 private final MediaCodecList mRegularCodecs = 56 new MediaCodecList(MediaCodecList.REGULAR_CODECS); 57 private final MediaCodecList mAllCodecs = 58 new MediaCodecList(MediaCodecList.ALL_CODECS); 59 private final MediaCodecInfo[] mRegularInfos = 60 mRegularCodecs.getCodecInfos(); 61 private final MediaCodecInfo[] mAllInfos = 62 mAllCodecs.getCodecInfos(); 63 64 // Android device implementations with H.264 encoders, MUST support Baseline Profile Level 3. 65 // SHOULD support Main Profile/ Level 4, if supported the device must also support Main 66 // Profile/Level 4 decoding. testH264EncoderProfileAndLevel()67 public void testH264EncoderProfileAndLevel() throws Exception { 68 if (!MediaUtils.checkEncoder(MIMETYPE_VIDEO_AVC)) { 69 return; // skip 70 } 71 72 assertTrue( 73 "H.264 must support Baseline Profile Level 3", 74 hasEncoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3)); 75 76 if (hasEncoder(MIMETYPE_VIDEO_AVC, AVCProfileMain, AVCLevel4)) { 77 assertTrue( 78 "H.264 decoder must support Main Profile Level 4 if it can encode it", 79 hasDecoder(MIMETYPE_VIDEO_AVC, AVCProfileMain, AVCLevel4)); 80 } 81 } 82 83 // Android device implementations with H.264 decoders, MUST support Baseline Profile Level 3. 84 // Android Television Devices MUST support High Profile Level 4.2. testH264DecoderProfileAndLevel()85 public void testH264DecoderProfileAndLevel() throws Exception { 86 if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_AVC)) { 87 return; // skip 88 } 89 90 assertTrue( 91 "H.264 must support Baseline Profile Level 3", 92 hasDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3)); 93 94 if (isTv()) { 95 assertTrue( 96 "H.264 must support High Profile Level 4.2 on TV", 97 checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel42)); 98 } 99 } 100 101 // Android device implementations with H.263 encoders, MUST support Level 45. testH263EncoderProfileAndLevel()102 public void testH263EncoderProfileAndLevel() throws Exception { 103 if (!MediaUtils.checkEncoder(MIMETYPE_VIDEO_H263)) { 104 return; // skip 105 } 106 107 assertTrue( 108 "H.263 must support Level 45", 109 hasEncoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level45)); 110 } 111 112 // Android device implementations with H.263 decoders, MUST support Level 30. testH263DecoderProfileAndLevel()113 public void testH263DecoderProfileAndLevel() throws Exception { 114 if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_H263)) { 115 return; // skip 116 } 117 118 assertTrue( 119 "H.263 must support Level 30", 120 hasDecoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level30)); 121 } 122 123 // Android device implementations with MPEG-4 decoders, MUST support Simple Profile Level 3. testMpeg4DecoderProfileAndLevel()124 public void testMpeg4DecoderProfileAndLevel() throws Exception { 125 if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_MPEG4)) { 126 return; // skip 127 } 128 129 assertTrue( 130 "MPEG-4 must support Simple Profile Level 3", 131 hasDecoder(MIMETYPE_VIDEO_MPEG4, MPEG4ProfileSimple, MPEG4Level3)); 132 } 133 134 // Android device implementations, when supporting H.265 codec MUST support the Main Profile 135 // Level 3 Main tier. 136 // Android Television Devices MUST support the Main Profile Level 4.1 Main tier. 137 // When the UHD video decoding profile is supported, it MUST support Main10 Level 5 Main 138 // Tier profile. testH265DecoderProfileAndLevel()139 public void testH265DecoderProfileAndLevel() throws Exception { 140 if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_HEVC)) { 141 return; // skip 142 } 143 144 assertTrue( 145 "H.265 must support Main Profile Main Tier Level 3", 146 hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel3)); 147 148 if (isTv()) { 149 assertTrue( 150 "H.265 must support Main Profile Main Tier Level 4.1 on TV", 151 hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel41)); 152 } 153 154 if (isTv() && MediaUtils.canDecodeVideo(MIMETYPE_VIDEO_HEVC, 3840, 2160, 30)) { 155 assertTrue( 156 "H.265 must support Main10 Profile Main Tier Level 5 if UHD is supported", 157 hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain10, HEVCMainTierLevel5)); 158 } 159 } 160 testAvcBaseline1()161 public void testAvcBaseline1() throws Exception { 162 if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel1)) { 163 return; // skip 164 } 165 166 // TODO: add a test stream 167 MediaUtils.skipTest(TAG, "no test stream"); 168 } 169 testAvcBaseline12()170 public void testAvcBaseline12() throws Exception { 171 if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel12)) { 172 return; // skip 173 } 174 175 playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e" 176 + "&itag=160&source=youtube&user=android-device-test" 177 + "&sparams=ip,ipbits,expire,id,itag,source,user" 178 + "&ip=0.0.0.0&ipbits=0&expire=19000000000" 179 + "&signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD." 180 + "702DE9BA7AF96785FD6930AD2DD693A0486C880E" 181 + "&key=ik0", 256, 144, PLAY_TIME_MS); 182 } 183 testAvcBaseline30()184 public void testAvcBaseline30() throws Exception { 185 if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileBaseline, AVCLevel3)) { 186 return; // skip 187 } 188 playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e" 189 + "&itag=18&source=youtube&user=android-device-test" 190 + "&sparams=ip,ipbits,expire,id,itag,source,user" 191 + "&ip=0.0.0.0&ipbits=0&expire=19000000000" 192 + "&signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA." 193 + "7A83031734CB1EDCE06766B6228842F954927960" 194 + "&key=ik0", 640, 360, PLAY_TIME_MS); 195 } 196 testAvcHigh31()197 public void testAvcHigh31() throws Exception { 198 if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel31)) { 199 return; // skip 200 } 201 playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e" 202 + "&itag=22&source=youtube&user=android-device-test" 203 + "&sparams=ip,ipbits,expire,id,itag,source,user" 204 + "&ip=0.0.0.0&ipbits=0&expire=19000000000" 205 + "&signature=179525311196616BD8E1381759B0E5F81A9E91B5." 206 + "C4A50E44059FEBCC6BBC78E3B3A4E0E0065777" 207 + "&key=ik0", 1280, 720, PLAY_TIME_MS); 208 } 209 testAvcHigh40()210 public void testAvcHigh40() throws Exception { 211 if (!checkDecoder(MIMETYPE_VIDEO_AVC, AVCProfileHigh, AVCLevel4)) { 212 return; // skip 213 } 214 if (Build.VERSION.SDK_INT < 18) { 215 MediaUtils.skipTest(TAG, "fragmented mp4 not supported"); 216 return; 217 } 218 playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e" 219 + "&itag=137&source=youtube&user=android-device-test" 220 + "&sparams=ip,ipbits,expire,id,itag,source,user" 221 + "&ip=0.0.0.0&ipbits=0&expire=19000000000" 222 + "&signature=B0976085596DD42DEA3F08307F76587241CB132B." 223 + "043B719C039E8B92F45391ADC0BE3665E2332930" 224 + "&key=ik0", 1920, 1080, PLAY_TIME_MS); 225 } 226 testHevcMain1()227 public void testHevcMain1() throws Exception { 228 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel1)) { 229 return; // skip 230 } 231 232 // TODO: add a test stream 233 MediaUtils.skipTest(TAG, "no test stream"); 234 } 235 testHevcMain2()236 public void testHevcMain2() throws Exception { 237 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel2)) { 238 return; // skip 239 } 240 241 // TODO: add a test stream 242 MediaUtils.skipTest(TAG, "no test stream"); 243 } 244 testHevcMain21()245 public void testHevcMain21() throws Exception { 246 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel21)) { 247 return; // skip 248 } 249 250 // TODO: add a test stream 251 MediaUtils.skipTest(TAG, "no test stream"); 252 } 253 testHevcMain3()254 public void testHevcMain3() throws Exception { 255 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel3)) { 256 return; // skip 257 } 258 259 // TODO: add a test stream 260 MediaUtils.skipTest(TAG, "no test stream"); 261 } 262 testHevcMain31()263 public void testHevcMain31() throws Exception { 264 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel31)) { 265 return; // skip 266 } 267 268 // TODO: add a test stream 269 MediaUtils.skipTest(TAG, "no test stream"); 270 } 271 testHevcMain4()272 public void testHevcMain4() throws Exception { 273 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel4)) { 274 return; // skip 275 } 276 277 // TODO: add a test stream 278 MediaUtils.skipTest(TAG, "no test stream"); 279 } 280 testHevcMain41()281 public void testHevcMain41() throws Exception { 282 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel41)) { 283 return; // skip 284 } 285 286 // TODO: add a test stream 287 MediaUtils.skipTest(TAG, "no test stream"); 288 } 289 testHevcMain5()290 public void testHevcMain5() throws Exception { 291 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel5)) { 292 return; // skip 293 } 294 295 // TODO: add a test stream 296 MediaUtils.skipTest(TAG, "no test stream"); 297 } 298 testHevcMain51()299 public void testHevcMain51() throws Exception { 300 if (!checkDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel51)) { 301 return; // skip 302 } 303 304 // TODO: add a test stream 305 MediaUtils.skipTest(TAG, "no test stream"); 306 } 307 checkDecoder(String mime, int profile, int level)308 private boolean checkDecoder(String mime, int profile, int level) { 309 if (!hasDecoder(mime, profile, level)) { 310 MediaUtils.skipTest(TAG, "no " + mime + " decoder for profile " 311 + profile + " and level " + level); 312 return false; 313 } 314 return true; 315 } 316 hasDecoder(String mime, int profile, int level)317 private boolean hasDecoder(String mime, int profile, int level) { 318 return supports(mime, false /* isEncoder */, profile, level); 319 } 320 hasEncoder(String mime, int profile, int level)321 private boolean hasEncoder(String mime, int profile, int level) { 322 return supports(mime, true /* isEncoder */, profile, level); 323 } 324 supports( String mime, boolean isEncoder, int profile, int level)325 private boolean supports( 326 String mime, boolean isEncoder, int profile, int level) { 327 MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 328 for (MediaCodecInfo info : mcl.getCodecInfos()) { 329 if (isEncoder != info.isEncoder()) { 330 continue; 331 } 332 try { 333 CodecCapabilities caps = info.getCapabilitiesForType(mime); 334 for (CodecProfileLevel pl : caps.profileLevels) { 335 if (pl.profile != profile) { 336 continue; 337 } 338 339 // H.263 levels are not completely ordered: 340 // Level45 support only implies Level10 support 341 if (mime.equalsIgnoreCase(MIMETYPE_VIDEO_H263)) { 342 if (pl.level != level && pl.level == H263Level45 && level > H263Level10) { 343 continue; 344 } 345 } 346 if (pl.level >= level) { 347 return true; 348 } 349 } 350 } catch (IllegalArgumentException e) { 351 } 352 } 353 return false; 354 } 355 isVideoMime(String mime)356 private boolean isVideoMime(String mime) { 357 return mime.toLowerCase().startsWith("video/"); 358 } 359 requiredAdaptiveFormats()360 private Set<String> requiredAdaptiveFormats() { 361 Set<String> adaptiveFormats = new HashSet<String>(); 362 adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_AVC); 363 adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_HEVC); 364 adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_VP8); 365 adaptiveFormats.add(MediaFormat.MIMETYPE_VIDEO_VP9); 366 return adaptiveFormats; 367 } 368 testHaveAdaptiveVideoDecoderForAllSupportedFormats()369 public void testHaveAdaptiveVideoDecoderForAllSupportedFormats() { 370 Set<String> supportedFormats = new HashSet<String>(); 371 boolean skipped = true; 372 373 // gather all supported video formats 374 for (MediaCodecInfo info : mAllInfos) { 375 if (info.isEncoder()) { 376 continue; 377 } 378 for (String mime : info.getSupportedTypes()) { 379 if (isVideoMime(mime)) { 380 supportedFormats.add(mime); 381 } 382 } 383 } 384 385 // limit to CDD-required formats for now 386 supportedFormats.retainAll(requiredAdaptiveFormats()); 387 388 // check if there is an adaptive decoder for each 389 for (String mime : supportedFormats) { 390 skipped = false; 391 // implicit assumption that QVGA video is always valid. 392 MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144); 393 format.setFeatureEnabled(CodecCapabilities.FEATURE_AdaptivePlayback, true); 394 String codec = mAllCodecs.findDecoderForFormat(format); 395 assertTrue( 396 "could not find adaptive decoder for " + mime, codec != null); 397 } 398 if (skipped) { 399 MediaUtils.skipTest("no video decoders that are required to be adaptive found"); 400 } 401 } 402 testAllVideoDecodersAreAdaptive()403 public void testAllVideoDecodersAreAdaptive() { 404 Set<String> adaptiveFormats = requiredAdaptiveFormats(); 405 boolean skipped = true; 406 for (MediaCodecInfo info : mAllInfos) { 407 if (info.isEncoder()) { 408 continue; 409 } 410 for (String mime : info.getSupportedTypes()) { 411 if (!isVideoMime(mime) 412 // limit to CDD-required formats for now 413 || !adaptiveFormats.contains(mime)) { 414 continue; 415 } 416 skipped = false; 417 CodecCapabilities caps = info.getCapabilitiesForType(mime); 418 assertTrue( 419 info.getName() + " is not adaptive for " + mime, 420 caps.isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback)); 421 } 422 } 423 if (skipped) { 424 MediaUtils.skipTest("no video decoders that are required to be adaptive found"); 425 } 426 } 427 createReasonableVideoFormat( CodecCapabilities caps, String mime, boolean encoder, int width, int height)428 private MediaFormat createReasonableVideoFormat( 429 CodecCapabilities caps, String mime, boolean encoder, int width, int height) { 430 VideoCapabilities vidCaps = caps.getVideoCapabilities(); 431 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); 432 if (encoder) { 433 // bitrate 434 int maxWidth = vidCaps.getSupportedWidths().getUpper(); 435 int maxHeight = vidCaps.getSupportedHeightsFor(width).getUpper(); 436 int maxRate = vidCaps.getSupportedFrameRatesFor(width, height).getUpper().intValue(); 437 int bitrate = vidCaps.getBitrateRange().clamp( 438 (int)(vidCaps.getBitrateRange().getUpper() 439 / Math.sqrt((double)maxWidth * maxHeight / width / height))); 440 Log.i(TAG, "reasonable bitrate for " + width + "x" + height + "@" + maxRate 441 + " " + mime + " = " + bitrate); 442 format.setInteger(format.KEY_BIT_RATE, bitrate); 443 format.setInteger(format.KEY_FRAME_RATE, maxRate); 444 format.setInteger(format.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL); 445 } 446 return format; 447 } 448 testSecureCodecsAdvertiseSecurePlayback()449 public void testSecureCodecsAdvertiseSecurePlayback() throws IOException { 450 boolean skipped = true; 451 for (MediaCodecInfo info : mAllInfos) { 452 boolean isEncoder = info.isEncoder(); 453 if (isEncoder || !info.getName().endsWith(".secure")) { 454 continue; 455 } 456 for (String mime : info.getSupportedTypes()) { 457 if (!isVideoMime(mime)) { 458 continue; 459 } 460 skipped = false; 461 CodecCapabilities caps = info.getCapabilitiesForType(mime); 462 assertTrue( 463 info.getName() + " does not advertise secure playback", 464 caps.isFeatureSupported(CodecCapabilities.FEATURE_SecurePlayback)); 465 } 466 } 467 if (skipped) { 468 MediaUtils.skipTest("no video decoders found ending in .secure"); 469 } 470 } 471 testAllNonTunneledVideoCodecsSupportFlexibleYUV()472 public void testAllNonTunneledVideoCodecsSupportFlexibleYUV() throws IOException { 473 boolean skipped = true; 474 for (MediaCodecInfo info : mAllInfos) { 475 boolean isEncoder = info.isEncoder(); 476 for (String mime: info.getSupportedTypes()) { 477 if (!isVideoMime(mime)) { 478 continue; 479 } 480 CodecCapabilities caps = info.getCapabilitiesForType(mime); 481 if (caps.isFeatureRequired(CodecCapabilities.FEATURE_TunneledPlayback) 482 || caps.isFeatureRequired(CodecCapabilities.FEATURE_SecurePlayback)) { 483 continue; 484 } 485 skipped = false; 486 boolean found = false; 487 for (int c : caps.colorFormats) { 488 if (c == caps.COLOR_FormatYUV420Flexible) { 489 found = true; 490 break; 491 } 492 } 493 assertTrue( 494 info.getName() + " does not advertise COLOR_FormatYUV420Flexible", 495 found); 496 497 MediaCodec codec = null; 498 MediaFormat format = null; 499 try { 500 codec = MediaCodec.createByCodecName(info.getName()); 501 // implicit assumption that QVGA video is always valid. 502 format = createReasonableVideoFormat(caps, mime, isEncoder, 176, 144); 503 format.setInteger( 504 MediaFormat.KEY_COLOR_FORMAT, 505 caps.COLOR_FormatYUV420Flexible); 506 507 codec.configure(format, null /* surface */, null /* crypto */, 508 isEncoder ? codec.CONFIGURE_FLAG_ENCODE : 0); 509 MediaFormat configuredFormat = 510 isEncoder ? codec.getInputFormat() : codec.getOutputFormat(); 511 Log.d(TAG, "color format is " + configuredFormat.getInteger( 512 MediaFormat.KEY_COLOR_FORMAT)); 513 if (isEncoder) { 514 codec.start(); 515 int ix = codec.dequeueInputBuffer(TIMEOUT_US); 516 assertNotNull( 517 info.getName() + " encoder has non-flexYUV input buffer #" + ix, 518 codec.getInputImage(ix)); 519 } else { 520 // TODO: test these on various decoders (need test streams) 521 } 522 } finally { 523 if (codec != null) { 524 codec.release(); 525 } 526 } 527 } 528 } 529 if (skipped) { 530 MediaUtils.skipTest("no non-tunneled/non-secure video decoders found"); 531 } 532 } 533 createMinFormat(String mime, CodecCapabilities caps)534 private static MediaFormat createMinFormat(String mime, CodecCapabilities caps) { 535 MediaFormat format; 536 if (caps.getVideoCapabilities() != null) { 537 VideoCapabilities vcaps = caps.getVideoCapabilities(); 538 int minWidth = vcaps.getSupportedWidths().getLower(); 539 int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower(); 540 int minBitrate = vcaps.getBitrateRange().getLower(); 541 format = MediaFormat.createVideoFormat(mime, minWidth, minHeight); 542 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]); 543 format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate); 544 format.setInteger(MediaFormat.KEY_FRAME_RATE, 10); 545 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); 546 } else { 547 AudioCapabilities acaps = caps.getAudioCapabilities(); 548 int minSampleRate = acaps.getSupportedSampleRateRanges()[0].getLower(); 549 int minChannelCount = 1; 550 int minBitrate = acaps.getBitrateRange().getLower(); 551 format = MediaFormat.createAudioFormat(mime, minSampleRate, minChannelCount); 552 format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate); 553 } 554 555 return format; 556 } 557 getActualMax( boolean isEncoder, String name, String mime, CodecCapabilities caps, int max)558 private static int getActualMax( 559 boolean isEncoder, String name, String mime, CodecCapabilities caps, int max) { 560 int flag = isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0; 561 MediaFormat format = createMinFormat(mime, caps); 562 Log.d(TAG, "Test format " + format); 563 Vector<MediaCodec> codecs = new Vector<MediaCodec>(); 564 MediaCodec codec = null; 565 for (int i = 0; i < max; ++i) { 566 try { 567 Log.d(TAG, "Create codec " + name + " #" + i); 568 codec = MediaCodec.createByCodecName(name); 569 codec.configure(format, null, null, flag); 570 codec.start(); 571 codecs.add(codec); 572 codec = null; 573 } catch (IllegalArgumentException e) { 574 fail("Got unexpected IllegalArgumentException " + e.getMessage()); 575 } catch (IOException e) { 576 fail("Got unexpected IOException " + e.getMessage()); 577 } catch (MediaCodec.CodecException e) { 578 // ERROR_INSUFFICIENT_RESOURCE is expected as the test keep creating codecs. 579 // But other exception should be treated as failure. 580 if (e.getErrorCode() == MediaCodec.CodecException.ERROR_INSUFFICIENT_RESOURCE) { 581 Log.d(TAG, "Got CodecException with ERROR_INSUFFICIENT_RESOURCE."); 582 break; 583 } else { 584 fail("Unexpected CodecException " + e.getDiagnosticInfo()); 585 } 586 } finally { 587 if (codec != null) { 588 Log.d(TAG, "release codec"); 589 codec.release(); 590 codec = null; 591 } 592 } 593 } 594 int actualMax = codecs.size(); 595 for (int i = 0; i < codecs.size(); ++i) { 596 Log.d(TAG, "release codec #" + i); 597 codecs.get(i).release(); 598 } 599 codecs.clear(); 600 return actualMax; 601 } 602 testGetMaxSupportedInstances()603 public void testGetMaxSupportedInstances() { 604 final int MAX_INSTANCES = 32; 605 StringBuilder xmlOverrides = new StringBuilder(); 606 MediaCodecList allCodecs = new MediaCodecList(MediaCodecList.ALL_CODECS); 607 for (MediaCodecInfo info : allCodecs.getCodecInfos()) { 608 Log.d(TAG, "codec: " + info.getName()); 609 Log.d(TAG, " isEncoder = " + info.isEncoder()); 610 611 String[] types = info.getSupportedTypes(); 612 for (int j = 0; j < types.length; ++j) { 613 Log.d(TAG, "calling getCapabilitiesForType " + types[j]); 614 CodecCapabilities caps = info.getCapabilitiesForType(types[j]); 615 int max = caps.getMaxSupportedInstances(); 616 Log.d(TAG, "getMaxSupportedInstances returns " + max); 617 assertTrue(max > 0); 618 619 int actualMax = getActualMax( 620 info.isEncoder(), info.getName(), types[j], caps, MAX_INSTANCES); 621 Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max); 622 if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) { 623 String codec = "<MediaCodec name=\"" + info.getName() + 624 "\" type=\"" + types[j] + "\" >"; 625 String limit = " <Limit name=\"concurrent-instances\" max=\"" + 626 actualMax + "\" />"; 627 xmlOverrides.append(codec); 628 xmlOverrides.append("\n"); 629 xmlOverrides.append(limit); 630 xmlOverrides.append("\n"); 631 xmlOverrides.append("</MediaCodec>\n"); 632 } 633 } 634 } 635 636 if (xmlOverrides.length() > 0) { 637 String failMessage = "In order to pass the test, please publish following " + 638 "codecs' concurrent instances limit in /etc/media_codecs.xml: \n"; 639 fail(failMessage + xmlOverrides.toString()); 640 } 641 } 642 } 643