PiperOrigin-RevId: 702960045
This commit is contained in:
Googler 2024-12-04 20:33:19 -08:00 committed by Copybara-Service
parent f60d2b4146
commit 5ab9a7856f
5 changed files with 53 additions and 67 deletions

View file

@ -36,8 +36,6 @@
([#1904](https://github.com/androidx/media/issues/1904)).
* DataSource:
* Audio:
* Do not bypass `SonicAudioProcessor` when `SpeedChangingAudioProcessor`
is configured with default parameters.
* Video:
* Rollback of using `MediaCodecAdapter` supplied pixel aspect ratio values
when provided while processing `onOutputFormatChanged`

View file

@ -15,11 +15,8 @@
*/
package androidx.media3.common.audio;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.Math.abs;
import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
@ -47,8 +44,6 @@ public class SonicAudioProcessor implements AudioProcessor {
*/
private static final int MIN_BYTES_FOR_DURATION_SCALING_CALCULATION = 1024;
private final boolean shouldBeActiveWithDefaultParameters;
private int pendingOutputSampleRate;
private float speed;
private float pitch;
@ -69,17 +64,6 @@ public class SonicAudioProcessor implements AudioProcessor {
/** Creates a new Sonic audio processor. */
public SonicAudioProcessor() {
this(/* keepActiveWithDefaultParameters= */ false);
}
/**
* Creates a new instance of {@link SonicAudioProcessor}.
*
* <p>If {@code keepActiveWithDefaultParameters} is set to {@code true}, then {@link #isActive()}
* returns {@code true} when parameters have been configured to default values that result in
* no-op processing.
*/
/* package */ SonicAudioProcessor(boolean keepActiveWithDefaultParameters) {
speed = 1f;
pitch = 1f;
pendingInputAudioFormat = AudioFormat.NOT_SET;
@ -90,7 +74,6 @@ public class SonicAudioProcessor implements AudioProcessor {
shortBuffer = buffer.asShortBuffer();
outputBuffer = EMPTY_BUFFER;
pendingOutputSampleRate = SAMPLE_RATE_NO_CHANGE;
shouldBeActiveWithDefaultParameters = keepActiveWithDefaultParameters;
}
/**
@ -100,8 +83,7 @@ public class SonicAudioProcessor implements AudioProcessor {
*
* @param speed The target factor by which playback should be sped up.
*/
public final void setSpeed(@FloatRange(from = 0f, fromInclusive = false) float speed) {
checkArgument(speed > 0f);
public final void setSpeed(float speed) {
if (this.speed != speed) {
this.speed = speed;
pendingSonicRecreation = true;
@ -115,8 +97,7 @@ public class SonicAudioProcessor implements AudioProcessor {
*
* @param pitch The target pitch.
*/
public final void setPitch(@FloatRange(from = 0f, fromInclusive = false) float pitch) {
checkArgument(pitch > 0f);
public final void setPitch(float pitch) {
if (this.pitch != pitch) {
this.pitch = pitch;
pendingSonicRecreation = true;
@ -132,7 +113,6 @@ public class SonicAudioProcessor implements AudioProcessor {
* @see #configure(AudioFormat)
*/
public final void setOutputSampleRateHz(int sampleRateHz) {
checkArgument(sampleRateHz == SAMPLE_RATE_NO_CHANGE || sampleRateHz > 0);
pendingOutputSampleRate = sampleRateHz;
}
@ -216,13 +196,9 @@ public class SonicAudioProcessor implements AudioProcessor {
@Override
public final boolean isActive() {
return pendingOutputAudioFormat.sampleRate != Format.NO_VALUE
&& (shouldBeActiveWithDefaultParameters || !areParametersSetToDefaultValues());
}
private boolean areParametersSetToDefaultValues() {
return abs(speed - 1f) < CLOSE_THRESHOLD
&& abs(pitch - 1f) < CLOSE_THRESHOLD
&& pendingOutputAudioFormat.sampleRate == pendingInputAudioFormat.sampleRate;
&& (Math.abs(speed - 1f) >= CLOSE_THRESHOLD
|| Math.abs(pitch - 1f) >= CLOSE_THRESHOLD
|| pendingOutputAudioFormat.sampleRate != pendingInputAudioFormat.sampleRate);
}
@Override

View file

@ -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;
@ -100,8 +99,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
public SpeedChangingAudioProcessor(SpeedProvider speedProvider) {
this.speedProvider = speedProvider;
lock = new Object();
sonicAudioProcessor =
new SynchronizedSonicAudioProcessor(lock, /* keepActiveWithDefaultParameters= */ true);
sonicAudioProcessor = new SynchronizedSonicAudioProcessor(lock);
pendingCallbackInputTimesUs = new LongArrayQueue();
pendingCallbacks = new ArrayDeque<>();
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
@ -176,11 +174,19 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
}
long startPosition = inputBuffer.position();
sonicAudioProcessor.queueInput(inputBuffer);
if (bytesToNextSpeedChange != C.LENGTH_UNSET
&& (inputBuffer.position() - startPosition) == bytesToNextSpeedChange) {
sonicAudioProcessor.queueEndOfStream();
endOfStreamQueuedToSonic = true;
if (isUsingSonic()) {
sonicAudioProcessor.queueInput(inputBuffer);
if (bytesToNextSpeedChange != C.LENGTH_UNSET
&& (inputBuffer.position() - startPosition) == bytesToNextSpeedChange) {
sonicAudioProcessor.queueEndOfStream();
endOfStreamQueuedToSonic = true;
}
} else {
ByteBuffer buffer = replaceOutputBuffer(/* size= */ inputBuffer.remaining());
if (inputBuffer.hasRemaining()) {
buffer.put(inputBuffer);
}
buffer.flip();
}
long bytesRead = inputBuffer.position() - startPosition;
checkState(
@ -198,11 +204,9 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
}
}
// Not using BaseAudioProcessor's buffers.
@SuppressLint("MissingSuperCall")
@Override
public ByteBuffer getOutput() {
ByteBuffer output = sonicAudioProcessor.getOutput();
ByteBuffer output = isUsingSonic() ? sonicAudioProcessor.getOutput() : super.getOutput();
processPendingCallbacks();
return output;
}
@ -347,8 +351,10 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
if (newSpeed != currentSpeed) {
updateSpeedChangeArrays(timeUs);
currentSpeed = newSpeed;
sonicAudioProcessor.setSpeed(newSpeed);
sonicAudioProcessor.setPitch(newSpeed);
if (isUsingSonic()) {
sonicAudioProcessor.setSpeed(newSpeed);
sonicAudioProcessor.setPitch(newSpeed);
}
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
sonicAudioProcessor.flush();
endOfStreamQueuedToSonic = false;
@ -372,25 +378,39 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
}
private long getPlayoutDurationUsAtCurrentSpeed(long mediaDurationUs) {
return sonicAudioProcessor.getPlayoutDuration(mediaDurationUs);
return isUsingSonic()
? sonicAudioProcessor.getPlayoutDuration(mediaDurationUs)
: mediaDurationUs;
}
private long getMediaDurationUsAtCurrentSpeed(long playoutDurationUs) {
return sonicAudioProcessor.getMediaDuration(playoutDurationUs);
return isUsingSonic()
? sonicAudioProcessor.getMediaDuration(playoutDurationUs)
: playoutDurationUs;
}
private void updateLastProcessedInputTime() {
synchronized (lock) {
// TODO - b/320242819: Investigate whether bytesRead can be used here rather than
// sonicAudioProcessor.getProcessedInputBytes().
long currentProcessedInputDurationUs =
Util.scaleLargeTimestamp(
/* timestamp= */ sonicAudioProcessor.getProcessedInputBytes(),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ (long) inputAudioFormat.sampleRate * inputAudioFormat.bytesPerFrame);
lastProcessedInputTimeUs =
inputSegmentStartTimesUs.get(inputSegmentStartTimesUs.size() - 1)
+ currentProcessedInputDurationUs;
if (isUsingSonic()) {
// TODO - b/320242819: Investigate whether bytesRead can be used here rather than
// sonicAudioProcessor.getProcessedInputBytes().
long currentProcessedInputDurationUs =
Util.scaleLargeTimestamp(
/* timestamp= */ sonicAudioProcessor.getProcessedInputBytes(),
/* multiplier= */ C.MICROS_PER_SECOND,
/* divisor= */ (long) inputAudioFormat.sampleRate * inputAudioFormat.bytesPerFrame);
lastProcessedInputTimeUs =
inputSegmentStartTimesUs.get(inputSegmentStartTimesUs.size() - 1)
+ currentProcessedInputDurationUs;
} else {
lastProcessedInputTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate);
}
}
}
private boolean isUsingSonic() {
synchronized (lock) {
return currentSpeed != 1f;
}
}

View file

@ -26,9 +26,9 @@ import java.nio.ByteBuffer;
private final Object lock;
private final SonicAudioProcessor sonicAudioProcessor;
public SynchronizedSonicAudioProcessor(Object lock, boolean keepActiveWithDefaultParameters) {
public SynchronizedSonicAudioProcessor(Object lock) {
this.lock = lock;
sonicAudioProcessor = new SonicAudioProcessor(keepActiveWithDefaultParameters);
sonicAudioProcessor = new SonicAudioProcessor();
}
public final void setSpeed(float speed) {

View file

@ -86,19 +86,11 @@ public final class SonicAudioProcessorTest {
}
@Test
public void isActive_withDefaultParameters_returnsFalse() throws Exception {
public void isNotActiveWithNoChange() throws Exception {
sonicAudioProcessor.configure(AUDIO_FORMAT_44100_HZ);
assertThat(sonicAudioProcessor.isActive()).isFalse();
}
@Test
public void isActive_keepActiveWithDefaultParameters_returnsTrue() throws Exception {
SonicAudioProcessor processor =
new SonicAudioProcessor(/* keepActiveWithDefaultParameters= */ true);
processor.configure(AUDIO_FORMAT_44100_HZ);
assertThat(processor.isActive()).isTrue();
}
@Test
public void doesNotSupportNon16BitInput() throws Exception {
try {