mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Transformer: Take effects into account when signalling duration
PiperOrigin-RevId: 616224079
This commit is contained in:
parent
3136deb9b3
commit
d269b93755
@ -77,6 +77,7 @@ import androidx.media3.effect.GlEffect;
|
||||
import androidx.media3.effect.Presentation;
|
||||
import androidx.media3.effect.RgbFilter;
|
||||
import androidx.media3.effect.ScaleAndRotateTransformation;
|
||||
import androidx.media3.effect.SpeedChangeEffect;
|
||||
import androidx.media3.effect.TimestampWrapper;
|
||||
import androidx.media3.exoplayer.audio.TeeAudioProcessor;
|
||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||
@ -926,6 +927,67 @@ public class TransformerEndToEndTest {
|
||||
assertThat(exception).hasMessageThat().contains("video");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void durationAdjustedSequence_completesWithCorrectDuration() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder(context).build();
|
||||
if (AndroidTestUtil.skipAndLogIfFormatsUnsupported(
|
||||
context,
|
||||
testId,
|
||||
/* inputFormat= */ MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_FORMAT,
|
||||
/* outputFormat= */ MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_FORMAT)) {
|
||||
return;
|
||||
}
|
||||
ImmutableList<Effect> videoEffects =
|
||||
ImmutableList.of(new SpeedChangeEffect(1.5f), new SpeedChangeEffect(2f));
|
||||
EditedMediaItem editedMediaItem =
|
||||
new EditedMediaItem.Builder(
|
||||
MediaItem.fromUri(
|
||||
Uri.parse(MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_URI_STRING)))
|
||||
.setEffects(new Effects(/* audioProcessors= */ ImmutableList.of(), videoEffects))
|
||||
.setRemoveAudio(true)
|
||||
.build();
|
||||
Composition composition =
|
||||
new Composition.Builder(new EditedMediaItemSequence(editedMediaItem, editedMediaItem))
|
||||
.build();
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
assertThat(result.exportResult.durationMs).isEqualTo(10_351L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void durationAdjustedSequence_withForcedAudioTrack_completesWithCorrectDuration()
|
||||
throws Exception {
|
||||
Transformer transformer = new Transformer.Builder(context).build();
|
||||
if (AndroidTestUtil.skipAndLogIfFormatsUnsupported(
|
||||
context,
|
||||
testId,
|
||||
/* inputFormat= */ MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_FORMAT,
|
||||
/* outputFormat= */ MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_FORMAT)) {
|
||||
return;
|
||||
}
|
||||
ImmutableList<Effect> videoEffects = ImmutableList.of(new SpeedChangeEffect(1.5f));
|
||||
EditedMediaItem editedMediaItem =
|
||||
new EditedMediaItem.Builder(
|
||||
MediaItem.fromUri(
|
||||
Uri.parse(MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_URI_STRING)))
|
||||
.setEffects(new Effects(/* audioProcessors= */ ImmutableList.of(), videoEffects))
|
||||
.setRemoveAudio(true)
|
||||
.build();
|
||||
Composition composition =
|
||||
new Composition.Builder(new EditedMediaItemSequence(editedMediaItem, editedMediaItem))
|
||||
.experimentalSetForceAudioTrack(true)
|
||||
.build();
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
assertThat(result.exportResult.durationMs).isAtMost(20_720L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void audioVideoTranscodedFromDifferentSequences_producesExpectedResult() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder(context).build();
|
||||
|
@ -17,10 +17,13 @@ package androidx.media3.transformer;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Effect;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.audio.AudioProcessor;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||
@ -298,4 +301,24 @@ public final class EditedMediaItem {
|
||||
}
|
||||
return presentationDurationUs;
|
||||
}
|
||||
|
||||
/* package */ long getDurationAfterEffectsApplied(long durationUs) {
|
||||
long audioDurationUs = durationUs;
|
||||
long videoDurationUs = durationUs;
|
||||
if (removeAudio) {
|
||||
audioDurationUs = C.TIME_UNSET;
|
||||
} else {
|
||||
for (AudioProcessor audioProcessor : effects.audioProcessors) {
|
||||
audioDurationUs = audioProcessor.getDurationAfterProcessorApplied(audioDurationUs);
|
||||
}
|
||||
}
|
||||
if (removeVideo) {
|
||||
videoDurationUs = C.TIME_UNSET;
|
||||
} else {
|
||||
for (Effect videoEffect : effects.videoEffects) {
|
||||
videoDurationUs = videoEffect.getDurationAfterEffectApplied(videoDurationUs);
|
||||
}
|
||||
}
|
||||
return max(audioDurationUs, videoDurationUs);
|
||||
}
|
||||
}
|
||||
|
@ -335,6 +335,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
checkArgument(
|
||||
durationUs != C.TIME_UNSET || currentMediaItemIndex == editedMediaItems.size() - 1,
|
||||
"Could not retrieve required duration for EditedMediaItem " + currentMediaItemIndex);
|
||||
durationUs =
|
||||
editedMediaItems.get(currentMediaItemIndex).getDurationAfterEffectsApplied(durationUs);
|
||||
currentAssetDurationUs = durationUs;
|
||||
if (editedMediaItems.size() == 1 && !isLooping) {
|
||||
sequenceAssetLoaderListener.onDurationUs(durationUs);
|
||||
|
Loading…
x
Reference in New Issue
Block a user