1 /* 2 * Copyright (C) 2019 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.mediav2.cts; 18 19 import static android.mediav2.common.cts.CodecTestBase.hasDecoder; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 import static org.junit.Assume.assumeTrue; 25 26 import android.content.Context; 27 import android.content.res.AssetFileDescriptor; 28 import android.media.MediaCodec; 29 import android.media.MediaCodecInfo; 30 import android.media.MediaDataSource; 31 import android.media.MediaExtractor; 32 import android.media.MediaFormat; 33 import android.mediav2.common.cts.CodecDecoderTestBase; 34 import android.mediav2.common.cts.CodecTestBase; 35 import android.net.Uri; 36 import android.os.ParcelFileDescriptor; 37 import android.os.PersistableBundle; 38 import android.util.Log; 39 import android.webkit.cts.CtsTestServer; 40 41 import androidx.test.filters.LargeTest; 42 import androidx.test.filters.SmallTest; 43 import androidx.test.platform.app.InstrumentationRegistry; 44 45 import com.android.compatibility.common.util.ApiTest; 46 import com.android.compatibility.common.util.CddTest; 47 import com.android.compatibility.common.util.Preconditions; 48 49 import org.apache.http.Header; 50 import org.apache.http.HttpRequest; 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Ignore; 54 import org.junit.Rule; 55 import org.junit.Test; 56 import org.junit.experimental.runners.Enclosed; 57 import org.junit.rules.TestName; 58 import org.junit.runner.RunWith; 59 import org.junit.runners.Parameterized; 60 61 import java.io.BufferedReader; 62 import java.io.File; 63 import java.io.FileInputStream; 64 import java.io.FileOutputStream; 65 import java.io.IOException; 66 import java.io.InputStreamReader; 67 import java.io.Reader; 68 import java.io.StreamTokenizer; 69 import java.nio.ByteBuffer; 70 import java.util.ArrayList; 71 import java.util.Arrays; 72 import java.util.Collection; 73 import java.util.Collections; 74 import java.util.HashMap; 75 import java.util.List; 76 import java.util.Map; 77 import java.util.Random; 78 import java.util.zip.CRC32; 79 80 class TestMediaDataSource extends MediaDataSource { 81 private static final String LOG_TAG = TestMediaDataSource.class.getSimpleName(); 82 private static final boolean ENABLE_LOGS = false; 83 private byte[] mData; 84 private boolean mFatalGetSize; 85 private boolean mFatalReadAt; 86 private boolean mIsClosed = false; 87 fromString(String inpPath, boolean failSize, boolean failRead)88 static TestMediaDataSource fromString(String inpPath, boolean failSize, boolean failRead) 89 throws IOException { 90 try (FileInputStream fInp = new FileInputStream(inpPath)) { 91 int size = (int) new File(inpPath).length(); 92 byte[] data = new byte[size]; 93 fInp.read(data, 0, size); 94 return new TestMediaDataSource(data, failSize, failRead); 95 } 96 } 97 TestMediaDataSource(byte[] data, boolean fatalGetSize, boolean fatalReadAt)98 private TestMediaDataSource(byte[] data, boolean fatalGetSize, boolean fatalReadAt) { 99 mData = data; 100 mFatalGetSize = fatalGetSize; 101 mFatalReadAt = fatalReadAt; 102 } 103 104 @Override readAt(long srcOffset, byte[] buffer, int dstOffset, int size)105 public synchronized int readAt(long srcOffset, byte[] buffer, int dstOffset, int size) 106 throws IOException { 107 if (mFatalReadAt) { 108 throw new IOException("malformed media data source"); 109 } 110 if (srcOffset >= mData.length) { 111 return -1; 112 } 113 if (srcOffset + size > mData.length) { 114 size = mData.length - (int) srcOffset; 115 } 116 System.arraycopy(mData, (int) srcOffset, buffer, dstOffset, size); 117 return size; 118 } 119 120 @Override getSize()121 public synchronized long getSize() throws IOException { 122 if (mFatalGetSize) { 123 throw new IOException("malformed media data source"); 124 } 125 if (ENABLE_LOGS) { 126 Log.v(LOG_TAG, "getSize: " + mData.length); 127 } 128 return mData.length; 129 } 130 131 @Override close()132 public synchronized void close() { 133 mIsClosed = true; 134 } 135 isClosed()136 public boolean isClosed() { 137 return mIsClosed; 138 } 139 } 140 141 @RunWith(Enclosed.class) 142 public class ExtractorTest { 143 private static final String LOG_TAG = ExtractorTest.class.getSimpleName(); 144 private static final boolean ENABLE_LOGS = false; 145 private static final int MAX_SAMPLE_SIZE = 4 * 1024 * 1024; 146 private static final String EXT_SEL_KEY = "ext-sel"; 147 static private final List<String> codecListforTypeMp4 = 148 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_MPEG, MediaFormat.MIMETYPE_AUDIO_AAC, 149 MediaFormat.MIMETYPE_AUDIO_FLAC, MediaFormat.MIMETYPE_AUDIO_VORBIS, 150 MediaFormat.MIMETYPE_AUDIO_OPUS, MediaFormat.MIMETYPE_VIDEO_MPEG2, 151 MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263, 152 MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC); 153 static private final List<String> codecListforTypeWebm = 154 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS, 155 MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9); 156 static private final List<String> codecListforType3gp = 157 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_AUDIO_AMR_NB, 158 MediaFormat.MIMETYPE_AUDIO_AMR_WB, MediaFormat.MIMETYPE_VIDEO_MPEG4, 159 MediaFormat.MIMETYPE_VIDEO_H263, MediaFormat.MIMETYPE_VIDEO_AVC); 160 static private final List<String> codecListforTypeMkv = 161 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_MPEG, MediaFormat.MIMETYPE_AUDIO_AAC, 162 MediaFormat.MIMETYPE_AUDIO_FLAC, MediaFormat.MIMETYPE_AUDIO_VORBIS, 163 MediaFormat.MIMETYPE_AUDIO_OPUS, MediaFormat.MIMETYPE_VIDEO_MPEG2, 164 MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263, 165 MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC, 166 MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9); 167 static private final List<String> codecListforTypeOgg = 168 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS); 169 static private final List<String> codecListforTypeTs = 170 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_VIDEO_MPEG2, 171 MediaFormat.MIMETYPE_VIDEO_AVC); 172 static private final List<String> codecListforTypePs = 173 Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG2); 174 static private final List<String> codecListforTypeRaw = 175 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_AUDIO_FLAC, 176 MediaFormat.MIMETYPE_AUDIO_MPEG, MediaFormat.MIMETYPE_AUDIO_AMR_NB, 177 MediaFormat.MIMETYPE_AUDIO_AMR_WB, MediaFormat.MIMETYPE_AUDIO_RAW); 178 static private final List<String> codecListforTypeWav = 179 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_RAW, MediaFormat.MIMETYPE_AUDIO_G711_ALAW, 180 MediaFormat.MIMETYPE_AUDIO_G711_MLAW, MediaFormat.MIMETYPE_AUDIO_MSGSM); 181 // List of codecs that are not required to be supported as per CDD but are tested 182 static private final List<String> codecListSupp = 183 Arrays.asList(MediaFormat.MIMETYPE_VIDEO_AV1, MediaFormat.MIMETYPE_AUDIO_AC3, 184 MediaFormat.MIMETYPE_AUDIO_AC4, MediaFormat.MIMETYPE_AUDIO_EAC3); 185 private static final String MEDIA_DIR = WorkDir.getMediaDirString(); 186 private static String extSel; 187 188 static { 189 android.os.Bundle args = InstrumentationRegistry.getArguments(); 190 final String defSel = "mp4;webm;3gp;mkv;ogg;supp;raw;ts;ps;wav"; 191 extSel = (null == args.getString(EXT_SEL_KEY)) ? defSel : args.getString(EXT_SEL_KEY); 192 } 193 shouldRunTest(String mediaType)194 private static boolean shouldRunTest(String mediaType) { 195 boolean result = false; 196 if ((extSel.contains("mp4") && codecListforTypeMp4.contains(mediaType)) 197 || (extSel.contains("webm") && codecListforTypeWebm.contains(mediaType)) 198 || (extSel.contains("3gp") && codecListforType3gp.contains(mediaType)) 199 || (extSel.contains("mkv") && codecListforTypeMkv.contains(mediaType)) 200 || (extSel.contains("ogg") && codecListforTypeOgg.contains(mediaType)) 201 || (extSel.contains("ts") && codecListforTypeTs.contains(mediaType)) 202 || (extSel.contains("ps") && codecListforTypePs.contains(mediaType)) 203 || (extSel.contains("raw") && codecListforTypeRaw.contains(mediaType)) 204 || (extSel.contains("wav") && codecListforTypeWav.contains(mediaType)) 205 || (extSel.contains("supp") && codecListSupp.contains(mediaType))) { 206 result = true; 207 } 208 return result; 209 } 210 isExtractorOKonEOS(MediaExtractor extractor)211 private static boolean isExtractorOKonEOS(MediaExtractor extractor) { 212 return extractor.getSampleTrackIndex() < 0 && extractor.getSampleSize() < 0 && 213 extractor.getSampleFlags() < 0 && extractor.getSampleTime() < 0; 214 } 215 isSampleInfoIdentical(MediaCodec.BufferInfo refSample, MediaCodec.BufferInfo testSample)216 private static boolean isSampleInfoIdentical(MediaCodec.BufferInfo refSample, 217 MediaCodec.BufferInfo testSample) { 218 return refSample.flags == testSample.flags && refSample.size == testSample.size && 219 refSample.presentationTimeUs == testSample.presentationTimeUs; 220 } 221 isSampleInfoValidAndIdentical(MediaCodec.BufferInfo refSample, MediaCodec.BufferInfo testSample)222 private static boolean isSampleInfoValidAndIdentical(MediaCodec.BufferInfo refSample, 223 MediaCodec.BufferInfo testSample) { 224 return refSample.flags == testSample.flags && refSample.size == testSample.size && 225 Math.abs(refSample.presentationTimeUs - testSample.presentationTimeUs) <= 1 && 226 refSample.flags >= 0 && refSample.size >= 0 && refSample.presentationTimeUs >= 0; 227 } 228 isCSDIdentical(MediaFormat refFormat, MediaFormat testFormat)229 static boolean isCSDIdentical(MediaFormat refFormat, MediaFormat testFormat) { 230 String mediaType = refFormat.getString(MediaFormat.KEY_MIME); 231 for (int i = 0; ; i++) { 232 String csdKey = "csd-" + i; 233 boolean refHasCSD = refFormat.containsKey(csdKey); 234 boolean testHasCSD = testFormat.containsKey(csdKey); 235 if (refHasCSD != testHasCSD) { 236 if (ENABLE_LOGS) { 237 Log.w(LOG_TAG, "error, ref fmt has CSD: " + refHasCSD + " test fmt has CSD: " + 238 testHasCSD); 239 } 240 return false; 241 } 242 if (refHasCSD) { 243 Log.v(LOG_TAG, mediaType + " has " + csdKey); 244 ByteBuffer r = refFormat.getByteBuffer(csdKey); 245 ByteBuffer t = testFormat.getByteBuffer(csdKey); 246 if (!r.equals(t)) { 247 if (ENABLE_LOGS) { 248 Log.w(LOG_TAG, "ref CSD and test CSD buffers are not identical"); 249 } 250 return false; 251 } 252 } else break; 253 } 254 return true; 255 } 256 isFormatSimilar(MediaFormat refFormat, MediaFormat testFormat)257 static boolean isFormatSimilar(MediaFormat refFormat, MediaFormat testFormat) { 258 String refMediaType = refFormat.getString(MediaFormat.KEY_MIME); 259 String testMediaType = testFormat.getString(MediaFormat.KEY_MIME); 260 261 if (!refMediaType.equals(testMediaType)) return false; 262 if (refFormat.getLong(MediaFormat.KEY_DURATION) != 263 testFormat.getLong(MediaFormat.KEY_DURATION)) { 264 Log.w(LOG_TAG, "Duration mismatches ref / test = " + 265 refFormat.getLong(MediaFormat.KEY_DURATION) + " / " + 266 testFormat.getLong(MediaFormat.KEY_DURATION)); 267 // TODO (b/163477410)(b/163478168) 268 // return false; 269 } 270 if (!isCSDIdentical(refFormat, testFormat)) return false; 271 if (refMediaType.startsWith("audio/")) { 272 if (refFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) != 273 testFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)) return false; 274 if (refFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) != 275 testFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)) return false; 276 } else if (refMediaType.startsWith("video/")) { 277 if (refFormat.getInteger(MediaFormat.KEY_WIDTH) != 278 testFormat.getInteger(MediaFormat.KEY_WIDTH)) return false; 279 if (refFormat.getInteger(MediaFormat.KEY_HEIGHT) != 280 testFormat.getInteger(MediaFormat.KEY_HEIGHT)) return false; 281 } 282 return true; 283 } 284 isMediaSimilar(MediaExtractor refExtractor, MediaExtractor testExtractor, String mediaType, int sampleLimit)285 private static boolean isMediaSimilar(MediaExtractor refExtractor, MediaExtractor testExtractor, 286 String mediaType, int sampleLimit) { 287 ByteBuffer refBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE); 288 ByteBuffer testBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE); 289 290 int noOfTracksMatched = 0; 291 for (int refTrackID = 0; refTrackID < refExtractor.getTrackCount(); refTrackID++) { 292 MediaFormat refFormat = refExtractor.getTrackFormat(refTrackID); 293 String refMediaType = refFormat.getString(MediaFormat.KEY_MIME); 294 if (mediaType != null && !refMediaType.equals(mediaType)) { 295 continue; 296 } 297 for (int testTrackID = 0; testTrackID < testExtractor.getTrackCount(); testTrackID++) { 298 MediaFormat testFormat = testExtractor.getTrackFormat(testTrackID); 299 if (!isFormatSimilar(refFormat, testFormat)) { 300 continue; 301 } 302 refExtractor.selectTrack(refTrackID); 303 testExtractor.selectTrack(testTrackID); 304 305 MediaCodec.BufferInfo refSampleInfo = new MediaCodec.BufferInfo(); 306 MediaCodec.BufferInfo testSampleInfo = new MediaCodec.BufferInfo(); 307 boolean areTracksIdentical = true; 308 for (int frameCount = 0; ; frameCount++) { 309 refSampleInfo.set(0, (int) refExtractor.getSampleSize(), 310 refExtractor.getSampleTime(), refExtractor.getSampleFlags()); 311 testSampleInfo.set(0, (int) testExtractor.getSampleSize(), 312 testExtractor.getSampleTime(), testExtractor.getSampleFlags()); 313 if (!isSampleInfoValidAndIdentical(refSampleInfo, testSampleInfo)) { 314 if (ENABLE_LOGS) { 315 Log.d(LOG_TAG, 316 " Mediatype: " + refMediaType + " mismatch for sample: " 317 + frameCount); 318 Log.d(LOG_TAG, " flags exp/got: " + refSampleInfo.flags + '/' 319 + testSampleInfo.flags); 320 Log.d(LOG_TAG, " size exp/got: " + refSampleInfo.size + '/' 321 + testSampleInfo.size); 322 Log.d(LOG_TAG, " ts exp/got: " + refSampleInfo.presentationTimeUs 323 + '/' + testSampleInfo.presentationTimeUs); 324 } 325 areTracksIdentical = false; 326 break; 327 } 328 int refSz = refExtractor.readSampleData(refBuffer, 0); 329 if (refSz != refSampleInfo.size) { 330 if (ENABLE_LOGS) { 331 Log.d(LOG_TAG, "Mediatype: " + refMediaType + " Size exp/got: " 332 + refSampleInfo.size + '/' + refSz); 333 } 334 areTracksIdentical = false; 335 break; 336 } 337 int testSz = testExtractor.readSampleData(testBuffer, 0); 338 if (testSz != testSampleInfo.size) { 339 if (ENABLE_LOGS) { 340 Log.d(LOG_TAG, "Mediatype: " + refMediaType + " Size exp/got: " 341 + testSampleInfo.size + '/' + testSz); 342 } 343 areTracksIdentical = false; 344 break; 345 } 346 int trackIndex = refExtractor.getSampleTrackIndex(); 347 if (trackIndex != refTrackID) { 348 if (ENABLE_LOGS) { 349 Log.d(LOG_TAG, "Mediatype: " + refMediaType + " TrackID exp/got: " 350 + refTrackID + '/' + trackIndex); 351 } 352 areTracksIdentical = false; 353 break; 354 } 355 trackIndex = testExtractor.getSampleTrackIndex(); 356 if (trackIndex != testTrackID) { 357 if (ENABLE_LOGS) { 358 Log.d(LOG_TAG, "Mediatype: " + refMediaType + " TrackID exp/got: " 359 + testTrackID + '/' + trackIndex); 360 } 361 areTracksIdentical = false; 362 break; 363 } 364 if (!testBuffer.equals(refBuffer)) { 365 if (ENABLE_LOGS) { 366 Log.d(LOG_TAG, 367 "Mediatype: " + refMediaType + " sample data is not identical"); 368 } 369 areTracksIdentical = false; 370 break; 371 } 372 boolean haveRefSamples = refExtractor.advance(); 373 boolean haveTestSamples = testExtractor.advance(); 374 if (haveRefSamples != haveTestSamples) { 375 if (ENABLE_LOGS) { 376 Log.d(LOG_TAG, "Mediatype: " + refMediaType + " Mismatch " 377 + "in sampleCount"); 378 } 379 areTracksIdentical = false; 380 break; 381 } 382 383 if (!haveRefSamples && !isExtractorOKonEOS(refExtractor)) { 384 if (ENABLE_LOGS) { 385 Log.d(LOG_TAG, 386 "Mediatype: " + refMediaType 387 + " calls post advance() are not OK"); 388 } 389 areTracksIdentical = false; 390 break; 391 } 392 if (!haveTestSamples && !isExtractorOKonEOS(testExtractor)) { 393 if (ENABLE_LOGS) { 394 Log.d(LOG_TAG, 395 "Mediatype: " + refMediaType 396 + " calls post advance() are not OK"); 397 } 398 areTracksIdentical = false; 399 break; 400 } 401 if (ENABLE_LOGS) { 402 Log.v(LOG_TAG, "Mediatype: " + refMediaType + " Sample: " + frameCount 403 + " flags: " + refSampleInfo.flags + " size: " + refSampleInfo.size 404 + " ts: " + refSampleInfo.presentationTimeUs); 405 } 406 if (!haveRefSamples || frameCount >= sampleLimit) { 407 break; 408 } 409 } 410 testExtractor.unselectTrack(testTrackID); 411 refExtractor.unselectTrack(refTrackID); 412 if (areTracksIdentical) { 413 noOfTracksMatched++; 414 break; 415 } 416 } 417 if (mediaType != null && noOfTracksMatched > 0) break; 418 } 419 if (mediaType == null) { 420 return noOfTracksMatched == refExtractor.getTrackCount(); 421 } else { 422 return noOfTracksMatched > 0; 423 } 424 } 425 readAllData(MediaExtractor extractor, String mediaType, int sampleLimit)426 private static long readAllData(MediaExtractor extractor, String mediaType, int sampleLimit) { 427 CRC32 checksum = new CRC32(); 428 ByteBuffer buffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE); 429 int tracksSelected = 0; 430 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 431 MediaFormat format = extractor.getTrackFormat(trackID); 432 String srcMediaType = format.getString(MediaFormat.KEY_MIME); 433 if (mediaType != null && !srcMediaType.equals(mediaType)) { 434 continue; 435 } 436 extractor.selectTrack(trackID); 437 tracksSelected++; 438 if (srcMediaType.startsWith("audio/")) { 439 buffer.putInt(0); 440 buffer.putInt(format.getInteger(MediaFormat.KEY_SAMPLE_RATE)); 441 buffer.putInt(format.getInteger(MediaFormat.KEY_CHANNEL_COUNT)); 442 } else if (srcMediaType.startsWith("video/")) { 443 buffer.putInt(1); 444 buffer.putInt(format.getInteger(MediaFormat.KEY_WIDTH)); 445 buffer.putInt(format.getInteger(MediaFormat.KEY_HEIGHT)); 446 } else { 447 buffer.putInt(2); 448 } 449 buffer.putLong(format.getLong(MediaFormat.KEY_DURATION)); 450 for (int i = 0; ; i++) { 451 String csdKey = "csd-" + i; 452 if (format.containsKey(csdKey)) { 453 checksum.update(format.getByteBuffer(csdKey)); 454 } else break; 455 } 456 } 457 assertTrue(tracksSelected > 0); 458 buffer.flip(); 459 checksum.update(buffer); 460 461 MediaCodec.BufferInfo sampleInfo = new MediaCodec.BufferInfo(); 462 for (int sampleCount = 0; sampleCount < sampleLimit; sampleCount++) { 463 sampleInfo.set(0, (int) extractor.getSampleSize(), extractor.getSampleTime(), 464 extractor.getSampleFlags()); 465 extractor.readSampleData(buffer, 0); 466 checksum.update(buffer); 467 assertEquals(sampleInfo.size, buffer.limit()); 468 assertTrue(sampleInfo.flags != -1); 469 assertTrue(sampleInfo.presentationTimeUs != -1); 470 buffer.position(0); 471 buffer.putInt(sampleInfo.size) 472 .putInt(sampleInfo.flags) 473 .putLong(sampleInfo.presentationTimeUs); 474 buffer.flip(); 475 checksum.update(buffer); 476 sampleCount++; 477 if (!extractor.advance()) { 478 assertTrue(isExtractorOKonEOS(extractor)); 479 break; 480 } 481 } 482 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 483 extractor.unselectTrack(trackID); 484 } 485 return checksum.getValue(); 486 } 487 nativeReadAllData(String srcPath, String mediaType, int sampleLimit, String[] keys, String[] values, boolean isSrcUrl)488 private static native long nativeReadAllData(String srcPath, String mediaType, int sampleLimit, 489 String[] keys, String[] values, boolean isSrcUrl); 490 491 /** 492 * Tests setDataSource(...) Api by observing the extractor behavior after its successful 493 * instantiation using a media stream. 494 */ 495 @ApiTest(apis = {"android.media.MediaExtractor#setDataSource", "AMediaExtractor_setDataSource"}) 496 @SmallTest 497 public static class SetDataSourceTest { 498 @Rule 499 public TestName testName = new TestName(); 500 501 private static final String INPUT_MEDIA = "ForBiggerEscapes.mp4"; 502 private static final String RES_STRING = "raw/forbiggerescapes"; 503 private CtsTestServer mWebServer; 504 private String mInpMediaUrl; 505 private MediaExtractor mRefExtractor; 506 507 static { 508 System.loadLibrary("ctsmediav2extractor_jni"); 509 } 510 511 @Before setUp()512 public void setUp() throws IOException { 513 mRefExtractor = new MediaExtractor(); 514 Preconditions.assertTestFileExists(MEDIA_DIR + INPUT_MEDIA); 515 mRefExtractor.setDataSource(MEDIA_DIR + INPUT_MEDIA); 516 try { 517 Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 518 mWebServer = new CtsTestServer(context); 519 mInpMediaUrl = mWebServer.getAssetUrl(RES_STRING); 520 } catch (Exception e) { 521 fail(e.getMessage()); 522 } 523 } 524 525 @After tearDown()526 public void tearDown() { 527 mRefExtractor.release(); 528 mRefExtractor = null; 529 mWebServer.shutdown(); 530 } 531 areMetricsIdentical(MediaExtractor refExtractor, MediaExtractor testExtractor)532 private static boolean areMetricsIdentical(MediaExtractor refExtractor, 533 MediaExtractor testExtractor) { 534 PersistableBundle bundle = refExtractor.getMetrics(); 535 int refNumTracks = bundle.getInt(MediaExtractor.MetricsConstants.TRACKS); 536 String refFormat = bundle.getString(MediaExtractor.MetricsConstants.FORMAT); 537 String refMediaType = bundle.getString(MediaExtractor.MetricsConstants.MIME_TYPE); 538 bundle = testExtractor.getMetrics(); 539 int testNumTracks = bundle.getInt(MediaExtractor.MetricsConstants.TRACKS); 540 String testFormat = bundle.getString(MediaExtractor.MetricsConstants.FORMAT); 541 String testMediaType = bundle.getString(MediaExtractor.MetricsConstants.MIME_TYPE); 542 boolean result = testNumTracks == refNumTracks && testFormat.equals(refFormat) && 543 testMediaType.equals(refMediaType); 544 if (ENABLE_LOGS) { 545 Log.d(LOG_TAG, " NumTracks exp/got: " + refNumTracks + '/' + testNumTracks); 546 Log.d(LOG_TAG, " Format exp/got: " + refFormat + '/' + testFormat); 547 Log.d(LOG_TAG, " Mediatype exp/got: " + refMediaType + '/' + testMediaType); 548 } 549 return result; 550 } 551 isSeekOk(MediaExtractor refExtractor, MediaExtractor testExtractor)552 private static boolean isSeekOk(MediaExtractor refExtractor, MediaExtractor testExtractor) { 553 final long maxEstDuration = 14000000; 554 final int MAX_SEEK_POINTS = 7; 555 final long mSeed = 0x12b9b0a1; 556 final Random randNum = new Random(mSeed); 557 MediaCodec.BufferInfo refSampleInfo = new MediaCodec.BufferInfo(); 558 MediaCodec.BufferInfo testSampleInfo = new MediaCodec.BufferInfo(); 559 boolean result = true; 560 for (int trackID = 0; trackID < refExtractor.getTrackCount() && result; trackID++) { 561 refExtractor.selectTrack(trackID); 562 testExtractor.selectTrack(trackID); 563 for (int i = 0; i < MAX_SEEK_POINTS && result; i++) { 564 long pts = (long) (randNum.nextDouble() * maxEstDuration); 565 for (int mode = MediaExtractor.SEEK_TO_PREVIOUS_SYNC; 566 mode <= MediaExtractor.SEEK_TO_CLOSEST_SYNC; mode++) { 567 refExtractor.seekTo(pts, mode); 568 testExtractor.seekTo(pts, mode); 569 refSampleInfo.set(0, (int) refExtractor.getSampleSize(), 570 refExtractor.getSampleTime(), refExtractor.getSampleFlags()); 571 testSampleInfo.set(0, (int) testExtractor.getSampleSize(), 572 testExtractor.getSampleTime(), testExtractor.getSampleFlags()); 573 result = isSampleInfoIdentical(refSampleInfo, testSampleInfo); 574 int refTrackIdx = refExtractor.getSampleTrackIndex(); 575 int testTrackIdx = testExtractor.getSampleTrackIndex(); 576 result &= (refTrackIdx == testTrackIdx); 577 if (ENABLE_LOGS) { 578 Log.d(LOG_TAG, " mode/pts/trackId:" + mode + "/" + pts + "/" + trackID); 579 Log.d(LOG_TAG, " trackId exp/got: " + refTrackIdx + '/' + testTrackIdx); 580 Log.d(LOG_TAG, " flags exp/got: " + 581 refSampleInfo.flags + '/' + testSampleInfo.flags); 582 Log.d(LOG_TAG, " size exp/got: " + 583 refSampleInfo.size + '/' + testSampleInfo.size); 584 Log.d(LOG_TAG, " ts exp/got: " + refSampleInfo.presentationTimeUs + 585 '/' + testSampleInfo.presentationTimeUs); 586 } 587 } 588 } 589 refExtractor.unselectTrack(trackID); 590 testExtractor.unselectTrack(trackID); 591 } 592 return result; 593 } 594 595 @Test testAssetFD()596 public void testAssetFD() throws IOException { 597 Preconditions.assertTestFileExists(MEDIA_DIR + INPUT_MEDIA); 598 File inpFile = new File(MEDIA_DIR + INPUT_MEDIA); 599 MediaExtractor testExtractor = new MediaExtractor(); 600 try (ParcelFileDescriptor parcelFD = ParcelFileDescriptor 601 .open(inpFile, ParcelFileDescriptor.MODE_READ_ONLY); 602 AssetFileDescriptor afd = new AssetFileDescriptor(parcelFD, 0, 603 AssetFileDescriptor.UNKNOWN_LENGTH)) { 604 testExtractor.setDataSource(afd); 605 } 606 assertTrue(testExtractor.getCachedDuration() < 0); 607 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 608 !areMetricsIdentical(mRefExtractor, testExtractor) || 609 !isSeekOk(mRefExtractor, testExtractor)) { 610 fail("setDataSource failed: " + testName.getMethodName()); 611 } 612 testExtractor.release(); 613 } 614 615 @Test 616 public void testFileDescriptor() throws IOException { 617 Preconditions.assertTestFileExists(MEDIA_DIR + INPUT_MEDIA); 618 File inpFile = new File(MEDIA_DIR + INPUT_MEDIA); 619 MediaExtractor testExtractor = new MediaExtractor(); 620 try (FileInputStream fInp = new FileInputStream(inpFile)) { 621 testExtractor.setDataSource(fInp.getFD()); 622 } 623 assertTrue(testExtractor.getCachedDuration() < 0); 624 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 625 !areMetricsIdentical(mRefExtractor, testExtractor) || 626 !isSeekOk(mRefExtractor, testExtractor)) { 627 fail("setDataSource failed: " + testName.getMethodName()); 628 } 629 long sdkChecksum = readAllData(testExtractor, null, Integer.MAX_VALUE); 630 long ndkChecksum = nativeReadAllData(MEDIA_DIR + INPUT_MEDIA, "", 631 Integer.MAX_VALUE, null, null, false); 632 testExtractor.release(); 633 assertEquals("SDK and NDK checksums mismatch", sdkChecksum, ndkChecksum); 634 } 635 636 @Test 637 public void testFileDescriptorLenOffset() throws IOException { 638 Preconditions.assertTestFileExists(MEDIA_DIR + INPUT_MEDIA); 639 File inpFile = new File(MEDIA_DIR + INPUT_MEDIA); 640 File outFile = File.createTempFile("temp", ".out"); 641 byte[] garbageAppend = "PrefixGarbage".getBytes(); 642 try (FileInputStream fInp = new FileInputStream(inpFile); 643 FileOutputStream fOut = new FileOutputStream(outFile)) { 644 fOut.write(garbageAppend); 645 byte[] data = new byte[(int) new File(inpFile.toString()).length()]; 646 if (fInp.read(data) == -1) { 647 fail("Failed to read input file"); 648 } 649 fOut.write(data); 650 fOut.write(garbageAppend); 651 } 652 MediaExtractor testExtractor = new MediaExtractor(); 653 try (FileInputStream fInp = new FileInputStream(outFile)) { 654 testExtractor.setDataSource(fInp.getFD(), garbageAppend.length, 655 inpFile.length()); 656 } 657 assertTrue(testExtractor.getCachedDuration() < 0); 658 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 659 !areMetricsIdentical(mRefExtractor, testExtractor) || 660 !isSeekOk(mRefExtractor, testExtractor)) { 661 fail("setDataSource failed: " + testName.getMethodName()); 662 } 663 testExtractor.release(); 664 outFile.delete(); 665 } 666 667 @Test 668 public void testMediaDataSource() throws Exception { 669 Preconditions.assertTestFileExists(MEDIA_DIR + INPUT_MEDIA); 670 TestMediaDataSource dataSource = 671 TestMediaDataSource.fromString(MEDIA_DIR + INPUT_MEDIA, false, false); 672 MediaExtractor testExtractor = new MediaExtractor(); 673 testExtractor.setDataSource(dataSource); 674 assertTrue(testExtractor.getCachedDuration() < 0); 675 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 676 !areMetricsIdentical(mRefExtractor, testExtractor) || 677 !isSeekOk(mRefExtractor, testExtractor)) { 678 fail("setDataSource failed: " + testName.getMethodName()); 679 } 680 testExtractor.release(); 681 assertTrue(dataSource.isClosed()); 682 } 683 684 @Test 685 public void testContextUri() throws IOException { 686 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 687 String path = "android.resource://android.mediav2.cts/" + RES_STRING; 688 MediaExtractor testExtractor = new MediaExtractor(); 689 testExtractor.setDataSource(context, Uri.parse(path), null); 690 assertTrue(testExtractor.getCachedDuration() < 0); 691 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 692 !areMetricsIdentical(mRefExtractor, testExtractor) || 693 !isSeekOk(mRefExtractor, testExtractor)) { 694 fail("setDataSource failed: " + testName.getMethodName()); 695 } 696 testExtractor.release(); 697 } 698 699 private void checkExtractorOkForUrlDS(Map<String, String> headers) throws Exception { 700 MediaExtractor testExtractor = new MediaExtractor(); 701 testExtractor.setDataSource(mInpMediaUrl, headers); 702 HttpRequest req = mWebServer.getLastAssetRequest(RES_STRING); 703 if (headers != null) { 704 for (String key : headers.keySet()) { 705 String value = headers.get(key); 706 Header[] header = req.getHeaders(key); 707 assertTrue( 708 "expecting " + key + ":" + value + ", saw " + Arrays.toString(header), 709 header.length == 1 && header[0].getValue().equals(value)); 710 } 711 } 712 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 713 !areMetricsIdentical(mRefExtractor, testExtractor) || 714 !isSeekOk(mRefExtractor, testExtractor)) { 715 fail("setDataSource failed: " + testName.getMethodName()); 716 } 717 testExtractor.selectTrack(0); 718 for (int idx = 0; ; idx++) { 719 if ((idx & (idx - 1)) == 0) { 720 long cachedDuration = testExtractor.getCachedDuration(); 721 if (ENABLE_LOGS) { 722 Log.v(LOG_TAG, "cachedDuration at frame: " + idx + " is:" + cachedDuration); 723 } 724 assertTrue("cached duration should be non-negative", cachedDuration >= 0); 725 } 726 if (!testExtractor.advance()) break; 727 } 728 assertTrue(testExtractor.hasCacheReachedEndOfStream()); 729 testExtractor.unselectTrack(0); 730 testExtractor.release(); 731 } 732 733 @Test 734 public void testUrlDataSource() throws Exception { 735 checkExtractorOkForUrlDS(null); 736 737 Map<String, String> headers = new HashMap<>(); 738 checkExtractorOkForUrlDS(headers); 739 740 String[] keys = new String[]{"From", "Client", "Location"}; 741 String[] values = new String[]{"alcor@bigdipper.asm", "CtsTestServer", "UrsaMajor"}; 742 for (int i = 0; i < keys.length; i++) { 743 headers.put(keys[i], values[i]); 744 } 745 checkExtractorOkForUrlDS(headers); 746 747 MediaExtractor testExtractor = new MediaExtractor(); 748 testExtractor.setDataSource(mInpMediaUrl, headers); 749 long sdkChecksum = readAllData(testExtractor, null, Integer.MAX_VALUE); 750 testExtractor.release(); 751 long ndkChecksum = nativeReadAllData(mInpMediaUrl, "", Integer.MAX_VALUE, keys, 752 values, true); 753 assertEquals("SDK and NDK checksums mismatch", sdkChecksum, ndkChecksum); 754 ndkChecksum = nativeReadAllData(mInpMediaUrl, "", Integer.MAX_VALUE, new String[0], 755 new String[0], true); 756 assertEquals("SDK and NDK checksums mismatch", sdkChecksum, ndkChecksum); 757 } 758 759 private native boolean nativeTestDataSource(String srcPath, String srcUrl); 760 761 @Test 762 public void testDataSourceNative() { 763 Preconditions.assertTestFileExists(MEDIA_DIR + INPUT_MEDIA); 764 assertTrue(testName.getMethodName() + " failed ", 765 nativeTestDataSource(MEDIA_DIR + INPUT_MEDIA, mInpMediaUrl)); 766 } 767 } 768 769 /** 770 * Encloses extractor functionality tests 771 */ 772 @RunWith(Parameterized.class) 773 public static class FunctionalityTest { 774 private static final int MAX_SEEK_POINTS = 7; 775 private static final long SEED = 0x12b9b0a1; 776 private final Random mRandNum = new Random(SEED); 777 private String[] mSrcFiles; 778 private String mMediaType; 779 780 static { 781 System.loadLibrary("ctsmediav2extractor_jni"); 782 } 783 784 @Rule 785 public TestName testName = new TestName(); 786 787 @Parameterized.Parameters(name = "{index}_{0}") 788 public static Collection<Object[]> input() { 789 return Arrays.asList(new Object[][]{ 790 {MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{ 791 "bbb_cif_768kbps_30fps_mpeg2_stereo_48kHz_192kbps_mp3.mp4", 792 "bbb_cif_768kbps_30fps_mpeg2.mkv", 793 /* TODO(b/162919907) 794 "bbb_cif_768kbps_30fps_mpeg2.vob",*/ 795 /* TODO(b/162715861) 796 "bbb_cif_768kbps_30fps_mpeg2.ts" */}}, 797 {MediaFormat.MIMETYPE_VIDEO_H263, new String[]{ 798 "bbb_cif_768kbps_30fps_h263.mp4", 799 "bbb_cif_768kbps_30fps_h263_stereo_48kHz_192kbps_flac.mkv", 800 "bbb_cif_768kbps_30fps_h263_mono_8kHz_12kbps_amrnb.3gp",}}, 801 {MediaFormat.MIMETYPE_VIDEO_MPEG4, new String[]{ 802 "bbb_cif_768kbps_30fps_mpeg4.mkv", 803 "bbb_cif_768kbps_30fps_mpeg4_stereo_48kHz_192kbps_flac.mp4", 804 "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp",}}, 805 {MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 806 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_vorbis.mp4", 807 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.mkv", 808 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.3gp", 809 /* TODO(b/162715861) 810 "bbb_cif_768kbps_30fps_avc.ts",*/}}, 811 {MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{ 812 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_opus.mp4", 813 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_mp3.mkv",}}, 814 {MediaFormat.MIMETYPE_VIDEO_VP8, new String[]{ 815 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm", 816 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.mkv"}}, 817 {MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{ 818 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm", 819 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.mkv",}}, 820 {MediaFormat.MIMETYPE_VIDEO_AV1, new String[]{ 821 "bbb_cif_768kbps_30fps_av1.mp4", 822 "bbb_cif_768kbps_30fps_av1.webm", 823 "bbb_cif_768kbps_30fps_av1.mkv",}}, 824 {MediaFormat.MIMETYPE_AUDIO_VORBIS, new String[]{ 825 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_vorbis.mp4", 826 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.mkv", 827 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm", 828 "bbb_stereo_48kHz_192kbps_vorbis.ogg",}}, 829 {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{ 830 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm", 831 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.mkv", 832 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_opus.mp4", 833 "bbb_stereo_48kHz_192kbps_opus.ogg",}}, 834 {MediaFormat.MIMETYPE_AUDIO_MPEG, new String[]{ 835 "bbb_stereo_48kHz_192kbps_mp3.mp3", 836 "bbb_cif_768kbps_30fps_mpeg2_stereo_48kHz_192kbps_mp3.mp4", 837 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_mp3.mkv",}}, 838 {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{ 839 "bbb_stereo_48kHz_192kbps_aac.mp4", 840 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.3gp", 841 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.mkv", 842 "bbb_stereo_48kHz_128kbps_aac.ts",}}, 843 {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{ 844 "bbb_cif_768kbps_30fps_h263_mono_8kHz_12kbps_amrnb.3gp", 845 "bbb_mono_8kHz_12kbps_amrnb.amr",}}, 846 {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{ 847 "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp", 848 "bbb_mono_16kHz_20kbps_amrwb.amr"}}, 849 {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{ 850 "bbb_cif_768kbps_30fps_mpeg4_stereo_48kHz_192kbps_flac.mp4", 851 "bbb_cif_768kbps_30fps_h263_stereo_48kHz_192kbps_flac.mkv",}}, 852 {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"canon.mid",}}, 853 {MediaFormat.MIMETYPE_AUDIO_AC3, new String[]{ 854 "testac3mp4.mp4", "testac3ts.ts",}}, 855 {MediaFormat.MIMETYPE_AUDIO_AC4, new String[]{"multi0.mp4",}}, 856 {MediaFormat.MIMETYPE_AUDIO_EAC3, new String[]{ 857 "testeac3mp4.mp4", "testeac3ts.ts",}}, 858 {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"bbb_1ch_16kHz.wav",}}, 859 {MediaFormat.MIMETYPE_AUDIO_G711_ALAW, new String[]{"bbb_2ch_8kHz_alaw.wav",}}, 860 {MediaFormat.MIMETYPE_AUDIO_G711_MLAW, new String[]{"bbb_2ch_8kHz_mulaw.wav",}}, 861 {MediaFormat.MIMETYPE_AUDIO_MSGSM, new String[]{"bbb_1ch_8kHz_gsm.wav",}}, 862 }); 863 } 864 865 private native boolean nativeTestExtract(String srcPath, String refPath, String mediaType); 866 867 private native boolean nativeTestSeek(String srcPath, String mediaType); 868 869 private native boolean nativeTestSeekFlakiness(String srcPath, String mediaType); 870 871 private native boolean nativeTestSeekToZero(String srcPath, String mediaType); 872 873 private native boolean nativeTestFileFormat(String srcPath); 874 875 public FunctionalityTest(String mediaType, String[] srcFiles) { 876 mMediaType = mediaType; 877 mSrcFiles = srcFiles; 878 } 879 880 // content necessary for testing seek are grouped in this class 881 private class SeekTestParams { 882 MediaCodec.BufferInfo mExpected; 883 long mTimeStamp; 884 int mMode; 885 886 SeekTestParams(MediaCodec.BufferInfo expected, long timeStamp, int mode) { 887 mExpected = expected; 888 mTimeStamp = timeStamp; 889 mMode = mode; 890 } 891 } 892 893 private ArrayList<MediaCodec.BufferInfo> getSeekablePoints(String srcFile, String mediaType) 894 throws IOException { 895 ArrayList<MediaCodec.BufferInfo> bookmarks = null; 896 if (mediaType == null) return null; 897 MediaExtractor extractor = new MediaExtractor(); 898 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 899 extractor.setDataSource(MEDIA_DIR + srcFile); 900 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 901 MediaFormat format = extractor.getTrackFormat(trackID); 902 if (!mediaType.equals(format.getString(MediaFormat.KEY_MIME))) continue; 903 extractor.selectTrack(trackID); 904 bookmarks = new ArrayList<>(); 905 do { 906 int sampleFlags = extractor.getSampleFlags(); 907 if ((sampleFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { 908 MediaCodec.BufferInfo sampleInfo = new MediaCodec.BufferInfo(); 909 sampleInfo.set(0, (int) extractor.getSampleSize(), 910 extractor.getSampleTime(), extractor.getSampleFlags()); 911 bookmarks.add(sampleInfo); 912 } 913 } while (extractor.advance()); 914 extractor.unselectTrack(trackID); 915 break; 916 } 917 extractor.release(); 918 return bookmarks; 919 } 920 921 private ArrayList<SeekTestParams> generateSeekTestArgs(String srcFile, String mediaType, 922 boolean isRandom) throws IOException { 923 ArrayList<SeekTestParams> testArgs = new ArrayList<>(); 924 if (mediaType == null) return null; 925 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 926 if (isRandom) { 927 MediaExtractor extractor = new MediaExtractor(); 928 extractor.setDataSource(MEDIA_DIR + srcFile); 929 final long maxEstDuration = 4000000; 930 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 931 MediaFormat format = extractor.getTrackFormat(trackID); 932 if (!mediaType.equals(format.getString(MediaFormat.KEY_MIME))) continue; 933 extractor.selectTrack(trackID); 934 for (int i = 0; i < MAX_SEEK_POINTS; i++) { 935 long pts = (long) (mRandNum.nextDouble() * maxEstDuration); 936 for (int mode = MediaExtractor.SEEK_TO_PREVIOUS_SYNC; 937 mode <= MediaExtractor.SEEK_TO_CLOSEST_SYNC; mode++) { 938 MediaCodec.BufferInfo currInfo = new MediaCodec.BufferInfo(); 939 extractor.seekTo(pts, mode); 940 currInfo.set(0, (int) extractor.getSampleSize(), 941 extractor.getSampleTime(), extractor.getSampleFlags()); 942 testArgs.add(new SeekTestParams(currInfo, pts, mode)); 943 } 944 } 945 extractor.unselectTrack(trackID); 946 break; 947 } 948 extractor.release(); 949 } else { 950 ArrayList<MediaCodec.BufferInfo> bookmarks = getSeekablePoints(srcFile, mediaType); 951 if (bookmarks == null) return null; 952 int size = bookmarks.size(); 953 int[] indices; 954 if (size > MAX_SEEK_POINTS) { 955 indices = new int[MAX_SEEK_POINTS]; 956 indices[0] = 0; 957 indices[MAX_SEEK_POINTS - 1] = size - 1; 958 for (int i = 1; i < MAX_SEEK_POINTS - 1; i++) { 959 indices[i] = (int) (mRandNum.nextDouble() * (MAX_SEEK_POINTS - 1) + 1); 960 } 961 } else { 962 indices = new int[size]; 963 for (int i = 0; i < size; i++) indices[i] = i; 964 } 965 // closest sync : Seek to the sync sample CLOSEST to the specified time 966 // previous sync : Seek to a sync sample AT or AFTER the specified time 967 // next sync : Seek to a sync sample AT or BEFORE the specified time 968 for (int i : indices) { 969 MediaCodec.BufferInfo currInfo = bookmarks.get(i); 970 long pts = currInfo.presentationTimeUs; 971 testArgs.add( 972 new SeekTestParams(currInfo, pts, MediaExtractor.SEEK_TO_CLOSEST_SYNC)); 973 testArgs.add( 974 new SeekTestParams(currInfo, pts, MediaExtractor.SEEK_TO_NEXT_SYNC)); 975 testArgs.add( 976 new SeekTestParams(currInfo, pts, 977 MediaExtractor.SEEK_TO_PREVIOUS_SYNC)); 978 if (i > 0) { 979 MediaCodec.BufferInfo prevInfo = bookmarks.get(i - 1); 980 long ptsMinus = prevInfo.presentationTimeUs; 981 ptsMinus = pts - ((pts - ptsMinus) >> 3); 982 testArgs.add(new SeekTestParams(currInfo, ptsMinus, 983 MediaExtractor.SEEK_TO_CLOSEST_SYNC)); 984 testArgs.add(new SeekTestParams(currInfo, ptsMinus, 985 MediaExtractor.SEEK_TO_NEXT_SYNC)); 986 testArgs.add(new SeekTestParams(prevInfo, ptsMinus, 987 MediaExtractor.SEEK_TO_PREVIOUS_SYNC)); 988 } 989 if (i < size - 1) { 990 MediaCodec.BufferInfo nextInfo = bookmarks.get(i + 1); 991 long ptsPlus = nextInfo.presentationTimeUs; 992 ptsPlus = pts + ((ptsPlus - pts) >> 3); 993 testArgs.add(new SeekTestParams(currInfo, ptsPlus, 994 MediaExtractor.SEEK_TO_CLOSEST_SYNC)); 995 testArgs.add(new SeekTestParams(nextInfo, ptsPlus, 996 MediaExtractor.SEEK_TO_NEXT_SYNC)); 997 testArgs.add(new SeekTestParams(currInfo, ptsPlus, 998 MediaExtractor.SEEK_TO_PREVIOUS_SYNC)); 999 } 1000 } 1001 } 1002 return testArgs; 1003 } 1004 1005 int checkSeekPoints(String srcFile, String mediaType, 1006 ArrayList<SeekTestParams> seekTestArgs) throws IOException { 1007 int errCnt = 0; 1008 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1009 MediaExtractor extractor = new MediaExtractor(); 1010 extractor.setDataSource(MEDIA_DIR + srcFile); 1011 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 1012 MediaFormat format = extractor.getTrackFormat(trackID); 1013 if (!format.getString(MediaFormat.KEY_MIME).equals(mediaType)) continue; 1014 extractor.selectTrack(trackID); 1015 MediaCodec.BufferInfo received = new MediaCodec.BufferInfo(); 1016 for (SeekTestParams arg : seekTestArgs) { 1017 extractor.seekTo(arg.mTimeStamp, arg.mMode); 1018 received.set(0, (int) extractor.getSampleSize(), extractor.getSampleTime(), 1019 extractor.getSampleFlags()); 1020 if (!isSampleInfoIdentical(arg.mExpected, received)) { 1021 errCnt++; 1022 if (ENABLE_LOGS) { 1023 Log.d(LOG_TAG, " flags exp/got: " + arg.mExpected.flags + '/' + 1024 received.flags); 1025 Log.d(LOG_TAG, 1026 " size exp/got: " + arg.mExpected.size + '/' + received.size); 1027 Log.d(LOG_TAG, 1028 " ts exp/got: " + arg.mExpected.presentationTimeUs + '/' + 1029 received.presentationTimeUs); 1030 } 1031 } 1032 } 1033 extractor.unselectTrack(trackID); 1034 break; 1035 } 1036 extractor.release(); 1037 return errCnt; 1038 } 1039 1040 private boolean isFileSeekable(String srcFile) throws IOException { 1041 MediaExtractor ext = new MediaExtractor(); 1042 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1043 ext.setDataSource(MEDIA_DIR + srcFile); 1044 String format = ext.getMetrics().getString(MediaExtractor.MetricsConstants.FORMAT); 1045 ext.release(); 1046 // MPEG2TS and MPEG2PS files are non-seekable 1047 return !(format.equalsIgnoreCase("MPEG2TSExtractor") || 1048 format.equalsIgnoreCase("MPEG2PSExtractor")); 1049 } 1050 1051 /** 1052 * Audio, Video codecs support a variety of file-types/container formats. For example, 1053 * Vorbis supports OGG, MP4, WEBM and MKV. H.263 supports 3GPP, WEBM and MKV. For every 1054 * mediaType, a list of test vectors are provided one for each container) but underlying 1055 * elementary stream is the same for all. The streams of a mediaType are extracted and 1056 * compared with each other for similarity. 1057 */ 1058 @CddTest(requirements = {"5.1.3", "5.1.8"}) 1059 @LargeTest 1060 @Test 1061 public void testExtract() throws IOException { 1062 assumeTrue(shouldRunTest(mMediaType)); 1063 Preconditions.assertTestFileExists(MEDIA_DIR + mSrcFiles[0]); 1064 MediaExtractor refExtractor = new MediaExtractor(); 1065 refExtractor.setDataSource(MEDIA_DIR + mSrcFiles[0]); 1066 long sdkChecksum = readAllData(refExtractor, mMediaType, Integer.MAX_VALUE); 1067 long ndkChecksum = nativeReadAllData(MEDIA_DIR + mSrcFiles[0], mMediaType, 1068 Integer.MAX_VALUE, null, null, false); 1069 assertEquals("SDK and NDK checksums mismatch", sdkChecksum, ndkChecksum); 1070 if (mSrcFiles.length == 1) { 1071 refExtractor.release(); 1072 return; 1073 } 1074 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 1075 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_OPUS)); 1076 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 1077 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 1078 boolean isOk = true; 1079 for (int i = 1; i < mSrcFiles.length && isOk; i++) { 1080 MediaExtractor testExtractor = new MediaExtractor(); 1081 Preconditions.assertTestFileExists(MEDIA_DIR + mSrcFiles[i]); 1082 testExtractor.setDataSource(MEDIA_DIR + mSrcFiles[i]); 1083 if (!isMediaSimilar(refExtractor, testExtractor, mMediaType, Integer.MAX_VALUE)) { 1084 if (ENABLE_LOGS) { 1085 Log.d(LOG_TAG, "Files: " + mSrcFiles[0] + ", " + mSrcFiles[i] + 1086 " are different from extractor perspective"); 1087 } 1088 if (!codecListSupp.contains(mMediaType)) { 1089 isOk = false; 1090 } 1091 } 1092 testExtractor.release(); 1093 } 1094 refExtractor.release(); 1095 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1096 } 1097 1098 /** 1099 * Tests seek functionality, verifies if we seek to most accurate point for a given 1100 * choice of timestamp and mode. 1101 */ 1102 @ApiTest(apis = {"android.media.MediaExtractor#seekTo", 1103 "android.media.MediaExtractor#SEEK_TO_CLOSEST_SYNC", 1104 "android.media.MediaExtractor#SEEK_TO_NEXT_SYNC", 1105 "android.media.MediaExtractor#SEEK_TO_PREVIOUS_SYNC"}) 1106 @LargeTest 1107 @Test 1108 @Ignore("TODO(b/146420831)") 1109 public void testSeek() throws IOException { 1110 assumeTrue(shouldRunTest(mMediaType) 1111 && !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)); 1112 boolean isOk = true; 1113 for (String srcFile : mSrcFiles) { 1114 if (!isFileSeekable(srcFile)) continue; 1115 ArrayList<SeekTestParams> seekTestArgs = 1116 generateSeekTestArgs(srcFile, mMediaType, false); 1117 assertTrue("mediaType is null.", seekTestArgs != null); 1118 assertTrue("No sync samples found.", !seekTestArgs.isEmpty()); 1119 Collections.shuffle(seekTestArgs, mRandNum); 1120 int seekAccErrCnt = checkSeekPoints(srcFile, mMediaType, seekTestArgs); 1121 if (seekAccErrCnt != 0) { 1122 if (ENABLE_LOGS) { 1123 Log.d(LOG_TAG, "For " + srcFile + " seek chose inaccurate Sync point in: " + 1124 seekAccErrCnt + "/" + seekTestArgs.size()); 1125 } 1126 if (!codecListSupp.contains(mMediaType)) { 1127 isOk = false; 1128 break; 1129 } 1130 } 1131 } 1132 assertTrue(testName.getMethodName() + " failed for mediaType: " + mMediaType, isOk); 1133 } 1134 1135 /** 1136 * Tests if we get the same content each time after a call to seekto; 1137 */ 1138 @ApiTest(apis = {"android.media.MediaExtractor#seekTo", 1139 "android.media.MediaExtractor#SEEK_TO_CLOSEST_SYNC", 1140 "android.media.MediaExtractor#SEEK_TO_NEXT_SYNC", 1141 "android.media.MediaExtractor#SEEK_TO_PREVIOUS_SYNC"}) 1142 @LargeTest 1143 @Test 1144 public void testSeekFlakiness() throws IOException { 1145 assumeTrue(shouldRunTest(mMediaType)); 1146 boolean isOk = true; 1147 for (String srcFile : mSrcFiles) { 1148 if (!isFileSeekable(srcFile)) continue; 1149 ArrayList<SeekTestParams> seekTestArgs = 1150 generateSeekTestArgs(srcFile, mMediaType, true); 1151 assertTrue("mediaType is null.", seekTestArgs != null); 1152 assertTrue("No samples found.", !seekTestArgs.isEmpty()); 1153 Collections.shuffle(seekTestArgs, mRandNum); 1154 int flakyErrCnt = checkSeekPoints(srcFile, mMediaType, seekTestArgs); 1155 if (flakyErrCnt != 0) { 1156 if (ENABLE_LOGS) { 1157 Log.d(LOG_TAG, 1158 "No. of Samples where seek showed flakiness is: " + flakyErrCnt); 1159 } 1160 if (!codecListSupp.contains(mMediaType)) { 1161 isOk = false; 1162 break; 1163 } 1164 } 1165 } 1166 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1167 } 1168 1169 /** 1170 * Test if seekTo(0) yields the same content as if we had just opened the file and started 1171 * reading. 1172 */ 1173 @ApiTest(apis = {"android.media.MediaExtractor#seekTo", 1174 "android.media.MediaExtractor#SEEK_TO_CLOSEST_SYNC", 1175 "android.media.MediaExtractor#SEEK_TO_NEXT_SYNC", 1176 "android.media.MediaExtractor#SEEK_TO_PREVIOUS_SYNC"}) 1177 @SmallTest 1178 @Test 1179 public void testSeekToZero() throws IOException { 1180 assumeTrue(shouldRunTest(mMediaType)); 1181 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 1182 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 1183 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 1184 boolean isOk = true; 1185 for (String srcFile : mSrcFiles) { 1186 if (!isFileSeekable(srcFile)) continue; 1187 MediaExtractor extractor = new MediaExtractor(); 1188 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1189 extractor.setDataSource(MEDIA_DIR + srcFile); 1190 MediaCodec.BufferInfo sampleInfoAtZero = new MediaCodec.BufferInfo(); 1191 MediaCodec.BufferInfo currInfo = new MediaCodec.BufferInfo(); 1192 final long randomSeekPts = 1 << 20; 1193 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 1194 MediaFormat format = extractor.getTrackFormat(trackID); 1195 if (!mMediaType.equals(format.getString(MediaFormat.KEY_MIME))) continue; 1196 extractor.selectTrack(trackID); 1197 sampleInfoAtZero.set(0, (int) extractor.getSampleSize(), 1198 extractor.getSampleTime(), extractor.getSampleFlags()); 1199 extractor.seekTo(randomSeekPts, MediaExtractor.SEEK_TO_NEXT_SYNC); 1200 extractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 1201 currInfo.set(0, (int) extractor.getSampleSize(), 1202 extractor.getSampleTime(), extractor.getSampleFlags()); 1203 if (!isSampleInfoIdentical(sampleInfoAtZero, currInfo)) { 1204 if (!codecListSupp.contains(mMediaType)) { 1205 if (ENABLE_LOGS) { 1206 Log.d(LOG_TAG, "seen mismatch seekTo(0, SEEK_TO_CLOSEST_SYNC)"); 1207 Log.d(LOG_TAG, " flags exp/got: " + sampleInfoAtZero.flags + '/' + 1208 currInfo.flags); 1209 Log.d(LOG_TAG, " size exp/got: " + sampleInfoAtZero.size + '/' + 1210 currInfo.size); 1211 Log.d(LOG_TAG, 1212 " ts exp/got: " + sampleInfoAtZero.presentationTimeUs + 1213 '/' + currInfo.presentationTimeUs); 1214 } 1215 isOk = false; 1216 break; 1217 } 1218 } 1219 extractor.seekTo(-1L, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 1220 currInfo.set(0, (int) extractor.getSampleSize(), 1221 extractor.getSampleTime(), extractor.getSampleFlags()); 1222 if (!isSampleInfoIdentical(sampleInfoAtZero, currInfo)) { 1223 if (!codecListSupp.contains(mMediaType)) { 1224 if (ENABLE_LOGS) { 1225 Log.d(LOG_TAG, "seen mismatch seekTo(-1, SEEK_TO_CLOSEST_SYNC)"); 1226 Log.d(LOG_TAG, " flags exp/got: " + sampleInfoAtZero.flags + '/' + 1227 currInfo.flags); 1228 Log.d(LOG_TAG, " size exp/got: " + sampleInfoAtZero.size + '/' + 1229 currInfo.size); 1230 Log.d(LOG_TAG, 1231 " ts exp/got: " + sampleInfoAtZero.presentationTimeUs + 1232 '/' + currInfo.presentationTimeUs); 1233 } 1234 isOk = false; 1235 break; 1236 } 1237 } 1238 extractor.unselectTrack(trackID); 1239 } 1240 extractor.release(); 1241 } 1242 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1243 } 1244 1245 @ApiTest(apis = {"android.media.MediaExtractor#getMetrics"}) 1246 @SmallTest 1247 @Test 1248 public void testMetrics() throws IOException { 1249 assumeTrue(shouldRunTest(mMediaType)); 1250 for (String srcFile : mSrcFiles) { 1251 MediaExtractor extractor = new MediaExtractor(); 1252 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1253 extractor.setDataSource(MEDIA_DIR + srcFile); 1254 PersistableBundle bundle = extractor.getMetrics(); 1255 int numTracks = bundle.getInt(MediaExtractor.MetricsConstants.TRACKS); 1256 String format = bundle.getString(MediaExtractor.MetricsConstants.FORMAT); 1257 String mediaType = bundle.getString(MediaExtractor.MetricsConstants.MIME_TYPE); 1258 assertTrue(numTracks == extractor.getTrackCount() && format != null && 1259 mediaType != null); 1260 extractor.release(); 1261 } 1262 } 1263 1264 @CddTest(requirements = {"5.1.3", "5.1.8"}) 1265 @LargeTest 1266 @Test 1267 public void testExtractNative() { 1268 assumeTrue(shouldRunTest(mMediaType)); 1269 if (mSrcFiles.length == 1) return; 1270 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 1271 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_OPUS)); 1272 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 1273 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 1274 boolean isOk = true; 1275 Preconditions.assertTestFileExists(MEDIA_DIR + mSrcFiles[0]); 1276 for (int i = 1; i < mSrcFiles.length; i++) { 1277 Preconditions.assertTestFileExists(MEDIA_DIR + mSrcFiles[i]); 1278 if (!nativeTestExtract(MEDIA_DIR + mSrcFiles[0], MEDIA_DIR + mSrcFiles[i], 1279 mMediaType)) { 1280 Log.d(LOG_TAG, "Files: " + mSrcFiles[0] + ", " + mSrcFiles[i] + 1281 " are different from extractor perpsective"); 1282 if (!codecListSupp.contains(mMediaType)) { 1283 isOk = false; 1284 break; 1285 } 1286 } 1287 } 1288 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1289 } 1290 1291 @ApiTest(apis = {"AMediaExtractor_seekTo", "AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC", 1292 "AMEDIAEXTRACTOR_SEEK_NEXT_SYNC", "AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC"}) 1293 @LargeTest 1294 @Test 1295 @Ignore("TODO(b/146420831)") 1296 public void testSeekNative() throws IOException { 1297 assumeTrue(shouldRunTest(mMediaType) 1298 && !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)); 1299 boolean isOk = true; 1300 for (String srcFile : mSrcFiles) { 1301 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1302 if (!isFileSeekable(srcFile)) continue; 1303 if (!nativeTestSeek(MEDIA_DIR + srcFile, mMediaType)) { 1304 if (!codecListSupp.contains(mMediaType)) { 1305 isOk = false; 1306 break; 1307 } 1308 } 1309 } 1310 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1311 } 1312 1313 @ApiTest(apis = {"AMediaExtractor_seekTo", "AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC", 1314 "AMEDIAEXTRACTOR_SEEK_NEXT_SYNC", "AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC"}) 1315 @LargeTest 1316 @Test 1317 public void testSeekFlakinessNative() throws IOException { 1318 assumeTrue(shouldRunTest(mMediaType)); 1319 boolean isOk = true; 1320 for (String srcFile : mSrcFiles) { 1321 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1322 if (!isFileSeekable(srcFile)) continue; 1323 if (!nativeTestSeekFlakiness(MEDIA_DIR + srcFile, mMediaType)) { 1324 if (!codecListSupp.contains(mMediaType)) { 1325 isOk = false; 1326 break; 1327 } 1328 } 1329 } 1330 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1331 } 1332 1333 @ApiTest(apis = {"AMediaExtractor_seekTo", "AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC", 1334 "AMEDIAEXTRACTOR_SEEK_NEXT_SYNC", "AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC"}) 1335 @SmallTest 1336 @Test 1337 public void testSeekToZeroNative() throws IOException { 1338 assumeTrue(shouldRunTest(mMediaType)); 1339 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 1340 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 1341 assumeTrue("TODO(b/146925481)", !mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 1342 boolean isOk = true; 1343 for (String srcFile : mSrcFiles) { 1344 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1345 if (!isFileSeekable(srcFile)) continue; 1346 if (!nativeTestSeekToZero(MEDIA_DIR + srcFile, mMediaType)) { 1347 if (!codecListSupp.contains(mMediaType)) { 1348 isOk = false; 1349 break; 1350 } 1351 } 1352 } 1353 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1354 } 1355 1356 @ApiTest(apis = "AMediaExtractor_getFileFormat") 1357 @SmallTest 1358 @Test 1359 public void testFileFormatNative() { 1360 assumeTrue(shouldRunTest(mMediaType)); 1361 boolean isOk = true; 1362 for (String srcFile : mSrcFiles) { 1363 Preconditions.assertTestFileExists(MEDIA_DIR + srcFile); 1364 if (!nativeTestFileFormat(MEDIA_DIR + srcFile)) { 1365 isOk = false; 1366 break; 1367 } 1368 } 1369 assertTrue(testName.getMethodName() + " failed for Mediatype: " + mMediaType, isOk); 1370 } 1371 } 1372 1373 /** 1374 * Encloses extractor test for validating extractor output for extractors which directly 1375 * decode instead of extracting. 1376 */ 1377 @RunWith(Parameterized.class) 1378 public static class FusedExtractorDecoderTest { 1379 private final String mMediaType; 1380 private final String mRefFile; 1381 private final String mTestFile; 1382 1383 public FusedExtractorDecoderTest(String mediaType, String refFile, String testFile) { 1384 mMediaType = mediaType; 1385 mRefFile = refFile; 1386 mTestFile = testFile; 1387 } 1388 1389 @Parameterized.Parameters(name = "{index}_{0}") 1390 public static Collection<Object[]> input() { 1391 return Arrays.asList(new Object[][]{ 1392 {MediaFormat.MIMETYPE_AUDIO_FLAC, 1393 "bbb_cif_768kbps_30fps_mpeg4_stereo_48kHz_192kbps_flac.mp4", 1394 "bbb_stereo_48kHz_192kbps_flac.flac"}, 1395 /* TODO(b/163566531) 1396 {MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_1ch_16kHz.mkv", "bbb_1ch_16kHz.wav"},*/ 1397 }); 1398 } 1399 1400 @CddTest(requirements = {"5.1.3"}) 1401 @LargeTest 1402 @Test 1403 public void testExtractDecodeAndValidate() throws IOException, InterruptedException { 1404 MediaExtractor testExtractor = new MediaExtractor(); 1405 testExtractor.setDataSource(MEDIA_DIR + mTestFile); 1406 MediaFormat format = testExtractor.getTrackFormat(0); 1407 String mediaType = format.getString(MediaFormat.KEY_MIME); 1408 if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)) { 1409 ArrayList<String> listOfDecoders = 1410 CodecTestBase.selectCodecs(mMediaType, null, null, false); 1411 assertTrue("no suitable codecs found for Mediatype: " + mMediaType, 1412 !listOfDecoders.isEmpty()); 1413 CodecDecoderTestBase cdtb = 1414 new CodecDecoderTestBase(listOfDecoders.get(0), mMediaType, mRefFile, 1415 "invalid"); 1416 cdtb.decodeToMemory(MEDIA_DIR + mRefFile, listOfDecoders.get(0), 0, 1417 MediaExtractor.SEEK_TO_CLOSEST_SYNC, Integer.MAX_VALUE); 1418 String log = String.format("test file: %s, ref file: %s:: ", mTestFile, mRefFile); 1419 final ByteBuffer refBuffer = cdtb.getOutputManager().getBuffer(); 1420 1421 testExtractor.selectTrack(0); 1422 ByteBuffer testBuffer = ByteBuffer.allocate(refBuffer.limit()); 1423 int bufOffset = 0; 1424 while (true) { 1425 long bytesRead = testExtractor.readSampleData(testBuffer, bufOffset); 1426 if (bytesRead == -1) break; 1427 bufOffset += bytesRead; 1428 testExtractor.advance(); 1429 } 1430 testBuffer.rewind(); 1431 assertEquals(log + "Output mismatch", 0, refBuffer.compareTo(testBuffer)); 1432 assertTrue(log + "Output formats mismatch", 1433 cdtb.isFormatSimilar(cdtb.getOutputFormat(), format)); 1434 } else if (mediaType.equals(mMediaType)) { 1435 MediaExtractor refExtractor = new MediaExtractor(); 1436 refExtractor.setDataSource(MEDIA_DIR + mRefFile); 1437 if (!isMediaSimilar(refExtractor, testExtractor, mMediaType, Integer.MAX_VALUE)) { 1438 fail("Files: " + mRefFile + ", " + mTestFile + 1439 " are different from extractor perspective"); 1440 } 1441 refExtractor.release(); 1442 } else { 1443 fail("unexpected Mediatype: " + mediaType); 1444 } 1445 testExtractor.release(); 1446 } 1447 } 1448 1449 /** 1450 * Test if extractor populates key-value pairs correctly 1451 */ 1452 @RunWith(Parameterized.class) 1453 public static class ValidateKeyValuePairs { 1454 private static final String MEDIA_DIR = WorkDir.getMediaDirString(); 1455 private final String mMediaType; 1456 private final String[] mInpFiles; 1457 private final int mProfile; 1458 private final int mLevel; 1459 private final int mWR; 1460 private final int mHCh; 1461 1462 public ValidateKeyValuePairs(String mediaType, String[] inpFiles, int profile, int level, 1463 int wr, int hCh) { 1464 mMediaType = mediaType; 1465 mInpFiles = inpFiles; 1466 mProfile = profile; 1467 mLevel = level; 1468 mWR = wr; 1469 mHCh = hCh; 1470 } 1471 1472 @Parameterized.Parameters(name = "{index}_{0}") 1473 public static Collection<Object[]> input() { 1474 // mediaType, clips, profile, level, width/sample rate, height/channel count 1475 List<Object[]> exhaustiveArgsList = new ArrayList<>(); 1476 1477 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_MPEG2)) { 1478 // profile and level constraints as per sec 2.3.2 of cdd 1479 /* TODO(b/159582475) 1480 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{ 1481 "bbb_1920x1080_30fps_mpeg2_main_high.mp4", 1482 "bbb_1920x1080_30fps_mpeg2_main_high.mkv"}, 1483 MediaCodecInfo.CodecProfileLevel.MPEG2ProfileMain, 1484 MediaCodecInfo.CodecProfileLevel.MPEG2LevelHL, 1920, 1080});*/ 1485 } 1486 1487 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { 1488 // profile and level constraints as per sec 2.3.2 of cdd 1489 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 1490 "bbb_1920x1080_avc_baseline_l42.mp4", 1491 "bbb_1920x1080_avc_baseline_l42.mkv", 1492 "bbb_1920x1080_avc_baseline_l42.3gp"}, 1493 MediaCodecInfo.CodecProfileLevel.AVCProfileConstrainedBaseline, 1494 MediaCodecInfo.CodecProfileLevel.AVCLevel42, 1920, 1080}); 1495 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 1496 "bbb_1920x1080_avc_main_l42.mp4", 1497 "bbb_1920x1080_avc_main_l42.mkv", 1498 "bbb_1920x1080_avc_main_l42.3gp"}, 1499 MediaCodecInfo.CodecProfileLevel.AVCProfileMain, 1500 MediaCodecInfo.CodecProfileLevel.AVCLevel42, 1920, 1080}); 1501 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 1502 "bbb_1920x1080_avc_high_l42.mp4", 1503 "bbb_1920x1080_avc_high_l42.mkv", 1504 "bbb_1920x1080_avc_high_l42.3gp"}, 1505 MediaCodecInfo.CodecProfileLevel.AVCProfileHigh, 1506 MediaCodecInfo.CodecProfileLevel.AVCLevel42, 1920, 1080}); 1507 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 1508 "video_dovi_1920x1080_60fps_dvav_09.mp4"}, 1509 MediaCodecInfo.CodecProfileLevel.AVCProfileHigh, 1510 MediaCodecInfo.CodecProfileLevel.AVCLevel42, 1920, 1080}); 1511 // profile/level constraints for avc as per sec 5.3.4 of cdd 1512 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 1513 "bbb_1920x1080_avc_baseline_l40.mp4", 1514 "bbb_1920x1080_avc_baseline_l40.mkv", 1515 "bbb_1920x1080_avc_baseline_l40.3gp"}, 1516 MediaCodecInfo.CodecProfileLevel.AVCProfileConstrainedBaseline, 1517 MediaCodecInfo.CodecProfileLevel.AVCLevel4, 1920, 1080}); 1518 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 1519 "bbb_1920x1080_avc_main_l40.mp4", 1520 "bbb_1920x1080_avc_main_l40.mkv", 1521 "bbb_1920x1080_avc_main_l40.3gp"}, 1522 MediaCodecInfo.CodecProfileLevel.AVCProfileMain, 1523 MediaCodecInfo.CodecProfileLevel.AVCLevel4, 1920, 1080}); 1524 } 1525 1526 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 1527 // profile and level constraints as per sec 2.3.2 of cdd 1528 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{ 1529 "bbb_1920x1080_hevc_main_l41.mp4", 1530 "bbb_1920x1080_hevc_main_l41.mkv"}, 1531 MediaCodecInfo.CodecProfileLevel.HEVCProfileMain, 1532 MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel41, 1920, 1080}); 1533 // profile/level constraints for hevc as per sec 5.3.5 of cdd 1534 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{ 1535 "bbb_1920x1080_hevc_main_l40.mp4", 1536 "bbb_1920x1080_hevc_main_l40.mkv"}, 1537 MediaCodecInfo.CodecProfileLevel.HEVCProfileMain, 1538 MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel4, 1920, 1080}); 1539 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{ 1540 "video_dovi_1920x1080_30fps_dvhe_04.mp4"}, 1541 MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10, 1542 MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel4, 1920, 1080}); 1543 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{ 1544 "video_dovi_1920x1080_60fps_dvhe_08.mp4"}, 1545 MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10, 1546 MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel41, 1920, 1080}); 1547 } 1548 1549 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_VP9)) { 1550 // profile and level constraints as per sec 2.3.2 of cdd 1551 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{ 1552 "bbb_1920x1080_vp9_main_l41.webm", 1553 "bbb_1920x1080_vp9_main_l41.mkv"}, 1554 MediaCodecInfo.CodecProfileLevel.VP9Profile0, 1555 MediaCodecInfo.CodecProfileLevel.VP9Level41, 1920, 1080}); 1556 // profile/level constraints for vp9 as per sec 5.3.6 of cdd 1557 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{ 1558 "bbb_1920x1080_vp9_main_l40.webm", 1559 "bbb_1920x1080_vp9_main_l40.mkv"}, 1560 MediaCodecInfo.CodecProfileLevel.VP9Profile0, 1561 MediaCodecInfo.CodecProfileLevel.VP9Level4, 1920, 1080}); 1562 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{ 1563 "color_bands_176x176_vp9_10bit_fr.webm"}, 1564 MediaCodecInfo.CodecProfileLevel.VP9Profile2, 1565 MediaCodecInfo.CodecProfileLevel.VP9Level4, 176, 176}); 1566 } 1567 1568 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_H263)) { 1569 // profile/level constraints for h263 as per sec 5.3.2 of cdd 1570 /* TODO(b/159582475) 1571 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_H263, new String[]{ 1572 "bbb_352x288_384kbps_30fps_h263_baseline_l3.3gp", 1573 "bbb_352x288_384kbps_30fps_h263_baseline_l3.mp4", 1574 "bbb_352x288_384kbps_30fps_h263_baseline_l3.mkv"}, 1575 MediaCodecInfo.CodecProfileLevel.H263ProfileBaseline, 1576 MediaCodecInfo.CodecProfileLevel.H263Level30, 352, 288});*/ 1577 } 1578 1579 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 1580 // profile/level constraints for mpeg4 as per sec 5.3.3 of cdd 1581 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_MPEG4, new String[]{ 1582 "bbb_352x288_384kbps_30fps_mpeg4_simple_l3.mp4", 1583 "bbb_352x288_384kbps_30fps_mpeg4_simple_l3.3gp", 1584 "bbb_352x288_384kbps_30fps_mpeg4_simple_l3.mkv"}, 1585 MediaCodecInfo.CodecProfileLevel.MPEG4ProfileSimple, 1586 MediaCodecInfo.CodecProfileLevel.MPEG4Level3, 352, 288}); 1587 } 1588 1589 if (hasDecoder(MediaFormat.MIMETYPE_AUDIO_AAC)) { 1590 // profile and level constraints for devices that have audio output as per sec 2.2.2, 1591 // sec 2.3.2, sec 2.5.2, sec 5.1.2 of cdd 1592 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{ 1593 "bbb_stereo_44kHz_192kbps_aac_lc.mp4", 1594 "bbb_stereo_44kHz_192kbps_aac_lc.3gp", 1595 "bbb_stereo_44kHz_192kbps_aac_lc.mkv"}, 1596 MediaCodecInfo.CodecProfileLevel.AACObjectLC, 0, 44100, 2}); 1597 /* TODO(b/159582475) 1598 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{ 1599 "bbb_stereo_44kHz_192kbps_aac_he.mp4", 1600 "bbb_stereo_44kHz_192kbps_aac_he.3gp", 1601 "bbb_stereo_44kHz_192kbps_aac_he.mkv"}, 1602 MediaCodecInfo.CodecProfileLevel.AACObjectHE, 0, 44100, 2});*/ 1603 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_AUDIO_AAC, new String[] { 1604 "bbb_stereo_44kHz_192kbps_aac_eld.mp4", 1605 "bbb_stereo_44kHz_192kbps_aac_eld.3gp", 1606 "bbb_stereo_44kHz_192kbps_aac_eld.mkv"}, 1607 MediaCodecInfo.CodecProfileLevel.AACObjectELD, 0, 44100, 2}); 1608 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{ 1609 "bbb_stereo_44kHz_192kbps_aac_ld.mp4", 1610 "bbb_stereo_44kHz_192kbps_aac_ld.3gp", 1611 "bbb_stereo_44kHz_192kbps_aac_ld.mkv"}, 1612 MediaCodecInfo.CodecProfileLevel.AACObjectLD, 0, 44100, 2}); 1613 /*TODO(b/159582475) 1614 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{ 1615 "bbb_stereo_44kHz_192kbps_aac_hev2.mp4", 1616 "bbb_stereo_44kHz_192kbps_aac_hev2.3gp", 1617 "bbb_stereo_44kHz_192kbps_aac_hev2.mkv"}, 1618 MediaCodecInfo.CodecProfileLevel.AACObjectHE_PS, 0, 44100, 2});*/ 1619 } 1620 1621 // Miscellaneous 1622 if (hasDecoder(MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION)) { 1623 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, 1624 new String[]{"video_dovi_1920x1080_30fps_dvhe_04.mp4"}, 1625 MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheDtr, 1626 MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30, 1920, 1080}); 1627 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, 1628 new String[]{"video_dovi_1920x1080_60fps_dvhe_05.mp4"}, 1629 MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn, 1630 MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, 1920, 1080}); 1631 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, 1632 new String[]{"video_dovi_1920x1080_60fps_dvhe_08.mp4"}, 1633 MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt, 1634 MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, 1920, 1080}); 1635 exhaustiveArgsList.add(new Object[]{MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, 1636 new String[]{"video_dovi_1920x1080_60fps_dvav_09.mp4"}, 1637 MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe, 1638 MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, 1920, 1080}); 1639 } 1640 1641 return exhaustiveArgsList; 1642 } 1643 1644 @ApiTest(apis = {"android.media.MediaExtractor#getTrackFormat"}) 1645 @Test 1646 public void validateKeyValuePairs() throws IOException { 1647 for (String file : mInpFiles) { 1648 MediaFormat format = null; 1649 MediaExtractor extractor = new MediaExtractor(); 1650 Preconditions.assertTestFileExists(MEDIA_DIR + file); 1651 extractor.setDataSource(MEDIA_DIR + file); 1652 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 1653 MediaFormat fmt = extractor.getTrackFormat(trackID); 1654 if (mMediaType.equalsIgnoreCase(fmt.getString(MediaFormat.KEY_MIME))) { 1655 format = fmt; 1656 break; 1657 } 1658 } 1659 extractor.release(); 1660 assertTrue("missing track format from file " + file, format != null); 1661 if (mMediaType.equals(MediaFormat.MIMETYPE_AUDIO_AAC)) { 1662 assertTrue("neither KEY_AAC_PROFILE nor KEY_PROFILE found in file " + file, 1663 format.containsKey(MediaFormat.KEY_AAC_PROFILE) || 1664 format.containsKey(MediaFormat.KEY_PROFILE)); 1665 if (format.containsKey(MediaFormat.KEY_AAC_PROFILE)) { 1666 int profile = format.getInteger(MediaFormat.KEY_AAC_PROFILE, -1); 1667 assertEquals("mismatched KEY_AAC_PROFILE in file " + file, 1668 mProfile, profile); 1669 } 1670 if (format.containsKey(MediaFormat.KEY_PROFILE)) { 1671 int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1); 1672 assertEquals("mismatched KEY_PROFILE in file " + file, mProfile, profile); 1673 } 1674 } else if (mMediaType.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) { 1675 int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1); 1676 assertEquals("mismatched KEY_PROFILE in file " + file, mProfile, profile); 1677 int level = format.getInteger(MediaFormat.KEY_LEVEL, -1); 1678 // The level information cannot be parsed from uncompressed frame header, so 1679 // verify the level information only if it is present. 1680 if (level != -1) { 1681 assertEquals("mismatched KEY_LEVEL in file " + file, mLevel, level); 1682 } 1683 } else { 1684 int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1); 1685 assertEquals("mismatched KEY_PROFILE in file " + file, mProfile, profile); 1686 int level = format.getInteger(MediaFormat.KEY_LEVEL, -1); 1687 assertEquals("mismatched KEY_LEVEL in file " + file, mLevel, level); 1688 } 1689 if (mMediaType.startsWith("audio/")) { 1690 int sample_rate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE, -1); 1691 assertEquals("mismatched KEY_SAMPLE_RATE in file " + file, 1692 mWR, sample_rate); 1693 int channel_count = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -1); 1694 assertEquals("mismatched KEY_CHANNEL_COUNT in file " + file, 1695 mHCh, channel_count); 1696 } else if (mMediaType.startsWith("video/")) { 1697 int width = format.getInteger(MediaFormat.KEY_WIDTH, -1); 1698 assertEquals("mismatched KEY_WIDTH in file " + file, mWR, width); 1699 int height = format.getInteger(MediaFormat.KEY_HEIGHT, -1); 1700 assertEquals("mismatched KEY_HEIGHT in file " + file, mHCh, height); 1701 } 1702 } 1703 } 1704 } 1705 1706 /** 1707 * Makes sure if PTS(order) of a file matches the expected values in the corresponding text 1708 * file with just PTS values. 1709 */ 1710 @RunWith(Parameterized.class) 1711 public static class ExtractorTimeStampTest { 1712 private final String mRefFile; 1713 private final String mPTSListFile; 1714 private int mTrackIndex; 1715 // Allowing tolerance of +1/-1 for rounding error. 1716 private static final int PTS_TOLERANCE = 1; 1717 1718 public ExtractorTimeStampTest(String refFile, String textFile, int trackIndex) { 1719 mRefFile = refFile; 1720 mPTSListFile = textFile; 1721 mTrackIndex = trackIndex; 1722 } 1723 1724 @Parameterized.Parameters 1725 public static Collection<Object[]> input() { 1726 final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{ 1727 {"bbb_384x216_768kbps_30fps_avc_2b.mp4", 1728 "pts_bbb_384x216_768kbps_30fps_avc_2b.txt", 0}, 1729 {"bbb_384x216_768kbps_25fps_avc_7b.mp4", 1730 "pts_bbb_384x216_768kbps_25fps_avc_7b.txt", 0}, 1731 {"bbb_384x216_768kbps_24fps_avc_5b.mkv", 1732 "pts_bbb_384x216_768kbps_24fps_avc_5b.txt", 0}, 1733 {"bbb_384x216_768kbps_30fps_avc_badapt.mkv", 1734 "pts_bbb_384x216_768kbps_30fps_avc_badapt.txt", 0}, 1735 {"bbb_384x216_768kbps_30fps_avc_2b.3gp", 1736 "pts_bbb_384x216_768kbps_30fps_avc_2b.txt", 0}, 1737 {"bbb_384x216_768kbps_25fps_avc_7b.3gp", 1738 "pts_bbb_384x216_768kbps_25fps_avc_7b.txt", 0}, 1739 {"bbb_384x216_768kbps_30fps_avc_badapt_bbb_480x360_768kbps_24fps_avc_5b.mkv", 1740 "pts_bbb_384x216_768kbps_30fps_avc_badapt.txt", 0}, 1741 {"bbb_384x216_768kbps_30fps_avc_badapt_bbb_480x360_768kbps_24fps_avc_5b.mkv", 1742 "pts_bbb_480x360_768kbps_24fps_avc_5b.txt", 1}, 1743 {"bbb_384x216_768kbps_30fps_avc_2b_bbb_cif_768kbps_25fps_avc_7b.mp4", 1744 "pts_bbb_384x216_768kbps_30fps_avc_2b.txt", 0}, 1745 {"bbb_384x216_768kbps_30fps_avc_2b_bbb_cif_768kbps_25fps_avc_7b.mp4", 1746 "pts_bbb_cif_768kbps_25fps_avc_7b.txt", 1}, 1747 {"bbb_384x216_768kbps_30fps_hevc_2b.mp4", 1748 "pts_bbb_384x216_768kbps_30fps_hevc_2b.txt", 0}, 1749 {"bbb_384x216_768kbps_25fps_hevc_7b.mp4", 1750 "pts_bbb_384x216_768kbps_25fps_hevc_7b.txt", 0}, 1751 {"bbb_384x216_768kbps_24fps_hevc_5b.mkv", 1752 "pts_bbb_384x216_768kbps_24fps_hevc_5b.txt", 0}, 1753 {"bbb_384x216_768kbps_30fps_hevc_badapt.mkv", 1754 "pts_bbb_384x216_768kbps_30fps_hevc_badapt.txt", 0}, 1755 {"bbb_384x216_768kbps_30fps_hevc_badapt_bbb_480x360_768kbps_24fps_hevc_5b.mkv", 1756 "pts_bbb_384x216_768kbps_30fps_hevc_badapt.txt", 0}, 1757 {"bbb_384x216_768kbps_30fps_hevc_badapt_bbb_480x360_768kbps_24fps_hevc_5b.mkv", 1758 "pts_bbb_480x360_768kbps_24fps_hevc_5b.txt", 1}, 1759 {"bbb_384x216_768kbps_30fps_hevc_2b_bbb_cif_768kbps_25fps_hevc_7b.mp4", 1760 "pts_bbb_384x216_768kbps_30fps_hevc_2b.txt", 0}, 1761 {"bbb_384x216_768kbps_30fps_hevc_2b_bbb_cif_768kbps_25fps_hevc_7b.mp4", 1762 "pts_bbb_cif_768kbps_25fps_hevc_7b.txt", 1}, 1763 {"bbb_384x216_768kbps_30fps_mpeg2_2b.mp4", 1764 "pts_bbb_384x216_768kbps_30fps_mpeg2_2b.txt", 0}, 1765 {"bbb_384x216_768kbps_25fps_mpeg2_5b.mp4", 1766 "pts_bbb_384x216_768kbps_25fps_mpeg2_5b.txt", 0}, 1767 {"bbb_384x216_768kbps_24fps_mpeg2_5b.mkv", 1768 "pts_bbb_384x216_768kbps_24fps_mpeg2_5b.txt", 0}, 1769 {"bbb_384x216_768kbps_30fps_mpeg2_2b.ts", 1770 "pts_bbb_384x216_768kbps_30fps_mpeg2_2b.txt", 0}, 1771 {"bbb_384x216_768kbps_25fps_mpeg2_7b.ts", 1772 "pts_bbb_384x216_768kbps_25fps_mpeg2_7b.txt", 0}, 1773 {"bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm", 1774 "pts_bbb_cif_768kbps_30fps_vp8.txt", 0}, 1775 {"bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.mkv", 1776 "pts_bbb_cif_768kbps_30fps_vp8.txt", 0}, 1777 {"bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm", 1778 "pts_stereo_48kHz_192kbps_vorbis.txt", 1}, 1779 {"bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.mkv", 1780 "pts_stereo_48kHz_192kbps_vorbis.txt", 1}, 1781 {"bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.webm", 1782 "pts_bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.txt", 0}, 1783 {"bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm", 1784 "pts_bbb_cif_768kbps_30fps_vp9.txt", 0}, 1785 {"bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.mkv", 1786 "pts_bbb_cif_768kbps_30fps_vp9.txt", 0}, 1787 {"bbb_cif_768kbps_30fps_av1.mp4", 1788 "pts_bbb_cif_768kbps_30fps_av1.txt", 0}, 1789 {"bbb_cif_768kbps_30fps_av1.mkv", 1790 "pts_bbb_cif_768kbps_30fps_av1.txt", 0}, 1791 {"bbb_cif_768kbps_30fps_av1.webm", 1792 "pts_bbb_cif_768kbps_30fps_av1.txt", 0}, 1793 {"binary_counter_320x240_30fps_600frames.mp4", 1794 "pts_binary_counter_320x240_30fps_600frames.txt", 0}, 1795 }); 1796 return exhaustiveArgsList; 1797 } 1798 1799 @ApiTest(apis = {"android.media.MediaExtractor#getSampleTime"}) 1800 @LargeTest 1801 @Test 1802 public void testPresentationTimeStampsMatch() throws IOException { 1803 try (FileInputStream file = new FileInputStream(MEDIA_DIR + mPTSListFile); 1804 InputStreamReader input = new InputStreamReader(file); 1805 Reader txtRdr = new BufferedReader(input)) { 1806 StreamTokenizer strTok = new StreamTokenizer(txtRdr); 1807 strTok.parseNumbers(); 1808 1809 MediaExtractor extractor = new MediaExtractor(); 1810 Preconditions.assertTestFileExists(MEDIA_DIR + mRefFile); 1811 extractor.setDataSource(MEDIA_DIR + mRefFile); 1812 assertTrue(mTrackIndex < extractor.getTrackCount()); 1813 extractor.selectTrack(mTrackIndex); 1814 while (true) { 1815 if (strTok.nextToken() == StreamTokenizer.TT_EOF) break; 1816 assertTrue("PTS mismatch exp/got: " + (long) strTok.nval + "/" + 1817 extractor.getSampleTime(), 1818 Math.abs(extractor.getSampleTime() - (long) strTok.nval) <= 1819 PTS_TOLERANCE); 1820 if (!extractor.advance()) break; 1821 } 1822 assertEquals(StreamTokenizer.TT_EOF, strTok.nextToken()); 1823 assertTrue(!extractor.advance()); 1824 extractor.release(); 1825 } 1826 } 1827 } 1828 } 1829