Rename Mp4MetadataInfo to mp4Info
PiperOrigin-RevId: 593143940
This commit is contained in:
parent
4fc11a98a1
commit
e3056dacac
@ -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,
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user