mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Improve CompositionExportTest assertions by using dump files.
PiperOrigin-RevId: 563708666
This commit is contained in:
parent
007b7dbbf1
commit
866d62dd34
8 changed files with 11000 additions and 30 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,67 @@
|
||||||
|
format audio:
|
||||||
|
averageBitrate = 131072
|
||||||
|
sampleMimeType = audio/mp4a-latm
|
||||||
|
channelCount = 1
|
||||||
|
sampleRate = 44100
|
||||||
|
pcmEncoding = 2
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1365664853
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 0
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = -1466730976
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 100000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1178728837
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 200000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = -216459624
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 300000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1990341112
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 400000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1561236782
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 500000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1146352887
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 600000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1061204212
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 700000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 840187559
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 800000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = -29240395
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 900000
|
||||||
|
released = true
|
||||||
|
|
@ -18,13 +18,16 @@ package androidx.media3.transformer;
|
||||||
import static androidx.media3.transformer.TestUtil.ASSET_URI_PREFIX;
|
import static androidx.media3.transformer.TestUtil.ASSET_URI_PREFIX;
|
||||||
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_ONLY;
|
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_ONLY;
|
||||||
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_RAW;
|
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_RAW;
|
||||||
|
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_RAW_STEREO_48000KHZ;
|
||||||
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_RAW_VIDEO;
|
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_RAW_VIDEO;
|
||||||
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_VIDEO;
|
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_VIDEO;
|
||||||
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S;
|
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S;
|
||||||
import static androidx.media3.transformer.TestUtil.FILE_VIDEO_ONLY;
|
import static androidx.media3.transformer.TestUtil.FILE_VIDEO_ONLY;
|
||||||
import static androidx.media3.transformer.TestUtil.addAudioDecoders;
|
import static androidx.media3.transformer.TestUtil.addAudioDecoders;
|
||||||
import static androidx.media3.transformer.TestUtil.addAudioEncoders;
|
import static androidx.media3.transformer.TestUtil.addAudioEncoders;
|
||||||
|
import static androidx.media3.transformer.TestUtil.createAudioEffects;
|
||||||
import static androidx.media3.transformer.TestUtil.createTransformerBuilder;
|
import static androidx.media3.transformer.TestUtil.createTransformerBuilder;
|
||||||
|
import static androidx.media3.transformer.TestUtil.createVolumeScalingAudioProcessor;
|
||||||
import static androidx.media3.transformer.TestUtil.getDumpFileName;
|
import static androidx.media3.transformer.TestUtil.getDumpFileName;
|
||||||
import static androidx.media3.transformer.TestUtil.removeEncodersAndDecoders;
|
import static androidx.media3.transformer.TestUtil.removeEncodersAndDecoders;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
@ -66,13 +69,11 @@ public class CompositionExportTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void start_audioVideoTransmuxedFromDifferentSequences_producesExpectedResult()
|
public void start_audioVideoTransmuxedFromDifferentSequences_matchesSingleSequenceResult()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
transformer.start(mediaItem, outputDir.newFile().getPath());
|
|
||||||
ExportResult expectedExportResult = TransformerTestRunner.runLooper(transformer);
|
|
||||||
|
|
||||||
EditedMediaItem audioEditedMediaItem =
|
EditedMediaItem audioEditedMediaItem =
|
||||||
new EditedMediaItem.Builder(mediaItem).setRemoveVideo(true).build();
|
new EditedMediaItem.Builder(mediaItem).setRemoveVideo(true).build();
|
||||||
|
|
@ -85,16 +86,11 @@ public class CompositionExportTest {
|
||||||
.setTransmuxAudio(true)
|
.setTransmuxAudio(true)
|
||||||
.setTransmuxVideo(true)
|
.setTransmuxVideo(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
transformer.start(composition, outputDir.newFile().getPath());
|
transformer.start(composition, outputDir.newFile().getPath());
|
||||||
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
// We can't compare the muxer output against a dump file because the asset loaders in each
|
DumpFileAsserts.assertOutput(
|
||||||
// sequence load samples from their own thread, independently of each other, which makes the
|
context, muxerFactory.getCreatedMuxer(), getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
// output non-deterministic.
|
|
||||||
assertThat(exportResult.channelCount).isEqualTo(expectedExportResult.channelCount);
|
|
||||||
assertThat(exportResult.videoFrameCount).isEqualTo(expectedExportResult.videoFrameCount);
|
|
||||||
assertThat(exportResult.durationMs).isEqualTo(expectedExportResult.durationMs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -104,8 +100,7 @@ public class CompositionExportTest {
|
||||||
EditedMediaItem audioEditedMediaItem =
|
EditedMediaItem audioEditedMediaItem =
|
||||||
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_ONLY)).build();
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_ONLY)).build();
|
||||||
EditedMediaItemSequence loopingAudioSequence =
|
EditedMediaItemSequence loopingAudioSequence =
|
||||||
new EditedMediaItemSequence(
|
new EditedMediaItemSequence(ImmutableList.of(audioEditedMediaItem), /* isLooping= */ true);
|
||||||
ImmutableList.of(audioEditedMediaItem, audioEditedMediaItem), /* isLooping= */ true);
|
|
||||||
EditedMediaItem videoEditedMediaItem =
|
EditedMediaItem videoEditedMediaItem =
|
||||||
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY)).build();
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY)).build();
|
||||||
EditedMediaItemSequence videoSequence =
|
EditedMediaItemSequence videoSequence =
|
||||||
|
|
@ -121,10 +116,14 @@ public class CompositionExportTest {
|
||||||
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
assertThat(exportResult.processedInputs).hasSize(6);
|
assertThat(exportResult.processedInputs).hasSize(6);
|
||||||
assertThat(exportResult.channelCount).isEqualTo(1);
|
DumpFileAsserts.assertOutput(
|
||||||
assertThat(exportResult.videoFrameCount).isEqualTo(90);
|
context,
|
||||||
assertThat(exportResult.durationMs).isEqualTo(2977);
|
muxerFactory.getCreatedMuxer(),
|
||||||
assertThat(exportResult.fileSizeBytes).isEqualTo(293660);
|
getDumpFileName(
|
||||||
|
FILE_AUDIO_ONLY,
|
||||||
|
/* modifications...= */ "looping",
|
||||||
|
"mixedWith",
|
||||||
|
getFileName(FILE_VIDEO_ONLY)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -139,8 +138,7 @@ public class CompositionExportTest {
|
||||||
EditedMediaItem videoEditedMediaItem =
|
EditedMediaItem videoEditedMediaItem =
|
||||||
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY)).build();
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY)).build();
|
||||||
EditedMediaItemSequence loopingVideoSequence =
|
EditedMediaItemSequence loopingVideoSequence =
|
||||||
new EditedMediaItemSequence(
|
new EditedMediaItemSequence(ImmutableList.of(videoEditedMediaItem), /* isLooping= */ true);
|
||||||
ImmutableList.of(videoEditedMediaItem, videoEditedMediaItem), /* isLooping= */ true);
|
|
||||||
Composition composition =
|
Composition composition =
|
||||||
new Composition.Builder(audioSequence, loopingVideoSequence)
|
new Composition.Builder(audioSequence, loopingVideoSequence)
|
||||||
.setTransmuxAudio(true)
|
.setTransmuxAudio(true)
|
||||||
|
|
@ -151,14 +149,18 @@ public class CompositionExportTest {
|
||||||
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
assertThat(exportResult.processedInputs).hasSize(7);
|
assertThat(exportResult.processedInputs).hasSize(7);
|
||||||
assertThat(exportResult.channelCount).isEqualTo(1);
|
DumpFileAsserts.assertOutput(
|
||||||
assertThat(exportResult.videoFrameCount).isEqualTo(93);
|
context,
|
||||||
assertThat(exportResult.durationMs).isEqualTo(3108);
|
muxerFactory.getCreatedMuxer(),
|
||||||
assertThat(exportResult.fileSizeBytes).isEqualTo(337308);
|
getDumpFileName(
|
||||||
|
FILE_VIDEO_ONLY,
|
||||||
|
/* modifications...= */ "looping",
|
||||||
|
"mixedWith",
|
||||||
|
getFileName(FILE_AUDIO_ONLY)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void start_loopingRawAudio_producesExpectedResult() throws Exception {
|
public void start_longVideoCompositionWithLoopingAudio_producesExpectedResult() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
||||||
EditedMediaItemSequence loopingAudioSequence =
|
EditedMediaItemSequence loopingAudioSequence =
|
||||||
|
|
@ -191,7 +193,6 @@ public class CompositionExportTest {
|
||||||
public void start_compositionOfConcurrentAudio_isCorrect() throws Exception {
|
public void start_compositionOfConcurrentAudio_isCorrect() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
||||||
|
|
||||||
EditedMediaItem rawAudioEditedMediaItem =
|
EditedMediaItem rawAudioEditedMediaItem =
|
||||||
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW)).build();
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW)).build();
|
||||||
Composition composition =
|
Composition composition =
|
||||||
|
|
@ -208,7 +209,7 @@ public class CompositionExportTest {
|
||||||
context,
|
context,
|
||||||
muxerFactory.getCreatedMuxer(),
|
muxerFactory.getCreatedMuxer(),
|
||||||
getDumpFileName(
|
getDumpFileName(
|
||||||
/* originalFileName= */ FILE_AUDIO_RAW, /* modifications...= */ "concurrent"));
|
FILE_AUDIO_RAW, /* modifications...= */ "mixed", getFileName(FILE_AUDIO_RAW)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -219,7 +220,8 @@ public class CompositionExportTest {
|
||||||
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW_VIDEO))
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW_VIDEO))
|
||||||
.build();
|
.build();
|
||||||
EditedMediaItem audioEditedMediaItem =
|
EditedMediaItem audioEditedMediaItem =
|
||||||
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW_VIDEO))
|
new EditedMediaItem.Builder(
|
||||||
|
MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW_STEREO_48000KHZ))
|
||||||
.setRemoveVideo(true)
|
.setRemoveVideo(true)
|
||||||
.build();
|
.build();
|
||||||
Composition composition =
|
Composition composition =
|
||||||
|
|
@ -233,7 +235,48 @@ public class CompositionExportTest {
|
||||||
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
assertThat(exportResult.processedInputs).hasSize(2);
|
assertThat(exportResult.processedInputs).hasSize(2);
|
||||||
assertThat(exportResult.durationMs).isEqualTo(1984);
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(
|
||||||
|
FILE_AUDIO_RAW_VIDEO,
|
||||||
|
/* modifications...= */ "mixed",
|
||||||
|
getFileName(FILE_AUDIO_RAW_STEREO_48000KHZ)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void start_audioVideoCompositionWithMutedAudio_matchesSingleSequence() throws Exception {
|
||||||
|
Transformer transformer =
|
||||||
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false).build();
|
||||||
|
EditedMediaItem audioVideoEditedMediaItem =
|
||||||
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW_VIDEO))
|
||||||
|
.build();
|
||||||
|
EditedMediaItem mutedAudioEditedMediaItem =
|
||||||
|
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW_VIDEO))
|
||||||
|
.setEffects(createAudioEffects(createVolumeScalingAudioProcessor(0f)))
|
||||||
|
.setRemoveVideo(true)
|
||||||
|
.build();
|
||||||
|
EditedMediaItemSequence loopingMutedAudioSequence =
|
||||||
|
new EditedMediaItemSequence(
|
||||||
|
ImmutableList.of(mutedAudioEditedMediaItem), /* isLooping= */ true);
|
||||||
|
|
||||||
|
transformer.start(
|
||||||
|
new Composition.Builder(
|
||||||
|
new EditedMediaItemSequence(
|
||||||
|
audioVideoEditedMediaItem,
|
||||||
|
audioVideoEditedMediaItem,
|
||||||
|
audioVideoEditedMediaItem),
|
||||||
|
loopingMutedAudioSequence)
|
||||||
|
.setTransmuxVideo(true)
|
||||||
|
.build(),
|
||||||
|
outputDir.newFile().getPath());
|
||||||
|
TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(
|
||||||
|
FILE_AUDIO_RAW_VIDEO, /* modifications...= */ "sequence", "repeated3Times"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -252,7 +295,6 @@ public class CompositionExportTest {
|
||||||
.build();
|
.build();
|
||||||
EditedMediaItemSequence loopingAudioSequence =
|
EditedMediaItemSequence loopingAudioSequence =
|
||||||
new EditedMediaItemSequence(ImmutableList.of(audioEditedMediaItem), /* isLooping= */ true);
|
new EditedMediaItemSequence(ImmutableList.of(audioEditedMediaItem), /* isLooping= */ true);
|
||||||
|
|
||||||
Composition composition =
|
Composition composition =
|
||||||
new Composition.Builder(audioVideoSequence, loopingAudioSequence)
|
new Composition.Builder(audioVideoSequence, loopingAudioSequence)
|
||||||
.setTransmuxVideo(true)
|
.setTransmuxVideo(true)
|
||||||
|
|
@ -262,6 +304,19 @@ public class CompositionExportTest {
|
||||||
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
assertThat(exportResult.processedInputs).hasSize(7);
|
assertThat(exportResult.processedInputs).hasSize(7);
|
||||||
assertThat(exportResult.durationMs).isEqualTo(5984);
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(
|
||||||
|
/* originalFileName= */ FILE_AUDIO_RAW_VIDEO,
|
||||||
|
/* modifications...= */ "sequence",
|
||||||
|
"repeated3Times",
|
||||||
|
"mixed",
|
||||||
|
"loopingAudio" + getFileName(FILE_AUDIO_RAW_VIDEO)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFileName(String filePath) {
|
||||||
|
int lastSeparator = filePath.lastIndexOf("/");
|
||||||
|
return filePath.substring(lastSeparator + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import android.content.Context;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.audio.AudioProcessor;
|
import androidx.media3.common.audio.AudioProcessor;
|
||||||
|
import androidx.media3.common.audio.ChannelMixingAudioProcessor;
|
||||||
|
import androidx.media3.common.audio.ChannelMixingMatrix;
|
||||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
|
@ -78,6 +80,17 @@ public final class TestUtil {
|
||||||
return sonicAudioProcessor;
|
return sonicAudioProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ChannelMixingAudioProcessor createVolumeScalingAudioProcessor(float scale) {
|
||||||
|
ChannelMixingAudioProcessor audioProcessor = new ChannelMixingAudioProcessor();
|
||||||
|
for (int channel = 1; channel <= 6; channel++) {
|
||||||
|
audioProcessor.putChannelMixingMatrix(
|
||||||
|
ChannelMixingMatrix.create(
|
||||||
|
/* inputChannelCount= */ channel, /* outputChannelCount= */ channel)
|
||||||
|
.scaleBy(scale));
|
||||||
|
}
|
||||||
|
return audioProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getDumpFileName(String originalFileName, String... modifications) {
|
public static String getDumpFileName(String originalFileName, String... modifications) {
|
||||||
String fileName = DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '/';
|
String fileName = DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '/';
|
||||||
if (modifications.length == 0) {
|
if (modifications.length == 0) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue