mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Transformer: add speedChange API
PiperOrigin-RevId: 616163061
This commit is contained in:
parent
762065fae0
commit
fe640da5e8
@ -52,6 +52,7 @@ import android.os.Handler;
|
|||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.util.Pair;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
@ -64,6 +65,7 @@ import androidx.media3.common.audio.AudioProcessor.AudioFormat;
|
|||||||
import androidx.media3.common.audio.ChannelMixingAudioProcessor;
|
import androidx.media3.common.audio.ChannelMixingAudioProcessor;
|
||||||
import androidx.media3.common.audio.ChannelMixingMatrix;
|
import androidx.media3.common.audio.ChannelMixingMatrix;
|
||||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||||
|
import androidx.media3.common.audio.SpeedProvider;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.datasource.DataSourceBitmapLoader;
|
import androidx.media3.datasource.DataSourceBitmapLoader;
|
||||||
@ -81,6 +83,7 @@ import androidx.media3.extractor.mp4.Mp4Extractor;
|
|||||||
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
import androidx.media3.test.utils.FakeExtractorOutput;
|
import androidx.media3.test.utils.FakeExtractorOutput;
|
||||||
import androidx.media3.test.utils.FakeTrackOutput;
|
import androidx.media3.test.utils.FakeTrackOutput;
|
||||||
|
import androidx.media3.test.utils.TestSpeedProvider;
|
||||||
import androidx.media3.test.utils.TestUtil;
|
import androidx.media3.test.utils.TestUtil;
|
||||||
import androidx.media3.transformer.AssetLoader.CompositionSettings;
|
import androidx.media3.transformer.AssetLoader.CompositionSettings;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@ -868,6 +871,40 @@ public class TransformerEndToEndTest {
|
|||||||
assertThat(result.exportResult.audioConversionProcess).isEqualTo(CONVERSION_PROCESS_TRANSMUXED);
|
assertThat(result.exportResult.audioConversionProcess).isEqualTo(CONVERSION_PROCESS_TRANSMUXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void speedAdjustedMedia_completesWithCorrectDuration() throws Exception {
|
||||||
|
Transformer transformer = new Transformer.Builder(context).build();
|
||||||
|
SpeedProvider speedProvider =
|
||||||
|
TestSpeedProvider.createWithStartTimes(
|
||||||
|
new long[] {
|
||||||
|
0L,
|
||||||
|
3 * C.MICROS_PER_SECOND,
|
||||||
|
6 * C.MICROS_PER_SECOND,
|
||||||
|
9 * C.MICROS_PER_SECOND,
|
||||||
|
12 * C.MICROS_PER_SECOND
|
||||||
|
},
|
||||||
|
new float[] {0.5f, 0.75f, 1f, 1.5f, 2f});
|
||||||
|
Pair<AudioProcessor, Effect> speedEffect =
|
||||||
|
Effects.createExperimentalSpeedChangingEffect(speedProvider);
|
||||||
|
Effects effects =
|
||||||
|
new Effects(
|
||||||
|
/* audioProcessors= */ ImmutableList.of(speedEffect.first),
|
||||||
|
/* videoEffects= */ ImmutableList.of(speedEffect.second));
|
||||||
|
EditedMediaItem editedMediaItem =
|
||||||
|
new EditedMediaItem.Builder(
|
||||||
|
MediaItem.fromUri(MP4_ASSET_WITH_INCREASING_TIMESTAMPS_320W_240H_15S_URI_STRING))
|
||||||
|
.setEffects(effects)
|
||||||
|
.build();
|
||||||
|
ExportTestResult result =
|
||||||
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
|
.build()
|
||||||
|
.run(testId, editedMediaItem);
|
||||||
|
|
||||||
|
// The input video is 15.537 seconds.
|
||||||
|
// 3 / 0.5 + 3 / 0.75 + 3 + 3 / 1.5 + 3.537 / 2 rounds up to 16_770
|
||||||
|
assertThat(result.exportResult.durationMs).isAtMost(16_770);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void videoEncoderFormatUnsupported_completesWithError() throws Exception {
|
public void videoEncoderFormatUnsupported_completesWithError() throws Exception {
|
||||||
if (AndroidTestUtil.skipAndLogIfFormatsUnsupported(
|
if (AndroidTestUtil.skipAndLogIfFormatsUnsupported(
|
||||||
|
@ -15,10 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.audio.AudioProcessor;
|
import androidx.media3.common.audio.AudioProcessor;
|
||||||
|
import androidx.media3.common.audio.SpeedChangingAudioProcessor;
|
||||||
|
import androidx.media3.common.audio.SpeedProvider;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.effect.SpeedChangeEffect;
|
||||||
|
import androidx.media3.effect.TimestampAdjustment;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -54,4 +59,28 @@ public final class Effects {
|
|||||||
this.audioProcessors = ImmutableList.copyOf(audioProcessors);
|
this.audioProcessors = ImmutableList.copyOf(audioProcessors);
|
||||||
this.videoEffects = ImmutableList.copyOf(videoEffects);
|
this.videoEffects = ImmutableList.copyOf(videoEffects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an interlinked {@linkplain AudioProcessor audio processor} and {@linkplain Effect video
|
||||||
|
* effect} that changes the speed to media samples in segments of the input file specified by the
|
||||||
|
* given {@link SpeedProvider}.
|
||||||
|
*
|
||||||
|
* <p>The {@linkplain AudioProcessor audio processor} and {@linkplain Effect video effect} are
|
||||||
|
* interlinked to help maintain A/V sync. When using Transformer, if the input file doesn't have
|
||||||
|
* audio, or audio is being removed, you may have to {@linkplain
|
||||||
|
* Composition.Builder#experimentalSetForceAudioTrack force an audio track} for the interlinked
|
||||||
|
* effects to function correctly. Alternatively, you can use {@link SpeedChangeEffect} when input
|
||||||
|
* has no audio.
|
||||||
|
*
|
||||||
|
* @param speedProvider The {@link SpeedProvider} determining the speed for the media at specific
|
||||||
|
* timestamps.
|
||||||
|
*/
|
||||||
|
public static Pair<AudioProcessor, Effect> createExperimentalSpeedChangingEffect(
|
||||||
|
SpeedProvider speedProvider) {
|
||||||
|
SpeedChangingAudioProcessor speedChangingAudioProcessor =
|
||||||
|
new SpeedChangingAudioProcessor(speedProvider);
|
||||||
|
Effect audioDrivenvideoEffect =
|
||||||
|
new TimestampAdjustment(speedChangingAudioProcessor::getSpeedAdjustedTimeAsync);
|
||||||
|
return Pair.create(speedChangingAudioProcessor, audioDrivenvideoEffect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user