Accumulate remainder in buffer duration calculations.

When dropping the remainder, the decoder and encoder timestamps start diverging after a few buffers when no speed changes are supposed to occur. Tracking the remainder keeps them in sync.

PiperOrigin-RevId: 408341074
This commit is contained in:
hschlueter 2021-11-08 15:52:01 +00:00 committed by tonihei
parent ba9ade1c8e
commit 9efa32e49b
2 changed files with 41 additions and 29 deletions

View File

@ -31,7 +31,9 @@ import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat; import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat;
import com.google.android.exoplayer2.audio.SonicAudioProcessor; import com.google.android.exoplayer2.audio.SonicAudioProcessor;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.common.math.LongMath;
import java.io.IOException; import java.io.IOException;
import java.math.RoundingMode;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -62,6 +64,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private @MonotonicNonNull AudioFormat encoderInputAudioFormat; private @MonotonicNonNull AudioFormat encoderInputAudioFormat;
private @MonotonicNonNull MediaCodecAdapterWrapper encoder; private @MonotonicNonNull MediaCodecAdapterWrapper encoder;
private long nextEncoderInputBufferTimeUs; private long nextEncoderInputBufferTimeUs;
private long encoderBufferDurationRemainder;
private ByteBuffer sonicOutputBuffer; private ByteBuffer sonicOutputBuffer;
private boolean drainingSonicForSpeedChange; private boolean drainingSonicForSpeedChange;
@ -82,6 +85,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
sonicAudioProcessor = new SonicAudioProcessor(); sonicAudioProcessor = new SonicAudioProcessor();
sonicOutputBuffer = AudioProcessor.EMPTY_BUFFER; sonicOutputBuffer = AudioProcessor.EMPTY_BUFFER;
nextEncoderInputBufferTimeUs = 0; nextEncoderInputBufferTimeUs = 0;
encoderBufferDurationRemainder = 0;
speedProvider = new SegmentSpeedProvider(decoderInputFormat); speedProvider = new SegmentSpeedProvider(decoderInputFormat);
currentSpeed = speedProvider.getSpeed(0); currentSpeed = speedProvider.getSpeed(0);
try { try {
@ -269,7 +273,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
encoderInputBufferData.put(inputBuffer); encoderInputBufferData.put(inputBuffer);
encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs; encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs;
nextEncoderInputBufferTimeUs += nextEncoderInputBufferTimeUs +=
getBufferDurationUs( getEncoderBufferDurationUs(
/* bytesWritten= */ encoderInputBufferData.position(), /* bytesWritten= */ encoderInputBufferData.position(),
encoderInputAudioFormat.bytesPerFrame, encoderInputAudioFormat.bytesPerFrame,
encoderInputAudioFormat.sampleRate); encoderInputAudioFormat.sampleRate);
@ -366,9 +370,17 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
errorCode); errorCode);
} }
// TODO(internal b/204978301): Ensure encoder and decoder timestamps match when no speed change. private long getEncoderBufferDurationUs(long bytesWritten, int bytesPerFrame, int sampleRate) {
private static long getBufferDurationUs(long bytesWritten, int bytesPerFrame, int sampleRate) { // The calculation below accounts for remainders and rounding. Without that it corresponds to
long framesWritten = bytesWritten / bytesPerFrame; // the following:
return framesWritten * C.MICROS_PER_SECOND / sampleRate; // bufferDurationUs = numberOfFramesInBuffer * sampleDurationUs
// where numberOfFramesInBuffer = bytesWritten / bytesPerFrame
// and sampleDurationUs = C.MICROS_PER_SECOND / sampleRate
long framesWrittenMicrosPerSecond =
bytesWritten * C.MICROS_PER_SECOND / bytesPerFrame + encoderBufferDurationRemainder;
long bufferDurationUs =
LongMath.divide(framesWrittenMicrosPerSecond, sampleRate, RoundingMode.CEILING);
encoderBufferDurationRemainder = framesWrittenMicrosPerSecond - bufferDurationUs * sampleRate;
return bufferDurationUs;
} }
} }

View File

@ -135,145 +135,145 @@ sample:
dataHashCode = 1000136444 dataHashCode = 1000136444
size = 140 size = 140
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 416 presentationTimeUs = 417
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 217961709 dataHashCode = 217961709
size = 172 size = 172
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 3332 presentationTimeUs = 3334
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -879376936 dataHashCode = -879376936
size = 176 size = 176
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 6915 presentationTimeUs = 6917
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1259979587 dataHashCode = 1259979587
size = 192 size = 192
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 10581 presentationTimeUs = 10584
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 907407225 dataHashCode = 907407225
size = 188 size = 188
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 14581 presentationTimeUs = 14584
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -904354707 dataHashCode = -904354707
size = 176 size = 176
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 18497 presentationTimeUs = 18500
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1001385853 dataHashCode = 1001385853
size = 172 size = 172
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 22163 presentationTimeUs = 22167
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1545716086 dataHashCode = 1545716086
size = 196 size = 196
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 25746 presentationTimeUs = 25750
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 358710839 dataHashCode = 358710839
size = 180 size = 180
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 29829 presentationTimeUs = 29834
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -671124798 dataHashCode = -671124798
size = 140 size = 140
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 33579 presentationTimeUs = 33584
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -945404910 dataHashCode = -945404910
size = 120 size = 120
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 36495 presentationTimeUs = 36500
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1881048379 dataHashCode = 1881048379
size = 88 size = 88
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 38995 presentationTimeUs = 39000
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1059579897 dataHashCode = 1059579897
size = 88 size = 88
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 40828 presentationTimeUs = 40834
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1496098648 dataHashCode = 1496098648
size = 84 size = 84
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 42661 presentationTimeUs = 42667
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 250093960 dataHashCode = 250093960
size = 751 size = 751
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 44411 presentationTimeUs = 44417
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1895536226 dataHashCode = 1895536226
size = 1045 size = 1045
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 59994 presentationTimeUs = 60063
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1723596464 dataHashCode = 1723596464
size = 947 size = 947
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 81744 presentationTimeUs = 81834
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -978803114 dataHashCode = -978803114
size = 946 size = 946
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 101410 presentationTimeUs = 101563
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 387377078 dataHashCode = 387377078
size = 946 size = 946
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 121076 presentationTimeUs = 121271
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -132658698 dataHashCode = -132658698
size = 901 size = 901
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 140742 presentationTimeUs = 140980
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 1495036471 dataHashCode = 1495036471
size = 899 size = 899
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 159492 presentationTimeUs = 159750
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 304440590 dataHashCode = 304440590
size = 878 size = 878
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 178158 presentationTimeUs = 178480
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = -1955900344 dataHashCode = -1955900344
size = 112 size = 112
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 196408 presentationTimeUs = 196771
sample: sample:
trackIndex = 0 trackIndex = 0
dataHashCode = 88896626 dataHashCode = 88896626
size = 116 size = 116
isKeyFrame = true isKeyFrame = true
presentationTimeUs = 198741 presentationTimeUs = 199105
sample: sample:
trackIndex = 1 trackIndex = 1
dataHashCode = 2139021989 dataHashCode = 2139021989