Use BaseAudioProcessor format tracking in SilenceSkippingAudioProcessor
The class currently tracks the input format itself, updating it too early in onConfigure() instead of onFlush(). This causes issues when the format changes and the new values are applied to the silence skipping logic of the old format. The fix is to use the base class input format handling instead. Issue: androidx/media#1352 PiperOrigin-RevId: 633232368
This commit is contained in:
parent
04ab71a1d4
commit
1a5cf6718b
@ -51,6 +51,10 @@
|
||||
in `DefaultAudioSink` prior to calling `AudioTrack.stop()` so that
|
||||
`AudioTrack.StreamEventCallback#onPresentationEnded` correctly
|
||||
identifies when all pending data has been played.
|
||||
* Fix bug in `SilenceSkippingAudioProcessor` where transitions between
|
||||
different audio formats (for example stereo to mono) can cause the
|
||||
processor to throw an exception
|
||||
([#1352](https://github.com/androidx/media/issues/1352)).
|
||||
* Video:
|
||||
* Text:
|
||||
* Fix issue where subtitles starting before a seek position are skipped.
|
||||
|
@ -57,6 +57,7 @@ public abstract class BaseAudioProcessor implements AudioProcessor {
|
||||
return isActive() ? pendingOutputAudioFormat : AudioFormat.NOT_SET;
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return pendingOutputAudioFormat != AudioFormat.NOT_SET;
|
||||
|
@ -146,7 +146,6 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
|
||||
*/
|
||||
private final long maxSilenceToKeepDurationUs;
|
||||
|
||||
private AudioFormat inputFormat;
|
||||
private int bytesPerFrame;
|
||||
private boolean enabled;
|
||||
private @State int state;
|
||||
@ -236,7 +235,6 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
|
||||
this.maxSilenceToKeepDurationUs = maxSilenceToKeepDurationUs;
|
||||
this.minVolumeToKeepPercentageWhenMuting = minVolumeToKeepPercentageWhenMuting;
|
||||
this.silenceThresholdLevel = silenceThresholdLevel;
|
||||
inputFormat = AudioFormat.NOT_SET;
|
||||
maybeSilenceBuffer = Util.EMPTY_BYTE_ARRAY;
|
||||
contiguousOutputBuffer = Util.EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
@ -266,14 +264,15 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
|
||||
if (inputAudioFormat.encoding != C.ENCODING_PCM_16BIT) {
|
||||
throw new UnhandledAudioFormatException(inputAudioFormat);
|
||||
}
|
||||
this.inputFormat = inputAudioFormat;
|
||||
bytesPerFrame = inputAudioFormat.channelCount * 2;
|
||||
if (inputAudioFormat.sampleRate == Format.NO_VALUE) {
|
||||
return AudioFormat.NOT_SET;
|
||||
}
|
||||
return inputAudioFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return inputFormat.sampleRate != Format.NO_VALUE && enabled;
|
||||
return super.isActive() && enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -307,6 +306,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
|
||||
@Override
|
||||
public void onFlush() {
|
||||
if (isActive()) {
|
||||
bytesPerFrame = inputAudioFormat.channelCount * 2;
|
||||
// Divide by 2 to allow the buffer to be split into two bytesPerFrame aligned parts.
|
||||
int maybeSilenceBufferSize =
|
||||
alignToBytePerFrameBoundary(durationUsToFrames(minimumSilenceDurationUs) / 2) * 2;
|
||||
@ -325,7 +325,6 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
|
||||
@Override
|
||||
public void onReset() {
|
||||
enabled = false;
|
||||
inputFormat = AudioFormat.NOT_SET;
|
||||
maybeSilenceBuffer = Util.EMPTY_BYTE_ARRAY;
|
||||
contiguousOutputBuffer = Util.EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
@ -711,7 +710,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
|
||||
* Returns the number of input frames corresponding to {@code durationUs} microseconds of audio.
|
||||
*/
|
||||
private int durationUsToFrames(long durationUs) {
|
||||
return (int) ((durationUs * inputFormat.sampleRate) / C.MICROS_PER_SECOND);
|
||||
return (int) ((durationUs * inputAudioFormat.sampleRate) / C.MICROS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,6 +177,35 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
.isEqualTo(TEST_SIGNAL_FRAME_COUNT - totalOutputFrames);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
skipInAlternatingTestSignal_withEarlyConfigureForNextFormat_hasCorrectOutputAndSkippedFrameCounts()
|
||||
throws Exception {
|
||||
// Given a signal that alternates between silence and noise.
|
||||
InputBufferProvider inputBufferProvider =
|
||||
getInputBufferProviderForAlternatingSilenceAndNoise(
|
||||
TEST_SIGNAL_SILENCE_DURATION_MS,
|
||||
TEST_SIGNAL_NOISE_DURATION_MS,
|
||||
TEST_SIGNAL_FRAME_COUNT);
|
||||
SilenceSkippingAudioProcessor silenceSkippingAudioProcessor =
|
||||
new SilenceSkippingAudioProcessor();
|
||||
silenceSkippingAudioProcessor.setEnabled(true);
|
||||
silenceSkippingAudioProcessor.configure(AUDIO_FORMAT);
|
||||
silenceSkippingAudioProcessor.flush();
|
||||
|
||||
// Early configure the next format without flushing yet (this format should be ignored).
|
||||
silenceSkippingAudioProcessor.configure(
|
||||
new AudioFormat(
|
||||
/* sampleRate= */ 1000, /* channelCount= */ 1, /* encoding= */ C.ENCODING_PCM_16BIT));
|
||||
long totalOutputFrames =
|
||||
process(silenceSkippingAudioProcessor, inputBufferProvider, INPUT_BUFFER_SIZE);
|
||||
|
||||
// The output has 50000 frames of noise, plus 50 * 0.2 * 1000 padding (plus rounding errors).
|
||||
assertThat(totalOutputFrames).isIn(Range.closed(60000L - 500L, 60000L + 500L));
|
||||
assertThat(silenceSkippingAudioProcessor.getSkippedFrames())
|
||||
.isEqualTo(TEST_SIGNAL_FRAME_COUNT - totalOutputFrames);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipWithSmallerInputBufferSize_hasCorrectOutputAndSkippedFrameCounts()
|
||||
throws Exception {
|
||||
@ -291,7 +320,6 @@ public final class SilenceSkippingAudioProcessorTest {
|
||||
InputBufferProvider inputBufferProvider,
|
||||
int inputBufferSize) {
|
||||
int bytesPerFrame = AUDIO_FORMAT.bytesPerFrame;
|
||||
processor.flush();
|
||||
long totalOutputFrames = 0;
|
||||
while (inputBufferProvider.hasRemaining()) {
|
||||
ByteBuffer inputBuffer = inputBufferProvider.getNextInputBuffer(inputBufferSize);
|
||||
|
Loading…
x
Reference in New Issue
Block a user