Apply playback parameters in a consistent way.
Currently, we sometimes apply new playback parameters directly and sometimes
through the list of playbackParameterCheckpoints. Only when using the checkpoints,
we also reset the offset and corresponding position for speedup position
calculation. However, these offsets need to be changed in all cases to prevent
calculation errors during speedup calculation[1].
This change channels all playback parameters changes through the checkpoints to
ensure the offsets get updated accordingly. This fixes an issue introduced in
31911ca54a
.
[1] - The speed up is calculated using the ratio of input and output bytes in
SonicAudioProcessor.scaleDurationForSpeedUp. Whenever we set new playback
parameters to the audio processor these two counts are reset. If we don't reset
the offsets too, the scaled timestamp can be a large value compared to the input
and output bytes causing massive inaccuracies (like the +20 seconds in the
linked issue).
Issue:#6117
PiperOrigin-RevId: 256533780
This commit is contained in:
parent
1d766c4603
commit
dbabb7c9a3
@ -7,6 +7,8 @@
|
||||
* Audio:
|
||||
* Fix an issue where not all audio was played out when the configuration
|
||||
for the underlying track was changing (e.g., at some period transitions).
|
||||
* Fix an issue where playback speed was applied inaccurately in playlists
|
||||
([#6117](https://github.com/google/ExoPlayer/issues/6117)).
|
||||
* UI: Fix `PlayerView` incorrectly consuming touch events if no controller is
|
||||
attached ([#6109](https://github.com/google/ExoPlayer/issues/6133)).
|
||||
* CEA608: Fix repetition of special North American characters
|
||||
|
@ -501,7 +501,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() throws InitializationException {
|
||||
private void initialize(long presentationTimeUs) throws InitializationException {
|
||||
// If we're asynchronously releasing a previous audio track then we block until it has been
|
||||
// released. This guarantees that we cannot end up in a state where we have multiple audio
|
||||
// track instances. Without this guarantee it would be possible, in extreme cases, to exhaust
|
||||
@ -533,11 +533,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
}
|
||||
|
||||
playbackParameters =
|
||||
configuration.canApplyPlaybackParameters
|
||||
? audioProcessorChain.applyPlaybackParameters(playbackParameters)
|
||||
: PlaybackParameters.DEFAULT;
|
||||
setupAudioProcessors();
|
||||
applyPlaybackParameters(playbackParameters, presentationTimeUs);
|
||||
|
||||
audioTrackPositionTracker.setAudioTrack(
|
||||
audioTrack,
|
||||
@ -591,15 +587,12 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
configuration = pendingConfiguration;
|
||||
pendingConfiguration = null;
|
||||
}
|
||||
playbackParameters =
|
||||
configuration.canApplyPlaybackParameters
|
||||
? audioProcessorChain.applyPlaybackParameters(playbackParameters)
|
||||
: PlaybackParameters.DEFAULT;
|
||||
setupAudioProcessors();
|
||||
// Re-apply playback parameters.
|
||||
applyPlaybackParameters(playbackParameters, presentationTimeUs);
|
||||
}
|
||||
|
||||
if (!isInitialized()) {
|
||||
initialize();
|
||||
initialize(presentationTimeUs);
|
||||
if (playing) {
|
||||
play();
|
||||
}
|
||||
@ -635,15 +628,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
PlaybackParameters newPlaybackParameters = afterDrainPlaybackParameters;
|
||||
afterDrainPlaybackParameters = null;
|
||||
newPlaybackParameters = audioProcessorChain.applyPlaybackParameters(newPlaybackParameters);
|
||||
// Store the position and corresponding media time from which the parameters will apply.
|
||||
playbackParametersCheckpoints.add(
|
||||
new PlaybackParametersCheckpoint(
|
||||
newPlaybackParameters,
|
||||
Math.max(0, presentationTimeUs),
|
||||
configuration.framesToDurationUs(getWrittenFrames())));
|
||||
// Update the set of active audio processors to take into account the new parameters.
|
||||
setupAudioProcessors();
|
||||
applyPlaybackParameters(newPlaybackParameters, presentationTimeUs);
|
||||
}
|
||||
|
||||
if (startMediaTimeState == START_NOT_SET) {
|
||||
@ -857,8 +842,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
// parameters apply.
|
||||
afterDrainPlaybackParameters = playbackParameters;
|
||||
} else {
|
||||
// Update the playback parameters now.
|
||||
this.playbackParameters = audioProcessorChain.applyPlaybackParameters(playbackParameters);
|
||||
// Update the playback parameters now. They will be applied to the audio processors during
|
||||
// initialization.
|
||||
this.playbackParameters = playbackParameters;
|
||||
}
|
||||
}
|
||||
return this.playbackParameters;
|
||||
@ -1040,6 +1026,21 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void applyPlaybackParameters(
|
||||
PlaybackParameters playbackParameters, long presentationTimeUs) {
|
||||
PlaybackParameters newPlaybackParameters =
|
||||
configuration.canApplyPlaybackParameters
|
||||
? audioProcessorChain.applyPlaybackParameters(playbackParameters)
|
||||
: PlaybackParameters.DEFAULT;
|
||||
// Store the position and corresponding media time from which the parameters will apply.
|
||||
playbackParametersCheckpoints.add(
|
||||
new PlaybackParametersCheckpoint(
|
||||
newPlaybackParameters,
|
||||
/* mediaTimeUs= */ Math.max(0, presentationTimeUs),
|
||||
/* positionUs= */ configuration.framesToDurationUs(getWrittenFrames())));
|
||||
setupAudioProcessors();
|
||||
}
|
||||
|
||||
private long applySpeedup(long positionUs) {
|
||||
@Nullable PlaybackParametersCheckpoint checkpoint = null;
|
||||
while (!playbackParametersCheckpoints.isEmpty()
|
||||
|
Loading…
x
Reference in New Issue
Block a user