mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
parent
f60d2b4146
commit
5ab9a7856f
5 changed files with 53 additions and 67 deletions
|
|
@ -36,8 +36,6 @@
|
||||||
([#1904](https://github.com/androidx/media/issues/1904)).
|
([#1904](https://github.com/androidx/media/issues/1904)).
|
||||||
* DataSource:
|
* DataSource:
|
||||||
* Audio:
|
* Audio:
|
||||||
* Do not bypass `SonicAudioProcessor` when `SpeedChangingAudioProcessor`
|
|
||||||
is configured with default parameters.
|
|
||||||
* Video:
|
* Video:
|
||||||
* Rollback of using `MediaCodecAdapter` supplied pixel aspect ratio values
|
* Rollback of using `MediaCodecAdapter` supplied pixel aspect ratio values
|
||||||
when provided while processing `onOutputFormatChanged`
|
when provided while processing `onOutputFormatChanged`
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package androidx.media3.common.audio;
|
package androidx.media3.common.audio;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static java.lang.Math.abs;
|
|
||||||
|
|
||||||
import androidx.annotation.FloatRange;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
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 static final int MIN_BYTES_FOR_DURATION_SCALING_CALCULATION = 1024;
|
||||||
|
|
||||||
private final boolean shouldBeActiveWithDefaultParameters;
|
|
||||||
|
|
||||||
private int pendingOutputSampleRate;
|
private int pendingOutputSampleRate;
|
||||||
private float speed;
|
private float speed;
|
||||||
private float pitch;
|
private float pitch;
|
||||||
|
|
@ -69,17 +64,6 @@ public class SonicAudioProcessor implements AudioProcessor {
|
||||||
|
|
||||||
/** Creates a new Sonic audio processor. */
|
/** Creates a new Sonic audio processor. */
|
||||||
public SonicAudioProcessor() {
|
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;
|
speed = 1f;
|
||||||
pitch = 1f;
|
pitch = 1f;
|
||||||
pendingInputAudioFormat = AudioFormat.NOT_SET;
|
pendingInputAudioFormat = AudioFormat.NOT_SET;
|
||||||
|
|
@ -90,7 +74,6 @@ public class SonicAudioProcessor implements AudioProcessor {
|
||||||
shortBuffer = buffer.asShortBuffer();
|
shortBuffer = buffer.asShortBuffer();
|
||||||
outputBuffer = EMPTY_BUFFER;
|
outputBuffer = EMPTY_BUFFER;
|
||||||
pendingOutputSampleRate = SAMPLE_RATE_NO_CHANGE;
|
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.
|
* @param speed The target factor by which playback should be sped up.
|
||||||
*/
|
*/
|
||||||
public final void setSpeed(@FloatRange(from = 0f, fromInclusive = false) float speed) {
|
public final void setSpeed(float speed) {
|
||||||
checkArgument(speed > 0f);
|
|
||||||
if (this.speed != speed) {
|
if (this.speed != speed) {
|
||||||
this.speed = speed;
|
this.speed = speed;
|
||||||
pendingSonicRecreation = true;
|
pendingSonicRecreation = true;
|
||||||
|
|
@ -115,8 +97,7 @@ public class SonicAudioProcessor implements AudioProcessor {
|
||||||
*
|
*
|
||||||
* @param pitch The target pitch.
|
* @param pitch The target pitch.
|
||||||
*/
|
*/
|
||||||
public final void setPitch(@FloatRange(from = 0f, fromInclusive = false) float pitch) {
|
public final void setPitch(float pitch) {
|
||||||
checkArgument(pitch > 0f);
|
|
||||||
if (this.pitch != pitch) {
|
if (this.pitch != pitch) {
|
||||||
this.pitch = pitch;
|
this.pitch = pitch;
|
||||||
pendingSonicRecreation = true;
|
pendingSonicRecreation = true;
|
||||||
|
|
@ -132,7 +113,6 @@ public class SonicAudioProcessor implements AudioProcessor {
|
||||||
* @see #configure(AudioFormat)
|
* @see #configure(AudioFormat)
|
||||||
*/
|
*/
|
||||||
public final void setOutputSampleRateHz(int sampleRateHz) {
|
public final void setOutputSampleRateHz(int sampleRateHz) {
|
||||||
checkArgument(sampleRateHz == SAMPLE_RATE_NO_CHANGE || sampleRateHz > 0);
|
|
||||||
pendingOutputSampleRate = sampleRateHz;
|
pendingOutputSampleRate = sampleRateHz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,13 +196,9 @@ public class SonicAudioProcessor implements AudioProcessor {
|
||||||
@Override
|
@Override
|
||||||
public final boolean isActive() {
|
public final boolean isActive() {
|
||||||
return pendingOutputAudioFormat.sampleRate != Format.NO_VALUE
|
return pendingOutputAudioFormat.sampleRate != Format.NO_VALUE
|
||||||
&& (shouldBeActiveWithDefaultParameters || !areParametersSetToDefaultValues());
|
&& (Math.abs(speed - 1f) >= CLOSE_THRESHOLD
|
||||||
}
|
|| Math.abs(pitch - 1f) >= CLOSE_THRESHOLD
|
||||||
|
|| pendingOutputAudioFormat.sampleRate != pendingInputAudioFormat.sampleRate);
|
||||||
private boolean areParametersSetToDefaultValues() {
|
|
||||||
return abs(speed - 1f) < CLOSE_THRESHOLD
|
|
||||||
&& abs(pitch - 1f) < CLOSE_THRESHOLD
|
|
||||||
&& pendingOutputAudioFormat.sampleRate == pendingInputAudioFormat.sampleRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import static androidx.media3.common.util.Util.sampleCountToDurationUs;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
import static java.lang.Math.round;
|
import static java.lang.Math.round;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import androidx.annotation.GuardedBy;
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.IntRange;
|
import androidx.annotation.IntRange;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
|
|
@ -100,8 +99,7 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||||
public SpeedChangingAudioProcessor(SpeedProvider speedProvider) {
|
public SpeedChangingAudioProcessor(SpeedProvider speedProvider) {
|
||||||
this.speedProvider = speedProvider;
|
this.speedProvider = speedProvider;
|
||||||
lock = new Object();
|
lock = new Object();
|
||||||
sonicAudioProcessor =
|
sonicAudioProcessor = new SynchronizedSonicAudioProcessor(lock);
|
||||||
new SynchronizedSonicAudioProcessor(lock, /* keepActiveWithDefaultParameters= */ true);
|
|
||||||
pendingCallbackInputTimesUs = new LongArrayQueue();
|
pendingCallbackInputTimesUs = new LongArrayQueue();
|
||||||
pendingCallbacks = new ArrayDeque<>();
|
pendingCallbacks = new ArrayDeque<>();
|
||||||
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
|
speedAdjustedTimeAsyncInputTimeUs = C.TIME_UNSET;
|
||||||
|
|
@ -176,11 +174,19 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
long startPosition = inputBuffer.position();
|
long startPosition = inputBuffer.position();
|
||||||
sonicAudioProcessor.queueInput(inputBuffer);
|
if (isUsingSonic()) {
|
||||||
if (bytesToNextSpeedChange != C.LENGTH_UNSET
|
sonicAudioProcessor.queueInput(inputBuffer);
|
||||||
&& (inputBuffer.position() - startPosition) == bytesToNextSpeedChange) {
|
if (bytesToNextSpeedChange != C.LENGTH_UNSET
|
||||||
sonicAudioProcessor.queueEndOfStream();
|
&& (inputBuffer.position() - startPosition) == bytesToNextSpeedChange) {
|
||||||
endOfStreamQueuedToSonic = true;
|
sonicAudioProcessor.queueEndOfStream();
|
||||||
|
endOfStreamQueuedToSonic = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ByteBuffer buffer = replaceOutputBuffer(/* size= */ inputBuffer.remaining());
|
||||||
|
if (inputBuffer.hasRemaining()) {
|
||||||
|
buffer.put(inputBuffer);
|
||||||
|
}
|
||||||
|
buffer.flip();
|
||||||
}
|
}
|
||||||
long bytesRead = inputBuffer.position() - startPosition;
|
long bytesRead = inputBuffer.position() - startPosition;
|
||||||
checkState(
|
checkState(
|
||||||
|
|
@ -198,11 +204,9 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not using BaseAudioProcessor's buffers.
|
|
||||||
@SuppressLint("MissingSuperCall")
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer getOutput() {
|
public ByteBuffer getOutput() {
|
||||||
ByteBuffer output = sonicAudioProcessor.getOutput();
|
ByteBuffer output = isUsingSonic() ? sonicAudioProcessor.getOutput() : super.getOutput();
|
||||||
processPendingCallbacks();
|
processPendingCallbacks();
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
@ -347,8 +351,10 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||||
if (newSpeed != currentSpeed) {
|
if (newSpeed != currentSpeed) {
|
||||||
updateSpeedChangeArrays(timeUs);
|
updateSpeedChangeArrays(timeUs);
|
||||||
currentSpeed = newSpeed;
|
currentSpeed = newSpeed;
|
||||||
sonicAudioProcessor.setSpeed(newSpeed);
|
if (isUsingSonic()) {
|
||||||
sonicAudioProcessor.setPitch(newSpeed);
|
sonicAudioProcessor.setSpeed(newSpeed);
|
||||||
|
sonicAudioProcessor.setPitch(newSpeed);
|
||||||
|
}
|
||||||
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
|
// Invalidate any previously created buffers in SonicAudioProcessor and the base class.
|
||||||
sonicAudioProcessor.flush();
|
sonicAudioProcessor.flush();
|
||||||
endOfStreamQueuedToSonic = false;
|
endOfStreamQueuedToSonic = false;
|
||||||
|
|
@ -372,25 +378,39 @@ public final class SpeedChangingAudioProcessor extends BaseAudioProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getPlayoutDurationUsAtCurrentSpeed(long mediaDurationUs) {
|
private long getPlayoutDurationUsAtCurrentSpeed(long mediaDurationUs) {
|
||||||
return sonicAudioProcessor.getPlayoutDuration(mediaDurationUs);
|
return isUsingSonic()
|
||||||
|
? sonicAudioProcessor.getPlayoutDuration(mediaDurationUs)
|
||||||
|
: mediaDurationUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getMediaDurationUsAtCurrentSpeed(long playoutDurationUs) {
|
private long getMediaDurationUsAtCurrentSpeed(long playoutDurationUs) {
|
||||||
return sonicAudioProcessor.getMediaDuration(playoutDurationUs);
|
return isUsingSonic()
|
||||||
|
? sonicAudioProcessor.getMediaDuration(playoutDurationUs)
|
||||||
|
: playoutDurationUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLastProcessedInputTime() {
|
private void updateLastProcessedInputTime() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
// TODO - b/320242819: Investigate whether bytesRead can be used here rather than
|
if (isUsingSonic()) {
|
||||||
// sonicAudioProcessor.getProcessedInputBytes().
|
// TODO - b/320242819: Investigate whether bytesRead can be used here rather than
|
||||||
long currentProcessedInputDurationUs =
|
// sonicAudioProcessor.getProcessedInputBytes().
|
||||||
Util.scaleLargeTimestamp(
|
long currentProcessedInputDurationUs =
|
||||||
/* timestamp= */ sonicAudioProcessor.getProcessedInputBytes(),
|
Util.scaleLargeTimestamp(
|
||||||
/* multiplier= */ C.MICROS_PER_SECOND,
|
/* timestamp= */ sonicAudioProcessor.getProcessedInputBytes(),
|
||||||
/* divisor= */ (long) inputAudioFormat.sampleRate * inputAudioFormat.bytesPerFrame);
|
/* multiplier= */ C.MICROS_PER_SECOND,
|
||||||
lastProcessedInputTimeUs =
|
/* divisor= */ (long) inputAudioFormat.sampleRate * inputAudioFormat.bytesPerFrame);
|
||||||
inputSegmentStartTimesUs.get(inputSegmentStartTimesUs.size() - 1)
|
lastProcessedInputTimeUs =
|
||||||
+ currentProcessedInputDurationUs;
|
inputSegmentStartTimesUs.get(inputSegmentStartTimesUs.size() - 1)
|
||||||
|
+ currentProcessedInputDurationUs;
|
||||||
|
} else {
|
||||||
|
lastProcessedInputTimeUs = sampleCountToDurationUs(framesRead, inputAudioFormat.sampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsingSonic() {
|
||||||
|
synchronized (lock) {
|
||||||
|
return currentSpeed != 1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ import java.nio.ByteBuffer;
|
||||||
private final Object lock;
|
private final Object lock;
|
||||||
private final SonicAudioProcessor sonicAudioProcessor;
|
private final SonicAudioProcessor sonicAudioProcessor;
|
||||||
|
|
||||||
public SynchronizedSonicAudioProcessor(Object lock, boolean keepActiveWithDefaultParameters) {
|
public SynchronizedSonicAudioProcessor(Object lock) {
|
||||||
this.lock = lock;
|
this.lock = lock;
|
||||||
sonicAudioProcessor = new SonicAudioProcessor(keepActiveWithDefaultParameters);
|
sonicAudioProcessor = new SonicAudioProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setSpeed(float speed) {
|
public final void setSpeed(float speed) {
|
||||||
|
|
|
||||||
|
|
@ -86,19 +86,11 @@ public final class SonicAudioProcessorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isActive_withDefaultParameters_returnsFalse() throws Exception {
|
public void isNotActiveWithNoChange() throws Exception {
|
||||||
sonicAudioProcessor.configure(AUDIO_FORMAT_44100_HZ);
|
sonicAudioProcessor.configure(AUDIO_FORMAT_44100_HZ);
|
||||||
assertThat(sonicAudioProcessor.isActive()).isFalse();
|
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
|
@Test
|
||||||
public void doesNotSupportNon16BitInput() throws Exception {
|
public void doesNotSupportNon16BitInput() throws Exception {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue