Rename Mp4MetadataInfo to mp4Info

PiperOrigin-RevId: 593143940
This commit is contained in:
tofunmi 2023-12-22 11:07:27 -08:00 committed by Copybara-Service
parent 4fc11a98a1
commit e3056dacac
4 changed files with 77 additions and 81 deletions

View File

@ -40,8 +40,11 @@ import java.util.Map;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
/** Provides MP4 metadata like duration, last sync sample timestamp etc. */ /**
/* package */ final class Mp4MetadataInfo { * Provides some specific MP4 metadata about an mp4 file such as the duration, last sync sample
* timestamp etc.
*/
/* package */ final class Mp4Info {
/** /**
* The duration (in microseconds) of the MP4 file or {@link C#TIME_UNSET} if the duration is * The duration (in microseconds) of the MP4 file or {@link C#TIME_UNSET} if the duration is
* unknown. * unknown.
@ -67,7 +70,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
/** The audio {@link Format} or {@code null} if there is no audio track. */ /** The audio {@link Format} or {@code null} if there is no audio track. */
public final @Nullable Format audioFormat; public final @Nullable Format audioFormat;
private Mp4MetadataInfo( private Mp4Info(
long durationUs, long durationUs,
long lastSyncSampleTimestampUs, long lastSyncSampleTimestampUs,
long firstSyncSampleTimestampUsAfterTimeUs, long firstSyncSampleTimestampUsAfterTimeUs,
@ -81,18 +84,18 @@ import org.checkerframework.checker.nullness.qual.Nullable;
} }
/** /**
* Extracts the MP4 metadata synchronously and returns {@link Mp4MetadataInfo}. * Extracts the MP4 metadata synchronously and returns {@link Mp4Info}.
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param filePath The file path of a valid MP4. * @param filePath The file path of a valid MP4.
* @throws IOException If an error occurs during metadata extraction. * @throws IOException If an error occurs during metadata extraction.
*/ */
public static Mp4MetadataInfo create(Context context, String filePath) throws IOException { public static Mp4Info create(Context context, String filePath) throws IOException {
return create(context, filePath, C.TIME_UNSET); return create(context, filePath, C.TIME_UNSET);
} }
/** /**
* Extracts the MP4 metadata synchronously and returns {@link Mp4MetadataInfo}. * Extracts the MP4 metadata synchronously and returns {@link Mp4Info}.
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param filePath The file path of a valid MP4. * @param filePath The file path of a valid MP4.
@ -100,8 +103,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* #firstSyncSampleTimestampUsAfterTimeUs}. {@link C#TIME_UNSET} if not needed. * #firstSyncSampleTimestampUsAfterTimeUs}. {@link C#TIME_UNSET} if not needed.
* @throws IOException If an error occurs during metadata extraction. * @throws IOException If an error occurs during metadata extraction.
*/ */
public static Mp4MetadataInfo create(Context context, String filePath, long timeUs) public static Mp4Info create(Context context, String filePath, long timeUs) throws IOException {
throws IOException {
Mp4Extractor mp4Extractor = new Mp4Extractor(); Mp4Extractor mp4Extractor = new Mp4Extractor();
ExtractorOutputImpl extractorOutput = new ExtractorOutputImpl(); ExtractorOutputImpl extractorOutput = new ExtractorOutputImpl();
DefaultDataSource dataSource = DefaultDataSource dataSource =
@ -169,7 +171,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
audioFormat = checkNotNull(audioTrackOutput.format); audioFormat = checkNotNull(audioTrackOutput.format);
} }
return new Mp4MetadataInfo( return new Mp4Info(
durationUs, durationUs,
lastSyncSampleTimestampUs, lastSyncSampleTimestampUs,
firstSyncSampleTimestampUsAfterTimeUs, firstSyncSampleTimestampUsAfterTimeUs,

View File

@ -779,8 +779,7 @@ public final class Transformer {
private @MonotonicNonNull ListenableFuture<TransmuxTranscodeHelper.ResumeMetadata> private @MonotonicNonNull ListenableFuture<TransmuxTranscodeHelper.ResumeMetadata>
getResumeMetadataFuture; getResumeMetadataFuture;
private @MonotonicNonNull ListenableFuture<Void> copyOutputFuture; private @MonotonicNonNull ListenableFuture<Void> copyOutputFuture;
private @MonotonicNonNull ListenableFuture<Mp4MetadataInfo> getMp4MetadataInfoFuture; @Nullable private Mp4Info mediaItemInfo;
@Nullable private Mp4MetadataInfo mediaItemMetadataInfo;
private Transformer( private Transformer(
Context context, Context context,
@ -1089,15 +1088,14 @@ public final class Transformer {
} }
private @ProgressState int getTrimOptimizationProgress(ProgressHolder progressHolder) { private @ProgressState int getTrimOptimizationProgress(ProgressHolder progressHolder) {
if (mediaItemMetadataInfo == null) { if (mediaItemInfo == null) {
return PROGRESS_STATE_WAITING_FOR_AVAILABILITY; return PROGRESS_STATE_WAITING_FOR_AVAILABILITY;
} }
MediaItem firstMediaItem = MediaItem firstMediaItem =
checkNotNull(composition).sequences.get(0).editedMediaItems.get(0).mediaItem; checkNotNull(composition).sequences.get(0).editedMediaItems.get(0).mediaItem;
long trimStartTimeUs = firstMediaItem.clippingConfiguration.startPositionUs; long trimStartTimeUs = firstMediaItem.clippingConfiguration.startPositionUs;
long transcodeDuration = long transcodeDuration = mediaItemInfo.firstSyncSampleTimestampUsAfterTimeUs - trimStartTimeUs;
mediaItemMetadataInfo.firstSyncSampleTimestampUsAfterTimeUs - trimStartTimeUs; float transcodeWeighting = (float) transcodeDuration / mediaItemInfo.durationUs;
float transcodeWeighting = (float) transcodeDuration / mediaItemMetadataInfo.durationUs;
if (transformerState == TRANSFORMER_STATE_PROCESS_MEDIA_START) { if (transformerState == TRANSFORMER_STATE_PROCESS_MEDIA_START) {
if (transformerInternal == null) { if (transformerInternal == null) {
@ -1315,24 +1313,24 @@ public final class Transformer {
checkNotNull(composition).sequences.get(0).editedMediaItems.get(0).mediaItem; checkNotNull(composition).sequences.get(0).editedMediaItems.get(0).mediaItem;
long trimStartTimeUs = firstMediaItem.clippingConfiguration.startPositionUs; long trimStartTimeUs = firstMediaItem.clippingConfiguration.startPositionUs;
long trimEndTimeUs = firstMediaItem.clippingConfiguration.endPositionUs; long trimEndTimeUs = firstMediaItem.clippingConfiguration.endPositionUs;
getMp4MetadataInfoFuture = ListenableFuture<Mp4Info> getMp4InfoFuture =
TransmuxTranscodeHelper.getMp4MetadataInfo( TransmuxTranscodeHelper.getMp4Info(
context, context,
checkNotNull(firstMediaItem.localConfiguration).uri.toString(), checkNotNull(firstMediaItem.localConfiguration).uri.toString(),
trimStartTimeUs); trimStartTimeUs);
Futures.addCallback( Futures.addCallback(
getMp4MetadataInfoFuture, getMp4InfoFuture,
new FutureCallback<Mp4MetadataInfo>() { new FutureCallback<Mp4Info>() {
@Override @Override
public void onSuccess(Mp4MetadataInfo mp4MetadataInfo) { public void onSuccess(Mp4Info mp4Info) {
if (mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs == C.TIME_UNSET) { if (mp4Info.firstSyncSampleTimestampUsAfterTimeUs == C.TIME_UNSET) {
exportResultBuilder.setOptimizationResult(OPTIMIZATION_ABANDONED_OTHER); exportResultBuilder.setOptimizationResult(OPTIMIZATION_ABANDONED_OTHER);
processFullInput(); processFullInput();
return; return;
} }
if (mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs == C.TIME_END_OF_SOURCE if (mp4Info.firstSyncSampleTimestampUsAfterTimeUs == C.TIME_END_OF_SOURCE
|| (trimEndTimeUs != C.TIME_END_OF_SOURCE || (trimEndTimeUs != C.TIME_END_OF_SOURCE
&& trimEndTimeUs < mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs)) { && trimEndTimeUs < mp4Info.firstSyncSampleTimestampUsAfterTimeUs)) {
exportResultBuilder.setOptimizationResult( exportResultBuilder.setOptimizationResult(
OPTIMIZATION_ABANDONED_KEYFRAME_PLACEMENT_OPTIMAL_FOR_TRIM); OPTIMIZATION_ABANDONED_KEYFRAME_PLACEMENT_OPTIMAL_FOR_TRIM);
processFullInput(); processFullInput();
@ -1340,14 +1338,14 @@ public final class Transformer {
} }
// Ensure there is an audio sample to mux between the two clip times to prevent // Ensure there is an audio sample to mux between the two clip times to prevent
// Transformer from hanging because it received an audio track but no audio samples. // Transformer from hanging because it received an audio track but no audio samples.
if (mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs - trimStartTimeUs if (mp4Info.firstSyncSampleTimestampUsAfterTimeUs - trimStartTimeUs
< MAX_ENCODED_AUDIO_BUFFER_DURATION_US) { < MAX_ENCODED_AUDIO_BUFFER_DURATION_US) {
Transformer.this.composition = Transformer.this.composition =
buildNewCompositionWithClipTimes( buildNewCompositionWithClipTimes(
composition, composition,
mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs, mp4Info.firstSyncSampleTimestampUsAfterTimeUs,
firstMediaItem.clippingConfiguration.endPositionUs, firstMediaItem.clippingConfiguration.endPositionUs,
mp4MetadataInfo.durationUs, mp4Info.durationUs,
/* startsAtKeyFrame= */ true); /* startsAtKeyFrame= */ true);
exportResultBuilder.setOptimizationResult( exportResultBuilder.setOptimizationResult(
OPTIMIZATION_ABANDONED_KEYFRAME_PLACEMENT_OPTIMAL_FOR_TRIM); OPTIMIZATION_ABANDONED_KEYFRAME_PLACEMENT_OPTIMAL_FOR_TRIM);
@ -1362,15 +1360,15 @@ public final class Transformer {
MuxerWrapper.MUXER_MODE_MUX_PARTIAL, MuxerWrapper.MUXER_MODE_MUX_PARTIAL,
/* dropSamplesBeforeFirstVideoSample= */ false); /* dropSamplesBeforeFirstVideoSample= */ false);
if (shouldTranscodeVideo( if (shouldTranscodeVideo(
checkNotNull(mp4MetadataInfo.videoFormat), checkNotNull(mp4Info.videoFormat),
composition, composition,
/* sequenceIndex= */ 0, /* sequenceIndex= */ 0,
transformationRequest, transformationRequest,
encoderFactory, encoderFactory,
remuxingMuxerWrapper) remuxingMuxerWrapper)
|| (mp4MetadataInfo.audioFormat != null || (mp4Info.audioFormat != null
&& shouldTranscodeAudio( && shouldTranscodeAudio(
mp4MetadataInfo.audioFormat, mp4Info.audioFormat,
composition, composition,
/* sequenceIndex= */ 0, /* sequenceIndex= */ 0,
transformationRequest, transformationRequest,
@ -1382,13 +1380,13 @@ public final class Transformer {
processFullInput(); processFullInput();
return; return;
} }
Transformer.this.mediaItemMetadataInfo = mp4MetadataInfo; Transformer.this.mediaItemInfo = mp4Info;
Composition trancodeComposition = Composition trancodeComposition =
buildNewCompositionWithClipTimes( buildNewCompositionWithClipTimes(
composition, composition,
trimStartTimeUs, trimStartTimeUs,
mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs, mp4Info.firstSyncSampleTimestampUsAfterTimeUs,
mp4MetadataInfo.durationUs, mp4Info.durationUs,
/* startsAtKeyFrame= */ false); /* startsAtKeyFrame= */ false);
startInternal( startInternal(
@ -1408,7 +1406,7 @@ public final class Transformer {
} }
private void remuxRemainingMedia() { private void remuxRemainingMedia() {
Mp4MetadataInfo mediaItemMetadataInfo = checkNotNull(this.mediaItemMetadataInfo); Mp4Info mediaItemInfo = checkNotNull(this.mediaItemInfo);
transformerState = TRANSFORMER_STATE_REMUX_REMAINING_MEDIA; transformerState = TRANSFORMER_STATE_REMUX_REMAINING_MEDIA;
if (!doesFormatsMatch()) { if (!doesFormatsMatch()) {
remuxingMuxerWrapper = null; remuxingMuxerWrapper = null;
@ -1424,9 +1422,9 @@ public final class Transformer {
Composition transmuxComposition = Composition transmuxComposition =
buildNewCompositionWithClipTimes( buildNewCompositionWithClipTimes(
composition, composition,
mediaItemMetadataInfo.firstSyncSampleTimestampUsAfterTimeUs, mediaItemInfo.firstSyncSampleTimestampUsAfterTimeUs,
trimEndTimeUs, trimEndTimeUs,
mediaItemMetadataInfo.durationUs, mediaItemInfo.durationUs,
/* startsAtKeyFrame= */ true); /* startsAtKeyFrame= */ true);
checkNotNull(remuxingMuxerWrapper); checkNotNull(remuxingMuxerWrapper);
remuxingMuxerWrapper.changeToAppendMode(); remuxingMuxerWrapper.changeToAppendMode();
@ -1434,19 +1432,19 @@ public final class Transformer {
transmuxComposition, transmuxComposition,
remuxingMuxerWrapper, remuxingMuxerWrapper,
componentListener, componentListener,
/* initialTimestampOffsetUs= */ mediaItemMetadataInfo.firstSyncSampleTimestampUsAfterTimeUs /* initialTimestampOffsetUs= */ mediaItemInfo.firstSyncSampleTimestampUsAfterTimeUs
- trimStartTimeUs); - trimStartTimeUs);
} }
private boolean doesFormatsMatch() { private boolean doesFormatsMatch() {
Mp4MetadataInfo mediaItemMetadataInfo = checkNotNull(this.mediaItemMetadataInfo); Mp4Info mediaItemInfo = checkNotNull(this.mediaItemInfo);
boolean videoFormatMatches = boolean videoFormatMatches =
checkNotNull(remuxingMuxerWrapper) checkNotNull(remuxingMuxerWrapper)
.getTrackFormat(C.TRACK_TYPE_VIDEO) .getTrackFormat(C.TRACK_TYPE_VIDEO)
.initializationDataEquals(checkNotNull(mediaItemMetadataInfo.videoFormat)); .initializationDataEquals(checkNotNull(mediaItemInfo.videoFormat));
boolean audioFormatMatches = boolean audioFormatMatches =
mediaItemMetadataInfo.audioFormat == null mediaItemInfo.audioFormat == null
|| mediaItemMetadataInfo.audioFormat.initializationDataEquals( || mediaItemInfo.audioFormat.initializationDataEquals(
checkNotNull(remuxingMuxerWrapper).getTrackFormat(C.TRACK_TYPE_AUDIO)); checkNotNull(remuxingMuxerWrapper).getTrackFormat(C.TRACK_TYPE_AUDIO));
return videoFormatMatches && audioFormatMatches; return videoFormatMatches && audioFormatMatches;
} }
@ -1555,7 +1553,7 @@ public final class Transformer {
remuxRemainingMedia(); remuxRemainingMedia();
} else if (transformerState == TRANSFORMER_STATE_REMUX_REMAINING_MEDIA) { } else if (transformerState == TRANSFORMER_STATE_REMUX_REMAINING_MEDIA) {
transformerState = TRANSFORMER_STATE_PROCESS_FULL_INPUT; transformerState = TRANSFORMER_STATE_PROCESS_FULL_INPUT;
mediaItemMetadataInfo = null; mediaItemInfo = null;
exportResultBuilder.setOptimizationResult(ExportResult.OPTIMIZATION_SUCCEEDED); exportResultBuilder.setOptimizationResult(ExportResult.OPTIMIZATION_SUCCEEDED);
onExportCompletedWithSuccess(); onExportCompletedWithSuccess();
} else { } else {

View File

@ -59,20 +59,20 @@ import java.util.List;
} }
} }
public static ListenableFuture<Mp4MetadataInfo> getMp4MetadataInfo( public static ListenableFuture<Mp4Info> getMp4Info(
Context context, String filePath, long timeUs) { Context context, String filePath, long timeUs) {
SettableFuture<Mp4MetadataInfo> mp4MetadataInfoSettableFuture = SettableFuture.create(); SettableFuture<Mp4Info> mp4InfoSettableFuture = SettableFuture.create();
new Thread("TransmuxTranscodeHelper:Mp4MetadataInfo") { new Thread("TransmuxTranscodeHelper:Mp4Info") {
@Override @Override
public void run() { public void run() {
try { try {
mp4MetadataInfoSettableFuture.set(Mp4MetadataInfo.create(context, filePath, timeUs)); mp4InfoSettableFuture.set(Mp4Info.create(context, filePath, timeUs));
} catch (Exception ex) { } catch (Exception ex) {
mp4MetadataInfoSettableFuture.setException(ex); mp4InfoSettableFuture.setException(ex);
} }
} }
}.start(); }.start();
return mp4MetadataInfoSettableFuture; return mp4InfoSettableFuture;
} }
public static Composition buildNewCompositionWithClipTimes( public static Composition buildNewCompositionWithClipTimes(
@ -261,7 +261,7 @@ import java.util.List;
return; return;
} }
long lastSyncSampleTimestampUs = long lastSyncSampleTimestampUs =
Mp4MetadataInfo.create(context, filePath).lastSyncSampleTimestampUs; Mp4Info.create(context, filePath).lastSyncSampleTimestampUs;
ImmutableList.Builder<Pair<Integer, Long>> firstMediaItemIndexAndOffsetInfoBuilder = ImmutableList.Builder<Pair<Integer, Long>> firstMediaItemIndexAndOffsetInfoBuilder =
new ImmutableList.Builder<>(); new ImmutableList.Builder<>();
@ -348,7 +348,7 @@ import java.util.List;
if (mediaItem.clippingConfiguration.endPositionMs != C.TIME_END_OF_SOURCE) { if (mediaItem.clippingConfiguration.endPositionMs != C.TIME_END_OF_SOURCE) {
endUs = Util.msToUs(mediaItem.clippingConfiguration.endPositionMs); endUs = Util.msToUs(mediaItem.clippingConfiguration.endPositionMs);
} else { } else {
endUs = Mp4MetadataInfo.create(context, filePath).durationUs; endUs = Mp4Info.create(context, filePath).durationUs;
} }
return endUs - startUs; return endUs - startUs;

View File

@ -31,9 +31,9 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Unit tests for {@link Mp4MetadataInfo}. */ /** Unit tests for {@link Mp4Info}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class Mp4MetadataInfoTest { public class Mp4InfoTest {
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
private final Context context = ApplicationProvider.getApplicationContext(); private final Context context = ApplicationProvider.getApplicationContext();
@ -42,58 +42,57 @@ public class Mp4MetadataInfoTest {
public void create_withEmptyFile_throws() throws IOException { public void create_withEmptyFile_throws() throws IOException {
String emptyFilePath = temporaryFolder.newFile("EmptyFile").getPath(); String emptyFilePath = temporaryFolder.newFile("EmptyFile").getPath();
assertThrows(IllegalStateException.class, () -> Mp4MetadataInfo.create(context, emptyFilePath)); assertThrows(IllegalStateException.class, () -> Mp4Info.create(context, emptyFilePath));
} }
@Test @Test
public void create_withNonMp4File_throws() { public void create_withNonMp4File_throws() {
String nonMp4FilePath = "asset:///media/mkv/sample.mkv"; String nonMp4FilePath = "asset:///media/mkv/sample.mkv";
assertThrows( assertThrows(IllegalStateException.class, () -> Mp4Info.create(context, nonMp4FilePath));
IllegalStateException.class, () -> Mp4MetadataInfo.create(context, nonMp4FilePath));
} }
@Test @Test
public void lastSyncSampleTimestampUs_ofSmallMp4File_outputsFirstTimestamp() throws IOException { public void lastSyncSampleTimestampUs_ofSmallMp4File_outputsFirstTimestamp() throws IOException {
String mp4FilePath = "asset:///media/mp4/sample.mp4"; String mp4FilePath = "asset:///media/mp4/sample.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
assertThat(mp4MetadataInfo.lastSyncSampleTimestampUs) assertThat(mp4Info.lastSyncSampleTimestampUs)
.isEqualTo(0); // The timestamp of the first sample in sample.mp4. .isEqualTo(0); // The timestamp of the first sample in sample.mp4.
} }
@Test @Test
public void lastSyncSampleTimestampUs_ofMp4File_outputMatchesExpected() throws IOException { public void lastSyncSampleTimestampUs_ofMp4File_outputMatchesExpected() throws IOException {
String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4"; String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
assertThat(mp4MetadataInfo.lastSyncSampleTimestampUs) assertThat(mp4Info.lastSyncSampleTimestampUs)
.isEqualTo(4_003_277L); // The timestamp of the last sync sample in hdr10-720p.mp4. .isEqualTo(4_003_277L); // The timestamp of the last sync sample in hdr10-720p.mp4.
} }
@Test @Test
public void lastSyncSampleTimestampUs_ofAudioOnlyMp4File_isUnset() throws IOException { public void lastSyncSampleTimestampUs_ofAudioOnlyMp4File_isUnset() throws IOException {
String audioOnlyMp4FilePath = "asset:///media/mp4/sample_ac3.mp4"; String audioOnlyMp4FilePath = "asset:///media/mp4/sample_ac3.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, audioOnlyMp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, audioOnlyMp4FilePath);
assertThat(mp4MetadataInfo.lastSyncSampleTimestampUs).isEqualTo(C.TIME_UNSET); assertThat(mp4Info.lastSyncSampleTimestampUs).isEqualTo(C.TIME_UNSET);
} }
@Test @Test
public void durationUs_ofMp4File_outputMatchesExpected() throws Exception { public void durationUs_ofMp4File_outputMatchesExpected() throws Exception {
String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4"; String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
assertThat(mp4MetadataInfo.durationUs).isEqualTo(4_236_600L); // The duration of hdr10-720p.mp4. assertThat(mp4Info.durationUs).isEqualTo(4_236_600L); // The duration of hdr10-720p.mp4.
} }
@Test @Test
public void firstSyncSampleTimestampUsAfterTimeUs_timeUsIsSyncSample_outputsFirstTimestamp() public void firstSyncSampleTimestampUsAfterTimeUs_timeUsIsSyncSample_outputsFirstTimestamp()
throws IOException { throws IOException {
String mp4FilePath = "asset:///media/mp4/sample.mp4"; String mp4FilePath = "asset:///media/mp4/sample.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath, /* timeUs= */ 0); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath, /* timeUs= */ 0);
assertThat(mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs) assertThat(mp4Info.firstSyncSampleTimestampUsAfterTimeUs)
.isEqualTo(0); // The timestamp of the first sample in sample.mp4. .isEqualTo(0); // The timestamp of the first sample in sample.mp4.
} }
@ -101,43 +100,40 @@ public class Mp4MetadataInfoTest {
public void firstSyncSampleTimestampUsAfterTimeUs_timeUsNotASyncSample_returnsCorrectTimestamp() public void firstSyncSampleTimestampUsAfterTimeUs_timeUsNotASyncSample_returnsCorrectTimestamp()
throws IOException { throws IOException {
String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4"; String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath, /* timeUs= */ 400);
Mp4MetadataInfo.create(context, mp4FilePath, /* timeUs= */ 400);
assertThat(mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs).isEqualTo(1_002_955L); assertThat(mp4Info.firstSyncSampleTimestampUsAfterTimeUs).isEqualTo(1_002_955L);
} }
@Test @Test
public void firstSyncSampleTimestampUsAfterTimeUs_timeUsSetToDuration_returnsTimeEndOfSource() public void firstSyncSampleTimestampUsAfterTimeUs_timeUsSetToDuration_returnsTimeEndOfSource()
throws IOException { throws IOException {
String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4"; String mp4FilePath = "asset:///media/mp4/hdr10-720p.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath, /* timeUs= */ 4_236_600L);
Mp4MetadataInfo.create(context, mp4FilePath, /* timeUs= */ 4_236_600L);
assertThat(mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs) assertThat(mp4Info.firstSyncSampleTimestampUsAfterTimeUs).isEqualTo(C.TIME_END_OF_SOURCE);
.isEqualTo(C.TIME_END_OF_SOURCE);
} }
@Test @Test
public void firstSyncSampleTimestampUsAfterTimeUs_ofAudioOnlyMp4File_returnsUnsetValue() public void firstSyncSampleTimestampUsAfterTimeUs_ofAudioOnlyMp4File_returnsUnsetValue()
throws IOException { throws IOException {
String mp4FilePath = "asset:///media/mp4/sample_ac3.mp4"; String mp4FilePath = "asset:///media/mp4/sample_ac3.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath, /* timeUs= */ 0); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath, /* timeUs= */ 0);
assertThat(mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs).isEqualTo(C.TIME_UNSET); assertThat(mp4Info.firstSyncSampleTimestampUsAfterTimeUs).isEqualTo(C.TIME_UNSET);
} }
@Test @Test
public void videoFormat_outputsFormatObjectWithCorrectRelevantFormatData() throws IOException { public void videoFormat_outputsFormatObjectWithCorrectRelevantFormatData() throws IOException {
String mp4FilePath = "asset:///media/mp4/sample.mp4"; String mp4FilePath = "asset:///media/mp4/sample.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
byte[] expectedCsd0 = { byte[] expectedCsd0 = {
0, 0, 0, 1, 103, 100, 0, 31, -84, -39, 64, 68, 5, -66, 95, 1, 16, 0, 0, 62, -112, 0, 14, -90, 0, 0, 0, 1, 103, 100, 0, 31, -84, -39, 64, 68, 5, -66, 95, 1, 16, 0, 0, 62, -112, 0, 14, -90,
0, -15, -125, 25, 96 0, -15, -125, 25, 96
}; };
byte[] expectedCsd1 = {0, 0, 0, 1, 104, -21, -29, -53, 34, -64}; byte[] expectedCsd1 = {0, 0, 0, 1, 104, -21, -29, -53, 34, -64};
Format actualFormat = mp4MetadataInfo.videoFormat; Format actualFormat = mp4Info.videoFormat;
assertThat(actualFormat).isNotNull(); assertThat(actualFormat).isNotNull();
assertThat(actualFormat.initializationData.get(0)).isEqualTo(expectedCsd0); assertThat(actualFormat.initializationData.get(0)).isEqualTo(expectedCsd0);
@ -152,18 +148,18 @@ public class Mp4MetadataInfoTest {
@Test @Test
public void videoFormat_audioOnlyMp4File_outputsNull() throws IOException { public void videoFormat_audioOnlyMp4File_outputsNull() throws IOException {
String mp4FilePath = "asset:///media/mp4/sample_ac3.mp4"; String mp4FilePath = "asset:///media/mp4/sample_ac3.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
assertThat(mp4MetadataInfo.videoFormat).isNull(); assertThat(mp4Info.videoFormat).isNull();
} }
@Test @Test
public void audioFormat_outputsFormatObjectWithCorrectRelevantFormatData() throws IOException { public void audioFormat_outputsFormatObjectWithCorrectRelevantFormatData() throws IOException {
String mp4FilePath = "asset:///media/mp4/sample.mp4"; String mp4FilePath = "asset:///media/mp4/sample.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
byte[] expectedCsd0 = {18, 8}; byte[] expectedCsd0 = {18, 8};
Format actualFormat = mp4MetadataInfo.audioFormat; Format actualFormat = mp4Info.audioFormat;
assertThat(actualFormat).isNotNull(); assertThat(actualFormat).isNotNull();
assertThat(actualFormat.sampleMimeType).isEqualTo(AUDIO_AAC); assertThat(actualFormat.sampleMimeType).isEqualTo(AUDIO_AAC);
@ -175,8 +171,8 @@ public class Mp4MetadataInfoTest {
@Test @Test
public void audioFormat_videoOnlyMp4File_outputsNull() throws IOException { public void audioFormat_videoOnlyMp4File_outputsNull() throws IOException {
String mp4FilePath = "asset:///media/mp4/sample_18byte_nclx_colr.mp4"; String mp4FilePath = "asset:///media/mp4/sample_18byte_nclx_colr.mp4";
Mp4MetadataInfo mp4MetadataInfo = Mp4MetadataInfo.create(context, mp4FilePath); Mp4Info mp4Info = Mp4Info.create(context, mp4FilePath);
assertThat(mp4MetadataInfo.audioFormat).isNull(); assertThat(mp4Info.audioFormat).isNull();
} }
} }