mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Make SpeedChangingAudioProcessor direct subclass of AudioProcessor
This non-functional refactor inlines and simplifies the logic of `BaseAudioProcessor` used by `SpeedChangingAudioProcessor`, and makes the latter implement `AudioProcessor` directly. `SpeedChangingAudioProcessor` acts as a wrapper over `SonicAudioProcessor` and does not actually modify any samples, so it had very little use for the affordances provided by `BaseAudioProcessor`. PiperOrigin-RevId: 698342962
This commit is contained in:
parent
3c01500a4e
commit
66e8b53b43
@ -24,7 +24,6 @@ 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;
|
||||
@ -45,10 +44,8 @@ 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 extends BaseAudioProcessor {
|
||||
public final class SpeedChangingAudioProcessor implements AudioProcessor {
|
||||
|
||||
private final Object lock;
|
||||
|
||||
@ -97,7 +94,18 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
|
||||
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 =
|
||||
@ -105,7 +113,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
pendingCallbackInputTimesUs = new LongArrayQueue();
|
||||
pendingCallbacks = new ArrayDeque<>();
|
||||
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
|
||||
resetState();
|
||||
resetInternalState();
|
||||
}
|
||||
|
||||
/** Returns the estimated number of samples output given the provided parameters. */
|
||||
@ -145,14 +153,20 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDurationAfterProcessorApplied(long durationUs) {
|
||||
return SpeedProviderUtil.getDurationAfterSpeedProviderApplied(speedProvider, durationUs);
|
||||
public AudioFormat configure(AudioFormat inputAudioFormat) throws UnhandledAudioFormatException {
|
||||
pendingInputAudioFormat = inputAudioFormat;
|
||||
pendingOutputAudioFormat = sonicAudioProcessor.configure(inputAudioFormat);
|
||||
return pendingOutputAudioFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioFormat onConfigure(AudioFormat inputAudioFormat)
|
||||
throws UnhandledAudioFormatException {
|
||||
return sonicAudioProcessor.configure(inputAudioFormat);
|
||||
public boolean isActive() {
|
||||
return !pendingOutputAudioFormat.equals(AudioFormat.NOT_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDurationAfterProcessorApplied(long durationUs) {
|
||||
return SpeedProviderUtil.getDurationAfterSpeedProviderApplied(speedProvider, durationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -191,15 +205,14 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueueEndOfStream() {
|
||||
public void queueEndOfStream() {
|
||||
inputEnded = true;
|
||||
if (!endOfStreamQueuedToSonic) {
|
||||
sonicAudioProcessor.queueEndOfStream();
|
||||
endOfStreamQueuedToSonic = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not using BaseAudioProcessor's buffers.
|
||||
@SuppressLint("MissingSuperCall")
|
||||
@Override
|
||||
public ByteBuffer getOutput() {
|
||||
ByteBuffer output = sonicAudioProcessor.getOutput();
|
||||
@ -209,18 +222,24 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
|
||||
@Override
|
||||
public boolean isEnded() {
|
||||
return super.isEnded() && sonicAudioProcessor.isEnded();
|
||||
return inputEnded && sonicAudioProcessor.isEnded();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFlush() {
|
||||
resetState();
|
||||
public void flush() {
|
||||
inputEnded = false;
|
||||
inputAudioFormat = pendingInputAudioFormat;
|
||||
resetInternalState();
|
||||
sonicAudioProcessor.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
resetState();
|
||||
public void reset() {
|
||||
flush();
|
||||
pendingInputAudioFormat = AudioFormat.NOT_SET;
|
||||
pendingOutputAudioFormat = AudioFormat.NOT_SET;
|
||||
inputAudioFormat = AudioFormat.NOT_SET;
|
||||
resetInternalState();
|
||||
sonicAudioProcessor.reset();
|
||||
}
|
||||
|
||||
@ -352,7 +371,6 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
|
||||
sonicAudioProcessor.flush();
|
||||
endOfStreamQueuedToSonic = false;
|
||||
super.getOutput();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -396,7 +414,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||
|
||||
@EnsuresNonNull({"inputSegmentStartTimesUs", "outputSegmentStartTimesUs"})
|
||||
@RequiresNonNull("lock")
|
||||
private void resetState(@UnknownInitialization SpeedChangingAudioProcessor this) {
|
||||
private void resetInternalState(@UnknownInitialization SpeedChangingAudioProcessor this) {
|
||||
synchronized (lock) {
|
||||
inputSegmentStartTimesUs = new LongArray();
|
||||
outputSegmentStartTimesUs = new LongArray();
|
||||
|
@ -701,6 +701,28 @@ 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 =
|
||||
|
Loading…
x
Reference in New Issue
Block a user