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