PiperOrigin-RevId: 702943864
This commit is contained in:
Googler 2024-12-04 19:19:39 -08:00 committed by Copybara-Service
parent 6193f7c38f
commit f60d2b4146
2 changed files with 21 additions and 61 deletions

View file

@ -24,6 +24,7 @@ import static androidx.media3.common.util.Util.sampleCountToDurationUs;
import static java.lang.Math.min;
import static java.lang.Math.round;
import android.annotation.SuppressLint;
import androidx.annotation.GuardedBy;
import androidx.annotation.IntRange;
import androidx.media3.common.C;
@ -44,8 +45,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/**
* An {@link AudioProcessor} that changes the speed of audio samples depending on their timestamp.
*/
// TODO(b/288221200): Consider making the processor inactive and skipping it in the processor chain
// when speed is 1.
@UnstableApi
public final class SpeedChangingAudioProcessor implements AudioProcessor {
public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
private final Object lock;
@ -94,18 +97,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
private boolean endOfStreamQueuedToSonic;
/** The current input audio format. */
private AudioFormat inputAudioFormat;
private AudioFormat pendingInputAudioFormat;
private AudioFormat pendingOutputAudioFormat;
private boolean inputEnded;
public SpeedChangingAudioProcessor(SpeedProvider speedProvider) {
pendingInputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputAudioFormat = AudioFormat.NOT_SET;
this.speedProvider = speedProvider;
lock = new Object();
sonicAudioProcessor =
@ -113,7 +105,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
pendingCallbackInputTimesUs = new LongArrayQueue();
pendingCallbacks = new ArrayDeque<>();
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
resetInternalState();
resetState();
}
/** Returns the estimated number of samples output given the provided parameters. */
@ -152,23 +144,17 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
return outputSamples;
}
@Override
public AudioFormat configure(AudioFormat inputAudioFormat) throws UnhandledAudioFormatException {
pendingInputAudioFormat = inputAudioFormat;
pendingOutputAudioFormat = sonicAudioProcessor.configure(inputAudioFormat);
return pendingOutputAudioFormat;
}
@Override
public boolean isActive() {
return !pendingOutputAudioFormat.equals(AudioFormat.NOT_SET);
}
@Override
public long getDurationAfterProcessorApplied(long durationUs) {
return SpeedProviderUtil.getDurationAfterSpeedProviderApplied(speedProvider, durationUs);
}
@Override
public AudioFormat onConfigure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
return sonicAudioProcessor.configure(inputAudioFormat);
}
@Override
public void queueInput(ByteBuffer inputBuffer) {
long currentTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate);
@ -205,14 +191,15 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
}
@Override
public void queueEndOfStream() {
inputEnded = true;
protected void onQueueEndOfStream() {
if (!endOfStreamQueuedToSonic) {
sonicAudioProcessor.queueEndOfStream();
endOfStreamQueuedToSonic = true;
}
}
// Not using BaseAudioProcessor's buffers.
@SuppressLint("MissingSuperCall")
@Override
public ByteBuffer getOutput() {
ByteBuffer output = sonicAudioProcessor.getOutput();
@ -222,24 +209,18 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
@Override
public boolean isEnded() {
return inputEnded && sonicAudioProcessor.isEnded();
return super.isEnded() && sonicAudioProcessor.isEnded();
}
@Override
public void flush() {
inputEnded = false;
inputAudioFormat = pendingInputAudioFormat;
resetInternalState();
protected void onFlush() {
resetState();
sonicAudioProcessor.flush();
}
@Override
public void reset() {
flush();
pendingInputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputAudioFormat = AudioFormat.NOT_SET;
resetInternalState();
protected void onReset() {
resetState();
sonicAudioProcessor.reset();
}
@ -371,6 +352,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
sonicAudioProcessor.flush();
endOfStreamQueuedToSonic = false;
super.getOutput();
}
}
}
@ -414,7 +396,7 @@ public final class SpeedChangingAudioProcessor implements AudioProcessor {
@EnsuresNonNull({"inputSegmentStartTimesUs", "outputSegmentStartTimesUs"})
@RequiresNonNull("lock")
private void resetInternalState(@UnknownInitialization SpeedChangingAudioProcessor this) {
private void resetState(@UnknownInitialization SpeedChangingAudioProcessor this) {
synchronized (lock) {
inputSegmentStartTimesUs = new LongArray();
outputSegmentStartTimesUs = new LongArray();

View file

@ -701,28 +701,6 @@ public class SpeedChangingAudioProcessorTest {
/* speedProvider= */ null, AUDIO_FORMAT.sampleRate, /* inputSamples= */ 1000L));
}
@Test
public void isActive_beforeConfigure_returnsFalse() {
SpeedProvider speedProvider =
TestSpeedProvider.createWithFrameCounts(
AUDIO_FORMAT, /* frameCounts= */ new int[] {1000}, /* speeds= */ new float[] {2f});
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
assertThat(processor.isActive()).isFalse();
}
@Test
public void isActive_afterConfigure_returnsTrue()
throws AudioProcessor.UnhandledAudioFormatException {
SpeedProvider speedProvider =
TestSpeedProvider.createWithFrameCounts(
AUDIO_FORMAT, /* frameCounts= */ new int[] {1000}, /* speeds= */ new float[] {2f});
SpeedChangingAudioProcessor processor = new SpeedChangingAudioProcessor(speedProvider);
processor.configure(AUDIO_FORMAT);
assertThat(processor.isActive()).isTrue();
}
private static SpeedChangingAudioProcessor getConfiguredSpeedChangingAudioProcessor(
SpeedProvider speedProvider) throws AudioProcessor.UnhandledAudioFormatException {
SpeedChangingAudioProcessor speedChangingAudioProcessor =