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 android.content.Context; 20 import android.content.res.AssetFileDescriptor; 21 import android.media.MediaCodec; 22 import android.media.MediaDataSource; 23 import android.media.MediaExtractor; 24 import android.media.MediaFormat; 25 import android.net.Uri; 26 import android.os.ParcelFileDescriptor; 27 import android.os.PersistableBundle; 28 import android.util.Log; 29 30 import androidx.test.filters.LargeTest; 31 import androidx.test.filters.SmallTest; 32 import androidx.test.platform.app.InstrumentationRegistry; 33 34 import org.junit.After; 35 import org.junit.Before; 36 import org.junit.Ignore; 37 import org.junit.Rule; 38 import org.junit.Test; 39 import org.junit.experimental.runners.Enclosed; 40 import org.junit.rules.TestName; 41 import org.junit.runner.RunWith; 42 import org.junit.runners.Parameterized; 43 44 import java.io.File; 45 import java.io.FileInputStream; 46 import java.io.FileOutputStream; 47 import java.io.IOException; 48 import java.nio.ByteBuffer; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.Collection; 52 import java.util.Collections; 53 import java.util.List; 54 import java.util.Random; 55 56 import static org.junit.Assert.assertTrue; 57 import static org.junit.Assert.fail; 58 import static org.junit.Assume.assumeTrue; 59 60 class TestMediaDataSource extends MediaDataSource { 61 private static final String LOG_TAG = TestMediaDataSource.class.getSimpleName(); 62 private static final boolean ENABLE_LOGS = false; 63 private byte[] mData; 64 private boolean mFatalGetSize; 65 private boolean mFatalReadAt; 66 private boolean mIsClosed = false; 67 fromString(String inpPath, boolean failSize, boolean failRead)68 static TestMediaDataSource fromString(String inpPath, boolean failSize, boolean failRead) 69 throws IOException { 70 try (FileInputStream fInp = new FileInputStream(inpPath)) { 71 int size = (int) new File(inpPath).length(); 72 byte[] data = new byte[size]; 73 fInp.read(data, 0, size); 74 return new TestMediaDataSource(data, failSize, failRead); 75 } 76 } 77 TestMediaDataSource(byte[] data, boolean fatalGetSize, boolean fatalReadAt)78 private TestMediaDataSource(byte[] data, boolean fatalGetSize, boolean fatalReadAt) { 79 mData = data; 80 mFatalGetSize = fatalGetSize; 81 mFatalReadAt = fatalReadAt; 82 } 83 84 @Override readAt(long srcOffset, byte[] buffer, int dstOffset, int size)85 public synchronized int readAt(long srcOffset, byte[] buffer, int dstOffset, int size) 86 throws IOException { 87 if (mFatalReadAt) { 88 throw new IOException("malformed media data source"); 89 } 90 if (srcOffset >= mData.length) { 91 return -1; 92 } 93 if (srcOffset + size > mData.length) { 94 size = mData.length - (int) srcOffset; 95 } 96 System.arraycopy(mData, (int) srcOffset, buffer, dstOffset, size); 97 return size; 98 } 99 100 @Override getSize()101 public synchronized long getSize() throws IOException { 102 if (mFatalGetSize) { 103 throw new IOException("malformed media data source"); 104 } 105 if (ENABLE_LOGS) { 106 Log.v(LOG_TAG, "getSize: " + mData.length); 107 } 108 return mData.length; 109 } 110 111 @Override close()112 public synchronized void close() { 113 mIsClosed = true; 114 } 115 isClosed()116 public boolean isClosed() { 117 return mIsClosed; 118 } 119 } 120 121 @RunWith(Enclosed.class) 122 public class ExtractorTest { 123 private static final String LOG_TAG = ExtractorTest.class.getSimpleName(); 124 private static final boolean ENABLE_LOGS = false; 125 private static final int MAX_SAMPLE_SIZE = 4 * 1024 * 1024; 126 private static final String EXT_SEL_KEY = "ext-sel"; 127 static private final List<String> codecListforTypeMp4 = 128 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_MPEG, MediaFormat.MIMETYPE_AUDIO_AAC, 129 MediaFormat.MIMETYPE_AUDIO_FLAC, MediaFormat.MIMETYPE_AUDIO_VORBIS, 130 MediaFormat.MIMETYPE_AUDIO_OPUS, MediaFormat.MIMETYPE_VIDEO_MPEG2, 131 MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263, 132 MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC); 133 static private final List<String> codecListforTypeWebm = 134 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS, 135 MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9); 136 static private final List<String> codecListforType3gp = 137 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_AUDIO_AMR_NB, 138 MediaFormat.MIMETYPE_AUDIO_AMR_WB, MediaFormat.MIMETYPE_VIDEO_MPEG4, 139 MediaFormat.MIMETYPE_VIDEO_H263, MediaFormat.MIMETYPE_VIDEO_AVC); 140 static private final List<String> codecListforTypeMkv = 141 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_MPEG, MediaFormat.MIMETYPE_AUDIO_AAC, 142 MediaFormat.MIMETYPE_AUDIO_FLAC, MediaFormat.MIMETYPE_AUDIO_VORBIS, 143 MediaFormat.MIMETYPE_AUDIO_OPUS, MediaFormat.MIMETYPE_VIDEO_MPEG2, 144 MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263, 145 MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC, 146 MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9); 147 static private final List<String> codecListforTypeOgg = 148 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS); 149 static private final List<String> codecListforTypeTs = 150 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_VIDEO_MPEG2, 151 MediaFormat.MIMETYPE_VIDEO_AVC); 152 static private final List<String> codecListforTypeRaw = 153 Arrays.asList(MediaFormat.MIMETYPE_AUDIO_AAC, MediaFormat.MIMETYPE_AUDIO_FLAC, 154 MediaFormat.MIMETYPE_AUDIO_MPEG, MediaFormat.MIMETYPE_AUDIO_AMR_NB, 155 MediaFormat.MIMETYPE_AUDIO_AMR_WB, MediaFormat.MIMETYPE_AUDIO_RAW); 156 // List of codecs that are not required to be supported as per CDD but are tested 157 static private final List<String> codecListSupp = 158 Arrays.asList(MediaFormat.MIMETYPE_VIDEO_AV1); 159 private static String mInpPrefix = WorkDir.getMediaDirString(); 160 private static String extSel; 161 162 static { 163 android.os.Bundle args = InstrumentationRegistry.getArguments(); 164 final String defSel = "mp4;webm;3gp;mkv;ogg;supp"; 165 extSel = (null == args.getString(EXT_SEL_KEY)) ? defSel : args.getString(EXT_SEL_KEY); 166 } 167 shouldRunTest(String mime)168 static private boolean shouldRunTest(String mime) { 169 boolean result = false; 170 if ((extSel.contains("mp4") && codecListforTypeMp4.contains(mime)) || 171 (extSel.contains("webm") && codecListforTypeWebm.contains(mime)) || 172 (extSel.contains("3gp") && codecListforType3gp.contains(mime)) || 173 (extSel.contains("mkv") && codecListforTypeMkv.contains(mime)) || 174 (extSel.contains("ogg") && codecListforTypeOgg.contains(mime)) || 175 (extSel.contains("supp") && codecListSupp.contains(mime))) 176 result = true; 177 return result; 178 } 179 isExtractorOKonEOS(MediaExtractor extractor)180 private static boolean isExtractorOKonEOS(MediaExtractor extractor) { 181 return extractor.getSampleTrackIndex() < 0 && extractor.getSampleSize() < 0 && 182 extractor.getSampleFlags() < 0 && extractor.getSampleTime() < 0; 183 } 184 isSampleInfoIdentical(MediaCodec.BufferInfo refSample, MediaCodec.BufferInfo testSample)185 private static boolean isSampleInfoIdentical(MediaCodec.BufferInfo refSample, 186 MediaCodec.BufferInfo testSample) { 187 return refSample.flags == testSample.flags && refSample.size == testSample.size && 188 refSample.presentationTimeUs == testSample.presentationTimeUs; 189 } 190 isSampleInfoValidAndIdentical(MediaCodec.BufferInfo refSample, MediaCodec.BufferInfo testSample)191 private static boolean isSampleInfoValidAndIdentical(MediaCodec.BufferInfo refSample, 192 MediaCodec.BufferInfo testSample) { 193 return refSample.flags == testSample.flags && refSample.size == testSample.size && 194 Math.abs(refSample.presentationTimeUs - testSample.presentationTimeUs) <= 1 && 195 refSample.flags >= 0 && refSample.size >= 0 && refSample.presentationTimeUs >= 0; 196 } 197 isCSDIdentical(MediaFormat refFormat, MediaFormat testFormat)198 static boolean isCSDIdentical(MediaFormat refFormat, MediaFormat testFormat) { 199 String mime = refFormat.getString(MediaFormat.KEY_MIME); 200 for (int i = 0; ; i++) { 201 String csdKey = "csd-" + i; 202 boolean refHasCSD = refFormat.containsKey(csdKey); 203 boolean testHasCSD = testFormat.containsKey(csdKey); 204 if (refHasCSD != testHasCSD) { 205 if (ENABLE_LOGS) { 206 Log.w(LOG_TAG, "error, ref fmt has CSD: " + refHasCSD + " test fmt has CSD: " + 207 testHasCSD); 208 } 209 return false; 210 } 211 if (refHasCSD) { 212 Log.v(LOG_TAG, mime + " has " + csdKey); 213 ByteBuffer r = refFormat.getByteBuffer(csdKey); 214 ByteBuffer t = testFormat.getByteBuffer(csdKey); 215 if (!r.equals(t)) { 216 if (ENABLE_LOGS) { 217 Log.w(LOG_TAG, "ref CSD and test CSD buffers are not identical"); 218 } 219 return false; 220 } 221 } else break; 222 } 223 return true; 224 } 225 isFormatSimilar(MediaFormat refFormat, MediaFormat testFormat)226 private static boolean isFormatSimilar(MediaFormat refFormat, MediaFormat testFormat) { 227 String refMime = refFormat.getString(MediaFormat.KEY_MIME); 228 String testMime = testFormat.getString(MediaFormat.KEY_MIME); 229 230 if (!refMime.equals(testMime)) return false; 231 if (!isCSDIdentical(refFormat, testFormat)) return false; 232 if (refMime.startsWith("audio/")) { 233 return refFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) == 234 testFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) && 235 refFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) == 236 testFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); 237 } else if (refMime.startsWith("video/")) { 238 return refFormat.getInteger(MediaFormat.KEY_WIDTH) == 239 testFormat.getInteger(MediaFormat.KEY_WIDTH) && 240 refFormat.getInteger(MediaFormat.KEY_HEIGHT) == 241 testFormat.getInteger(MediaFormat.KEY_HEIGHT); 242 } 243 return true; 244 } 245 isMediaSimilar(MediaExtractor refExtractor, MediaExtractor testExtractor, String mime, int sampleLimit)246 private static boolean isMediaSimilar(MediaExtractor refExtractor, MediaExtractor testExtractor, 247 String mime, int sampleLimit) { 248 ByteBuffer refBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE); 249 ByteBuffer testBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE); 250 251 int noOfTracksMatched = 0; 252 for (int refTrackID = 0; refTrackID < refExtractor.getTrackCount(); refTrackID++) { 253 MediaFormat refFormat = refExtractor.getTrackFormat(refTrackID); 254 String refMime = refFormat.getString(MediaFormat.KEY_MIME); 255 if (mime != null && !refMime.equals(mime)) { 256 continue; 257 } 258 for (int testTrackID = 0; testTrackID < testExtractor.getTrackCount(); testTrackID++) { 259 MediaFormat testFormat = testExtractor.getTrackFormat(testTrackID); 260 if (!isFormatSimilar(refFormat, testFormat)) { 261 continue; 262 } 263 refExtractor.selectTrack(refTrackID); 264 testExtractor.selectTrack(testTrackID); 265 266 MediaCodec.BufferInfo refSampleInfo = new MediaCodec.BufferInfo(); 267 MediaCodec.BufferInfo testSampleInfo = new MediaCodec.BufferInfo(); 268 boolean areTracksIdentical = true; 269 for (int frameCount = 0; ; frameCount++) { 270 refSampleInfo.set(0, (int) refExtractor.getSampleSize(), 271 refExtractor.getSampleTime(), refExtractor.getSampleFlags()); 272 testSampleInfo.set(0, (int) testExtractor.getSampleSize(), 273 testExtractor.getSampleTime(), testExtractor.getSampleFlags()); 274 if (!isSampleInfoValidAndIdentical(refSampleInfo, testSampleInfo)) { 275 if (ENABLE_LOGS) { 276 Log.d(LOG_TAG, 277 " Mime: " + refMime + " mismatch for sample: " + frameCount); 278 Log.d(LOG_TAG, " flags exp/got: " + 279 refSampleInfo.flags + '/' + testSampleInfo.flags); 280 Log.d(LOG_TAG, " size exp/got: " + 281 refSampleInfo.size + '/' + testSampleInfo.size); 282 Log.d(LOG_TAG, " ts exp/got: " + refSampleInfo.presentationTimeUs + 283 '/' + testSampleInfo.presentationTimeUs); 284 } 285 areTracksIdentical = false; 286 break; 287 } 288 int refSz = refExtractor.readSampleData(refBuffer, 0); 289 if (refSz != refSampleInfo.size) { 290 if (ENABLE_LOGS) { 291 Log.d(LOG_TAG, "Mime: " + refMime + " Size exp/got: " + 292 refSampleInfo.size + '/' + refSz); 293 } 294 areTracksIdentical = false; 295 break; 296 } 297 int testSz = testExtractor.readSampleData(testBuffer, 0); 298 if (testSz != testSampleInfo.size) { 299 if (ENABLE_LOGS) { 300 Log.d(LOG_TAG, "Mime: " + refMime + " Size exp/got: " + 301 testSampleInfo.size + '/' + testSz); 302 } 303 areTracksIdentical = false; 304 break; 305 } 306 int trackIndex = refExtractor.getSampleTrackIndex(); 307 if (trackIndex != refTrackID) { 308 if (ENABLE_LOGS) { 309 Log.d(LOG_TAG, "Mime: " + refMime + 310 " TrackID exp/got: " + refTrackID + '/' + trackIndex); 311 } 312 areTracksIdentical = false; 313 break; 314 } 315 trackIndex = testExtractor.getSampleTrackIndex(); 316 if (trackIndex != testTrackID) { 317 if (ENABLE_LOGS) { 318 Log.d(LOG_TAG, "Mime: " + refMime + 319 " TrackID exp/got: " + testTrackID + '/' + trackIndex); 320 } 321 areTracksIdentical = false; 322 break; 323 } 324 if (!testBuffer.equals(refBuffer)) { 325 if (ENABLE_LOGS) { 326 Log.d(LOG_TAG, "Mime: " + refMime + " sample data is not identical"); 327 } 328 areTracksIdentical = false; 329 break; 330 } 331 boolean haveRefSamples = refExtractor.advance(); 332 boolean haveTestSamples = testExtractor.advance(); 333 if (haveRefSamples != haveTestSamples) { 334 if (ENABLE_LOGS) { 335 Log.d(LOG_TAG, "Mime: " + refMime + " Mismatch in sampleCount"); 336 } 337 areTracksIdentical = false; 338 break; 339 } 340 341 if (!haveRefSamples && !isExtractorOKonEOS(refExtractor)) { 342 if (ENABLE_LOGS) { 343 Log.d(LOG_TAG, "Mime: " + refMime + " calls post advance() are not OK"); 344 } 345 areTracksIdentical = false; 346 break; 347 } 348 if (!haveTestSamples && !isExtractorOKonEOS(testExtractor)) { 349 if (ENABLE_LOGS) { 350 Log.d(LOG_TAG, "Mime: " + refMime + " calls post advance() are not OK"); 351 } 352 areTracksIdentical = false; 353 break; 354 } 355 if (ENABLE_LOGS) { 356 Log.v(LOG_TAG, "Mime: " + refMime + " Sample: " + frameCount + 357 " flags: " + refSampleInfo.flags + 358 " size: " + refSampleInfo.size + 359 " ts: " + refSampleInfo.presentationTimeUs); 360 } 361 if (!haveRefSamples || frameCount >= sampleLimit) { 362 break; 363 } 364 } 365 testExtractor.unselectTrack(testTrackID); 366 refExtractor.unselectTrack(refTrackID); 367 if (areTracksIdentical) { 368 noOfTracksMatched++; 369 break; 370 } 371 } 372 if (mime != null && noOfTracksMatched > 0) break; 373 } 374 if (mime == null) { 375 return noOfTracksMatched == refExtractor.getTrackCount(); 376 } else { 377 return noOfTracksMatched > 0; 378 } 379 } 380 381 /** 382 * Tests setDataSource(...) Api by observing the extractor behavior after its successful 383 * instantiation using a media stream. 384 */ 385 @SmallTest 386 public static class SetDataSourceTest { 387 @Rule 388 public TestName testName = new TestName(); 389 390 private static final String mInpMedia = "ForBiggerEscapes.mp4"; 391 private static final String mInpMediaUrl = 392 "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"; 393 394 private MediaExtractor mRefExtractor; 395 396 static { 397 System.loadLibrary("ctsmediav2extractor_jni"); 398 } 399 400 @Before setUp()401 public void setUp() throws IOException { 402 mRefExtractor = new MediaExtractor(); 403 mRefExtractor.setDataSource(mInpPrefix + mInpMedia); 404 } 405 406 @After tearDown()407 public void tearDown() { 408 mRefExtractor.release(); 409 mRefExtractor = null; 410 } 411 areMetricsIdentical(MediaExtractor refExtractor, MediaExtractor testExtractor)412 private static boolean areMetricsIdentical(MediaExtractor refExtractor, 413 MediaExtractor testExtractor) { 414 PersistableBundle bundle = refExtractor.getMetrics(); 415 int refNumTracks = bundle.getInt(MediaExtractor.MetricsConstants.TRACKS); 416 String refFormat = bundle.getString(MediaExtractor.MetricsConstants.FORMAT); 417 String refMime = bundle.getString(MediaExtractor.MetricsConstants.MIME_TYPE); 418 bundle = testExtractor.getMetrics(); 419 int testNumTracks = bundle.getInt(MediaExtractor.MetricsConstants.TRACKS); 420 String testFormat = bundle.getString(MediaExtractor.MetricsConstants.FORMAT); 421 String testMime = bundle.getString(MediaExtractor.MetricsConstants.MIME_TYPE); 422 boolean result = testNumTracks == refNumTracks && testFormat.equals(refFormat) && 423 testMime.equals(refMime); 424 if (ENABLE_LOGS) { 425 Log.d(LOG_TAG, " NumTracks exp/got: " + refNumTracks + '/' + testNumTracks); 426 Log.d(LOG_TAG, " Format exp/got: " + refFormat + '/' + testFormat); 427 Log.d(LOG_TAG, " Mime exp/got: " + refMime + '/' + testMime); 428 } 429 return result; 430 } 431 isSeekOk(MediaExtractor refExtractor, MediaExtractor testExtractor)432 private static boolean isSeekOk(MediaExtractor refExtractor, MediaExtractor testExtractor) { 433 final long maxEstDuration = 14000000; 434 final int MAX_SEEK_POINTS = 7; 435 final long mSeed = 0x12b9b0a1; 436 final Random randNum = new Random(mSeed); 437 MediaCodec.BufferInfo refSampleInfo = new MediaCodec.BufferInfo(); 438 MediaCodec.BufferInfo testSampleInfo = new MediaCodec.BufferInfo(); 439 boolean result = true; 440 for (int trackID = 0; trackID < refExtractor.getTrackCount() && result; trackID++) { 441 refExtractor.selectTrack(trackID); 442 testExtractor.selectTrack(trackID); 443 for (int i = 0; i < MAX_SEEK_POINTS && result; i++) { 444 long pts = (long) (randNum.nextDouble() * maxEstDuration); 445 for (int mode = MediaExtractor.SEEK_TO_PREVIOUS_SYNC; 446 mode <= MediaExtractor.SEEK_TO_CLOSEST_SYNC; mode++) { 447 refExtractor.seekTo(pts, mode); 448 testExtractor.seekTo(pts, mode); 449 refSampleInfo.set(0, (int) refExtractor.getSampleSize(), 450 refExtractor.getSampleTime(), refExtractor.getSampleFlags()); 451 testSampleInfo.set(0, (int) testExtractor.getSampleSize(), 452 testExtractor.getSampleTime(), testExtractor.getSampleFlags()); 453 result = isSampleInfoIdentical(refSampleInfo, testSampleInfo); 454 int refTrackIdx = refExtractor.getSampleTrackIndex(); 455 int testTrackIdx = testExtractor.getSampleTrackIndex(); 456 result &= (refTrackIdx == testTrackIdx); 457 if (ENABLE_LOGS) { 458 Log.d(LOG_TAG, " mode/pts/trackId:" + mode + "/" + pts + "/" + trackID); 459 Log.d(LOG_TAG, " trackId exp/got: " + refTrackIdx + '/' + testTrackIdx); 460 Log.d(LOG_TAG, " flags exp/got: " + 461 refSampleInfo.flags + '/' + testSampleInfo.flags); 462 Log.d(LOG_TAG, " size exp/got: " + 463 refSampleInfo.size + '/' + testSampleInfo.size); 464 Log.d(LOG_TAG, " ts exp/got: " + refSampleInfo.presentationTimeUs + 465 '/' + testSampleInfo.presentationTimeUs); 466 } 467 } 468 } 469 refExtractor.unselectTrack(trackID); 470 testExtractor.unselectTrack(trackID); 471 } 472 return result; 473 } 474 475 @Test testAssetFD()476 public void testAssetFD() throws IOException { 477 File inpFile = new File(mInpPrefix + mInpMedia); 478 MediaExtractor testExtractor = new MediaExtractor(); 479 try (ParcelFileDescriptor parcelFD = ParcelFileDescriptor 480 .open(inpFile, ParcelFileDescriptor.MODE_READ_ONLY); 481 AssetFileDescriptor afd = new AssetFileDescriptor(parcelFD, 0, 482 AssetFileDescriptor.UNKNOWN_LENGTH)) { 483 testExtractor.setDataSource(afd); 484 } 485 assertTrue(testExtractor.getCachedDuration() < 0); 486 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 487 !areMetricsIdentical(mRefExtractor, testExtractor) || 488 !isSeekOk(mRefExtractor, testExtractor)) { 489 fail("setDataSource failed: " + testName.getMethodName()); 490 } 491 testExtractor.release(); 492 } 493 494 @Test 495 public void testFileDescriptor() throws IOException { 496 File inpFile = new File(mInpPrefix + mInpMedia); 497 MediaExtractor testExtractor = new MediaExtractor(); 498 try (FileInputStream fInp = new FileInputStream(inpFile)) { 499 testExtractor.setDataSource(fInp.getFD()); 500 } 501 assertTrue(testExtractor.getCachedDuration() < 0); 502 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 503 !areMetricsIdentical(mRefExtractor, testExtractor) || 504 !isSeekOk(mRefExtractor, testExtractor)) { 505 fail("setDataSource failed: " + testName.getMethodName()); 506 } 507 testExtractor.release(); 508 } 509 510 @Test 511 public void testFileDescriptorLenOffset() throws IOException { 512 File inpFile = new File(mInpPrefix + mInpMedia); 513 File outFile = File.createTempFile("temp", ".out"); 514 byte[] garbageAppend = "PrefixGarbage".getBytes(); 515 try (FileInputStream fInp = new FileInputStream(inpFile); 516 FileOutputStream fOut = new FileOutputStream(outFile)) { 517 fOut.write(garbageAppend); 518 byte[] data = new byte[(int) new File(inpFile.toString()).length()]; 519 if (fInp.read(data) == -1) { 520 fail("Failed to read input file"); 521 } 522 fOut.write(data); 523 fOut.write(garbageAppend); 524 } 525 MediaExtractor testExtractor = new MediaExtractor(); 526 try (FileInputStream fInp = new FileInputStream(outFile)) { 527 testExtractor.setDataSource(fInp.getFD(), garbageAppend.length, 528 inpFile.length()); 529 } 530 assertTrue(testExtractor.getCachedDuration() < 0); 531 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 532 !areMetricsIdentical(mRefExtractor, testExtractor) || 533 !isSeekOk(mRefExtractor, testExtractor)) { 534 fail("setDataSource failed: " + testName.getMethodName()); 535 } 536 testExtractor.release(); 537 outFile.delete(); 538 } 539 540 @Test 541 public void testMediaDataSource() throws Exception { 542 TestMediaDataSource dataSource = 543 TestMediaDataSource.fromString(mInpPrefix + mInpMedia, false, false); 544 MediaExtractor testExtractor = new MediaExtractor(); 545 testExtractor.setDataSource(dataSource); 546 assertTrue(testExtractor.getCachedDuration() < 0); 547 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 548 !areMetricsIdentical(mRefExtractor, testExtractor) || 549 !isSeekOk(mRefExtractor, testExtractor)) { 550 fail("setDataSource failed: " + testName.getMethodName()); 551 } 552 testExtractor.release(); 553 assertTrue(dataSource.isClosed()); 554 } 555 556 @Test 557 public void testContextUri() throws IOException { 558 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 559 String path = "android.resource://android.mediav2.cts/" + R.raw.forbiggerescapes; 560 MediaExtractor testExtractor = new MediaExtractor(); 561 testExtractor.setDataSource(context, Uri.parse(path), null); 562 assertTrue(testExtractor.getCachedDuration() < 0); 563 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 564 !areMetricsIdentical(mRefExtractor, testExtractor) || 565 !isSeekOk(mRefExtractor, testExtractor)) { 566 fail("setDataSource failed: " + testName.getMethodName()); 567 } 568 testExtractor.release(); 569 } 570 571 @Test 572 public void testUrlDataSource() throws Exception { 573 MediaExtractor testExtractor = new MediaExtractor(); 574 testExtractor.setDataSource(mInpMediaUrl, null); 575 if (!isMediaSimilar(mRefExtractor, testExtractor, null, Integer.MAX_VALUE) || 576 !areMetricsIdentical(mRefExtractor, testExtractor) || 577 !isSeekOk(mRefExtractor, testExtractor)) { 578 fail("setDataSource failed: " + testName.getMethodName()); 579 } 580 testExtractor.selectTrack(0); 581 for (int idx = 0; ; idx++) { 582 if ((idx & (idx - 1)) == 0) { 583 long cachedDuration = testExtractor.getCachedDuration(); 584 if (ENABLE_LOGS) { 585 Log.v(LOG_TAG, "cachedDuration at frame: " + idx + " is:" + cachedDuration); 586 } 587 assertTrue("cached duration should be non-negative", cachedDuration >= 0); 588 } 589 if (!testExtractor.advance()) break; 590 } 591 assertTrue(testExtractor.hasCacheReachedEndOfStream()); 592 testExtractor.unselectTrack(0); 593 testExtractor.release(); 594 } 595 596 private native boolean nativeTestDataSource(String srcPath, String srcUrl); 597 598 @Test 599 public void testDataSourceNative() { 600 assertTrue(testName.getMethodName() + " failed ", 601 nativeTestDataSource(mInpPrefix + mInpMedia, mInpMediaUrl)); 602 } 603 } 604 605 /** 606 * Encloses extractor functionality tests 607 */ 608 @RunWith(Parameterized.class) 609 public static class FunctionalityTest { 610 private static final int MAX_SEEK_POINTS = 7; 611 private static final long mSeed = 0x12b9b0a1; 612 private final Random mRandNum = new Random(mSeed); 613 private String[] mSrcFiles; 614 private String mMime; 615 616 static { 617 System.loadLibrary("ctsmediav2extractor_jni"); 618 } 619 620 @Rule 621 public TestName testName = new TestName(); 622 623 @Parameterized.Parameters(name = "{index}({0})") 624 public static Collection<Object[]> input() { 625 /* TODO(b/157108639) - add missing test files */ 626 return Arrays.asList(new Object[][]{ 627 {MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{ 628 "bbb_cif_768kbps_30fps_mpeg2_stereo_48kHz_192kbps_mp3.mp4", 629 "bbb_cif_768kbps_30fps_mpeg2.mkv",}}, 630 {MediaFormat.MIMETYPE_VIDEO_H263, new String[]{ 631 "bbb_cif_768kbps_30fps_h263.mp4", 632 "bbb_cif_768kbps_30fps_h263_mono_8kHz_12kbps_amrnb.3gp",}}, 633 {MediaFormat.MIMETYPE_VIDEO_MPEG4, new String[]{ 634 "bbb_cif_768kbps_30fps_mpeg4_stereo_48kHz_192kbps_flac.mp4", 635 "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp",}}, 636 {MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{ 637 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_vorbis.mp4", 638 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.mkv", 639 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.3gp",}}, 640 {MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{ 641 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_opus.mp4", 642 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_mp3.mkv",}}, 643 {MediaFormat.MIMETYPE_VIDEO_VP8, new String[]{ 644 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm", 645 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.mkv"}}, 646 {MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{ 647 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm", 648 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.mkv",}}, 649 {MediaFormat.MIMETYPE_VIDEO_AV1, new String[]{ 650 "bbb_cif_768kbps_30fps_av1.mp4", 651 "bbb_cif_768kbps_30fps_av1.webm", 652 "bbb_cif_768kbps_30fps_av1.mkv",}}, 653 {MediaFormat.MIMETYPE_AUDIO_VORBIS, new String[]{ 654 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_vorbis.mp4", 655 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.mkv", 656 "bbb_cif_768kbps_30fps_vp8_stereo_48kHz_192kbps_vorbis.webm", 657 "bbb_stereo_48kHz_192kbps_vorbis.ogg",}}, 658 {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{ 659 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.webm", 660 "bbb_cif_768kbps_30fps_vp9_stereo_48kHz_192kbps_opus.mkv", 661 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_opus.mp4", 662 "bbb_stereo_48kHz_192kbps_opus.ogg",}}, 663 {MediaFormat.MIMETYPE_AUDIO_MPEG, new String[]{ 664 "bbb_stereo_48kHz_192kbps_mp3.mp3", 665 "bbb_cif_768kbps_30fps_mpeg2_stereo_48kHz_192kbps_mp3.mp4", 666 "bbb_cif_768kbps_30fps_hevc_stereo_48kHz_192kbps_mp3.mkv",}}, 667 {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{ 668 "bbb_stereo_48kHz_192kbps_aac.mp4", 669 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.3gp", 670 "bbb_cif_768kbps_30fps_avc_stereo_48kHz_192kbps_aac.mkv",}}, 671 {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{ 672 "bbb_cif_768kbps_30fps_h263_mono_8kHz_12kbps_amrnb.3gp", 673 "bbb_mono_8kHz_12kbps_amrnb.amr",}}, 674 {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{ 675 "bbb_cif_768kbps_30fps_mpeg4_mono_16kHz_20kbps_amrwb.3gp", 676 "bbb_mono_16kHz_20kbps_amrwb.amr"}}, 677 {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{ 678 "bbb_cif_768kbps_30fps_mpeg4_stereo_48kHz_192kbps_flac.mp4", 679 "bbb_cif_768kbps_30fps_h263_stereo_48kHz_192kbps_flac.mkv",}}, 680 }); 681 } 682 683 private native boolean nativeTestExtract(String srcPath, String refPath, String mime); 684 685 private native boolean nativeTestSeek(String srcPath, String mime); 686 687 private native boolean nativeTestSeekFlakiness(String srcPath, String mime); 688 689 private native boolean nativeTestSeekToZero(String srcPath, String mime); 690 691 private native boolean nativeTestFileFormat(String srcPath); 692 693 public FunctionalityTest(String mime, String[] srcFiles) { 694 mMime = mime; 695 mSrcFiles = srcFiles; 696 } 697 698 // content necessary for testing seek are grouped in this class 699 private class SeekTestParams { 700 MediaCodec.BufferInfo mExpected; 701 long mTimeStamp; 702 int mMode; 703 704 SeekTestParams(MediaCodec.BufferInfo expected, long timeStamp, int mode) { 705 mExpected = expected; 706 mTimeStamp = timeStamp; 707 mMode = mode; 708 } 709 } 710 711 private ArrayList<MediaCodec.BufferInfo> getSeekablePoints(String srcFile, String mime) 712 throws IOException { 713 ArrayList<MediaCodec.BufferInfo> bookmarks = null; 714 if (mime == null) return null; 715 MediaExtractor extractor = new MediaExtractor(); 716 extractor.setDataSource(mInpPrefix + srcFile); 717 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 718 MediaFormat format = extractor.getTrackFormat(trackID); 719 if (!mime.equals(format.getString(MediaFormat.KEY_MIME))) continue; 720 extractor.selectTrack(trackID); 721 bookmarks = new ArrayList<>(); 722 do { 723 int sampleFlags = extractor.getSampleFlags(); 724 if ((sampleFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { 725 MediaCodec.BufferInfo sampleInfo = new MediaCodec.BufferInfo(); 726 sampleInfo.set(0, (int) extractor.getSampleSize(), 727 extractor.getSampleTime(), extractor.getSampleFlags()); 728 bookmarks.add(sampleInfo); 729 } 730 } while (extractor.advance()); 731 extractor.unselectTrack(trackID); 732 break; 733 } 734 extractor.release(); 735 return bookmarks; 736 } 737 738 private ArrayList<SeekTestParams> generateSeekTestArgs(String srcFile, String mime, 739 boolean isRandom) throws IOException { 740 ArrayList<SeekTestParams> testArgs = new ArrayList<>(); 741 if (mime == null) return null; 742 if (isRandom) { 743 MediaExtractor extractor = new MediaExtractor(); 744 extractor.setDataSource(mInpPrefix + srcFile); 745 final long maxEstDuration = 4000000; 746 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 747 MediaFormat format = extractor.getTrackFormat(trackID); 748 if (!mime.equals(format.getString(MediaFormat.KEY_MIME))) continue; 749 extractor.selectTrack(trackID); 750 for (int i = 0; i < MAX_SEEK_POINTS; i++) { 751 long pts = (long) (mRandNum.nextDouble() * maxEstDuration); 752 for (int mode = MediaExtractor.SEEK_TO_PREVIOUS_SYNC; 753 mode <= MediaExtractor.SEEK_TO_CLOSEST_SYNC; mode++) { 754 MediaCodec.BufferInfo currInfo = new MediaCodec.BufferInfo(); 755 extractor.seekTo(pts, mode); 756 currInfo.set(0, (int) extractor.getSampleSize(), 757 extractor.getSampleTime(), extractor.getSampleFlags()); 758 testArgs.add(new SeekTestParams(currInfo, pts, mode)); 759 } 760 } 761 extractor.unselectTrack(trackID); 762 break; 763 } 764 extractor.release(); 765 } else { 766 ArrayList<MediaCodec.BufferInfo> bookmarks = getSeekablePoints(srcFile, mime); 767 if (bookmarks == null) return null; 768 int size = bookmarks.size(); 769 int[] indices; 770 if (size > MAX_SEEK_POINTS) { 771 indices = new int[MAX_SEEK_POINTS]; 772 indices[0] = 0; 773 indices[MAX_SEEK_POINTS - 1] = size - 1; 774 for (int i = 1; i < MAX_SEEK_POINTS - 1; i++) { 775 indices[i] = (int) (mRandNum.nextDouble() * (MAX_SEEK_POINTS - 1) + 1); 776 } 777 } else { 778 indices = new int[size]; 779 for (int i = 0; i < size; i++) indices[i] = i; 780 } 781 // closest sync : Seek to the sync sample CLOSEST to the specified time 782 // previous sync : Seek to a sync sample AT or AFTER the specified time 783 // next sync : Seek to a sync sample AT or BEFORE the specified time 784 for (int i : indices) { 785 MediaCodec.BufferInfo currInfo = bookmarks.get(i); 786 long pts = currInfo.presentationTimeUs; 787 testArgs.add( 788 new SeekTestParams(currInfo, pts, MediaExtractor.SEEK_TO_CLOSEST_SYNC)); 789 testArgs.add( 790 new SeekTestParams(currInfo, pts, MediaExtractor.SEEK_TO_NEXT_SYNC)); 791 testArgs.add( 792 new SeekTestParams(currInfo, pts, 793 MediaExtractor.SEEK_TO_PREVIOUS_SYNC)); 794 if (i > 0) { 795 MediaCodec.BufferInfo prevInfo = bookmarks.get(i - 1); 796 long ptsMinus = prevInfo.presentationTimeUs; 797 ptsMinus = pts - ((pts - ptsMinus) >> 3); 798 testArgs.add(new SeekTestParams(currInfo, ptsMinus, 799 MediaExtractor.SEEK_TO_CLOSEST_SYNC)); 800 testArgs.add(new SeekTestParams(currInfo, ptsMinus, 801 MediaExtractor.SEEK_TO_NEXT_SYNC)); 802 testArgs.add(new SeekTestParams(prevInfo, ptsMinus, 803 MediaExtractor.SEEK_TO_PREVIOUS_SYNC)); 804 } 805 if (i < size - 1) { 806 MediaCodec.BufferInfo nextInfo = bookmarks.get(i + 1); 807 long ptsPlus = nextInfo.presentationTimeUs; 808 ptsPlus = pts + ((ptsPlus - pts) >> 3); 809 testArgs.add(new SeekTestParams(currInfo, ptsPlus, 810 MediaExtractor.SEEK_TO_CLOSEST_SYNC)); 811 testArgs.add(new SeekTestParams(nextInfo, ptsPlus, 812 MediaExtractor.SEEK_TO_NEXT_SYNC)); 813 testArgs.add(new SeekTestParams(currInfo, ptsPlus, 814 MediaExtractor.SEEK_TO_PREVIOUS_SYNC)); 815 } 816 } 817 } 818 return testArgs; 819 } 820 821 int checkSeekPoints(String srcFile, String mime, 822 ArrayList<SeekTestParams> seekTestArgs) throws IOException { 823 int errCnt = 0; 824 MediaExtractor extractor = new MediaExtractor(); 825 extractor.setDataSource(mInpPrefix + srcFile); 826 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 827 MediaFormat format = extractor.getTrackFormat(trackID); 828 if (!format.getString(MediaFormat.KEY_MIME).equals(mime)) continue; 829 extractor.selectTrack(trackID); 830 MediaCodec.BufferInfo received = new MediaCodec.BufferInfo(); 831 for (SeekTestParams arg : seekTestArgs) { 832 extractor.seekTo(arg.mTimeStamp, arg.mMode); 833 received.set(0, (int) extractor.getSampleSize(), extractor.getSampleTime(), 834 extractor.getSampleFlags()); 835 if (!isSampleInfoIdentical(arg.mExpected, received)) { 836 errCnt++; 837 if (ENABLE_LOGS) { 838 Log.d(LOG_TAG, " flags exp/got: " + arg.mExpected.flags + '/' + 839 received.flags); 840 Log.d(LOG_TAG, 841 " size exp/got: " + arg.mExpected.size + '/' + received.size); 842 Log.d(LOG_TAG, 843 " ts exp/got: " + arg.mExpected.presentationTimeUs + '/' + 844 received.presentationTimeUs); 845 } 846 } 847 } 848 extractor.unselectTrack(trackID); 849 break; 850 } 851 extractor.release(); 852 return errCnt; 853 } 854 855 /** 856 * Audio, Video codecs support a variety of file-types/container formats. For example, 857 * Vorbis supports OGG, MP4, WEBM and MKV. H.263 supports 3GPP, WEBM and MKV. For every 858 * mime, a list of test vectors are provided one for each container) but underlying 859 * elementary stream is the same for all. The streams of a mime are extracted and 860 * compared with each other for similarity. 861 */ 862 @LargeTest 863 @Test 864 public void testExtract() throws IOException { 865 assumeTrue(shouldRunTest(mMime)); 866 assertTrue(mSrcFiles.length > 1); 867 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 868 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_OPUS)); 869 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 870 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 871 MediaExtractor refExtractor = new MediaExtractor(); 872 refExtractor.setDataSource(mInpPrefix + mSrcFiles[0]); 873 boolean isOk = true; 874 for (int i = 1; i < mSrcFiles.length && isOk; i++) { 875 MediaExtractor testExtractor = new MediaExtractor(); 876 testExtractor.setDataSource(mInpPrefix + mSrcFiles[i]); 877 if (!isMediaSimilar(refExtractor, testExtractor, mMime, Integer.MAX_VALUE)) { 878 if (ENABLE_LOGS) { 879 Log.d(LOG_TAG, "Files: " + mSrcFiles[0] + ", " + mSrcFiles[i] + 880 " are different from extractor perspective"); 881 } 882 if (!codecListSupp.contains(mMime)) { 883 isOk = false; 884 } 885 } 886 testExtractor.release(); 887 } 888 refExtractor.release(); 889 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 890 } 891 892 /** 893 * Tests seek functionality, verifies if we seek to most accurate point for a given 894 * choice of timestamp and mode. 895 */ 896 @LargeTest 897 @Test 898 @Ignore("TODO(b/146420831)") 899 public void testSeek() throws IOException { 900 assumeTrue(shouldRunTest(mMime)); 901 boolean isOk = true; 902 for (String srcFile : mSrcFiles) { 903 ArrayList<SeekTestParams> seekTestArgs = 904 generateSeekTestArgs(srcFile, mMime, false); 905 assertTrue("Mime is null.", seekTestArgs != null); 906 assertTrue("No sync samples found.", !seekTestArgs.isEmpty()); 907 Collections.shuffle(seekTestArgs, mRandNum); 908 int seekAccErrCnt = checkSeekPoints(srcFile, mMime, seekTestArgs); 909 if (seekAccErrCnt != 0) { 910 if (ENABLE_LOGS) { 911 Log.d(LOG_TAG, "For " + srcFile + " seek chose inaccurate Sync point in: " + 912 seekAccErrCnt + "/" + seekTestArgs.size()); 913 } 914 if (!codecListSupp.contains(mMime)) { 915 isOk = false; 916 break; 917 } 918 } 919 } 920 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 921 } 922 923 /** 924 * Tests if we get the same content each time after a call to seekto; 925 */ 926 @LargeTest 927 @Test 928 public void testSeekFlakiness() throws IOException { 929 assumeTrue(shouldRunTest(mMime)); 930 boolean isOk = true; 931 for (String srcFile : mSrcFiles) { 932 ArrayList<SeekTestParams> seekTestArgs = generateSeekTestArgs(srcFile, mMime, true); 933 assertTrue("Mime is null.", seekTestArgs != null); 934 assertTrue("No samples found.", !seekTestArgs.isEmpty()); 935 Collections.shuffle(seekTestArgs, mRandNum); 936 int flakyErrCnt = checkSeekPoints(srcFile, mMime, seekTestArgs); 937 if (flakyErrCnt != 0) { 938 if (ENABLE_LOGS) { 939 Log.d(LOG_TAG, 940 "No. of Samples where seek showed flakiness is: " + flakyErrCnt); 941 } 942 if (!codecListSupp.contains(mMime)) { 943 isOk = false; 944 break; 945 } 946 } 947 } 948 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 949 } 950 951 /** 952 * Test if seekTo(0) yields the same content as if we had just opened the file and started 953 * reading. 954 */ 955 @SmallTest 956 @Test 957 public void testSeekToZero() throws IOException { 958 assumeTrue(shouldRunTest(mMime)); 959 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 960 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 961 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 962 boolean isOk = true; 963 for (String srcFile : mSrcFiles) { 964 MediaExtractor extractor = new MediaExtractor(); 965 extractor.setDataSource(mInpPrefix + srcFile); 966 MediaCodec.BufferInfo sampleInfoAtZero = new MediaCodec.BufferInfo(); 967 MediaCodec.BufferInfo currInfo = new MediaCodec.BufferInfo(); 968 final long randomSeekPts = 1 << 20; 969 for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) { 970 MediaFormat format = extractor.getTrackFormat(trackID); 971 if (!mMime.equals(format.getString(MediaFormat.KEY_MIME))) continue; 972 extractor.selectTrack(trackID); 973 sampleInfoAtZero.set(0, (int) extractor.getSampleSize(), 974 extractor.getSampleTime(), extractor.getSampleFlags()); 975 extractor.seekTo(randomSeekPts, MediaExtractor.SEEK_TO_NEXT_SYNC); 976 extractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 977 currInfo.set(0, (int) extractor.getSampleSize(), 978 extractor.getSampleTime(), extractor.getSampleFlags()); 979 if (!isSampleInfoIdentical(sampleInfoAtZero, currInfo)) { 980 if (!codecListSupp.contains(mMime)) { 981 if (ENABLE_LOGS) { 982 Log.d(LOG_TAG, "seen mismatch seekTo(0, SEEK_TO_CLOSEST_SYNC)"); 983 Log.d(LOG_TAG, " flags exp/got: " + sampleInfoAtZero.flags + '/' + 984 currInfo.flags); 985 Log.d(LOG_TAG, " size exp/got: " + sampleInfoAtZero.size + '/' + 986 currInfo.size); 987 Log.d(LOG_TAG, 988 " ts exp/got: " + sampleInfoAtZero.presentationTimeUs + 989 '/' + currInfo.presentationTimeUs); 990 } 991 isOk = false; 992 break; 993 } 994 } 995 extractor.seekTo(-1L, MediaExtractor.SEEK_TO_CLOSEST_SYNC); 996 currInfo.set(0, (int) extractor.getSampleSize(), 997 extractor.getSampleTime(), extractor.getSampleFlags()); 998 if (!isSampleInfoIdentical(sampleInfoAtZero, currInfo)) { 999 if (!codecListSupp.contains(mMime)) { 1000 if (ENABLE_LOGS) { 1001 Log.d(LOG_TAG, "seen mismatch seekTo(-1, SEEK_TO_CLOSEST_SYNC)"); 1002 Log.d(LOG_TAG, " flags exp/got: " + sampleInfoAtZero.flags + '/' + 1003 currInfo.flags); 1004 Log.d(LOG_TAG, " size exp/got: " + sampleInfoAtZero.size + '/' + 1005 currInfo.size); 1006 Log.d(LOG_TAG, 1007 " ts exp/got: " + sampleInfoAtZero.presentationTimeUs + 1008 '/' + currInfo.presentationTimeUs); 1009 } 1010 isOk = false; 1011 break; 1012 } 1013 } 1014 extractor.unselectTrack(trackID); 1015 } 1016 extractor.release(); 1017 } 1018 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 1019 } 1020 1021 @SmallTest 1022 @Test 1023 public void testMetrics() throws IOException { 1024 assumeTrue(shouldRunTest(mMime)); 1025 for (String srcFile : mSrcFiles) { 1026 MediaExtractor extractor = new MediaExtractor(); 1027 extractor.setDataSource(mInpPrefix + srcFile); 1028 PersistableBundle bundle = extractor.getMetrics(); 1029 int numTracks = bundle.getInt(MediaExtractor.MetricsConstants.TRACKS); 1030 String format = bundle.getString(MediaExtractor.MetricsConstants.FORMAT); 1031 String mime = bundle.getString(MediaExtractor.MetricsConstants.MIME_TYPE); 1032 assertTrue(numTracks == extractor.getTrackCount() && format != null && 1033 mime != null); 1034 extractor.release(); 1035 } 1036 } 1037 1038 @LargeTest 1039 @Test 1040 public void testExtractNative() { 1041 assumeTrue(shouldRunTest(mMime)); 1042 assertTrue(mSrcFiles.length > 1); 1043 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 1044 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_OPUS)); 1045 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 1046 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 1047 boolean isOk = true; 1048 for (int i = 1; i < mSrcFiles.length; i++) { 1049 if (!nativeTestExtract(mInpPrefix + mSrcFiles[0], mInpPrefix + mSrcFiles[i], 1050 mMime)) { 1051 Log.d(LOG_TAG, "Files: " + mSrcFiles[0] + ", " + mSrcFiles[i] + 1052 " are different from extractor perpsective"); 1053 if (!codecListSupp.contains(mMime)) { 1054 isOk = false; 1055 break; 1056 } 1057 } 1058 } 1059 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 1060 } 1061 1062 @LargeTest 1063 @Test 1064 @Ignore("TODO(b/146420831)") 1065 public void testSeekNative() { 1066 assumeTrue(shouldRunTest(mMime)); 1067 boolean isOk = true; 1068 for (String srcFile : mSrcFiles) { 1069 if (!nativeTestSeek(mInpPrefix + srcFile, mMime)) { 1070 if (!codecListSupp.contains(mMime)) { 1071 isOk = false; 1072 break; 1073 } 1074 } 1075 } 1076 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 1077 } 1078 1079 @LargeTest 1080 @Test 1081 public void testSeekFlakinessNative() { 1082 assumeTrue(shouldRunTest(mMime)); 1083 boolean isOk = true; 1084 for (String srcFile : mSrcFiles) { 1085 if (!nativeTestSeekFlakiness(mInpPrefix + srcFile, mMime)) { 1086 if (!codecListSupp.contains(mMime)) { 1087 isOk = false; 1088 break; 1089 } 1090 } 1091 } 1092 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 1093 } 1094 1095 @SmallTest 1096 @Test 1097 public void testSeekToZeroNative() { 1098 assumeTrue(shouldRunTest(mMime)); 1099 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_VORBIS)); 1100 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_MPEG)); 1101 assumeTrue("TODO(b/146925481)", !mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)); 1102 boolean isOk = true; 1103 for (String srcFile : mSrcFiles) { 1104 if (!nativeTestSeekToZero(mInpPrefix + srcFile, mMime)) { 1105 if (!codecListSupp.contains(mMime)) { 1106 isOk = false; 1107 break; 1108 } 1109 } 1110 } 1111 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 1112 } 1113 1114 @SmallTest 1115 @Test 1116 public void testFileFormatNative() { 1117 assumeTrue(shouldRunTest(mMime)); 1118 boolean isOk = true; 1119 for (String srcFile : mSrcFiles) { 1120 if (!nativeTestFileFormat(mInpPrefix + srcFile)) { 1121 isOk = false; 1122 break; 1123 } 1124 assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk); 1125 } 1126 } 1127 } 1128 } 1129