diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java index 167d1725bc..d3d4a12092 100644 --- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java +++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java @@ -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.SonicAudioProcessor; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.common.math.LongMath; import java.io.IOException; +import java.math.RoundingMode; import java.nio.ByteBuffer; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -62,6 +64,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private @MonotonicNonNull AudioFormat encoderInputAudioFormat; private @MonotonicNonNull MediaCodecAdapterWrapper encoder; private long nextEncoderInputBufferTimeUs; + private long encoderBufferDurationRemainder; private ByteBuffer sonicOutputBuffer; private boolean drainingSonicForSpeedChange; @@ -82,6 +85,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; sonicAudioProcessor = new SonicAudioProcessor(); sonicOutputBuffer = AudioProcessor.EMPTY_BUFFER; nextEncoderInputBufferTimeUs = 0; + encoderBufferDurationRemainder = 0; speedProvider = new SegmentSpeedProvider(decoderInputFormat); currentSpeed = speedProvider.getSpeed(0); try { @@ -269,7 +273,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; encoderInputBufferData.put(inputBuffer); encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs; nextEncoderInputBufferTimeUs += - getBufferDurationUs( + getEncoderBufferDurationUs( /* bytesWritten= */ encoderInputBufferData.position(), encoderInputAudioFormat.bytesPerFrame, encoderInputAudioFormat.sampleRate); @@ -366,9 +370,17 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; errorCode); } - // TODO(internal b/204978301): Ensure encoder and decoder timestamps match when no speed change. - private static long getBufferDurationUs(long bytesWritten, int bytesPerFrame, int sampleRate) { - long framesWritten = bytesWritten / bytesPerFrame; - return framesWritten * C.MICROS_PER_SECOND / sampleRate; + private long getEncoderBufferDurationUs(long bytesWritten, int bytesPerFrame, int sampleRate) { + // The calculation below accounts for remainders and rounding. Without that it corresponds to + // the following: + // 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; } } diff --git a/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump b/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump index 707be77d53..816e26e384 100644 --- a/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump +++ b/testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump @@ -135,145 +135,145 @@ sample: dataHashCode = 1000136444 size = 140 isKeyFrame = true - presentationTimeUs = 416 + presentationTimeUs = 417 sample: trackIndex = 0 dataHashCode = 217961709 size = 172 isKeyFrame = true - presentationTimeUs = 3332 + presentationTimeUs = 3334 sample: trackIndex = 0 dataHashCode = -879376936 size = 176 isKeyFrame = true - presentationTimeUs = 6915 + presentationTimeUs = 6917 sample: trackIndex = 0 dataHashCode = 1259979587 size = 192 isKeyFrame = true - presentationTimeUs = 10581 + presentationTimeUs = 10584 sample: trackIndex = 0 dataHashCode = 907407225 size = 188 isKeyFrame = true - presentationTimeUs = 14581 + presentationTimeUs = 14584 sample: trackIndex = 0 dataHashCode = -904354707 size = 176 isKeyFrame = true - presentationTimeUs = 18497 + presentationTimeUs = 18500 sample: trackIndex = 0 dataHashCode = 1001385853 size = 172 isKeyFrame = true - presentationTimeUs = 22163 + presentationTimeUs = 22167 sample: trackIndex = 0 dataHashCode = 1545716086 size = 196 isKeyFrame = true - presentationTimeUs = 25746 + presentationTimeUs = 25750 sample: trackIndex = 0 dataHashCode = 358710839 size = 180 isKeyFrame = true - presentationTimeUs = 29829 + presentationTimeUs = 29834 sample: trackIndex = 0 dataHashCode = -671124798 size = 140 isKeyFrame = true - presentationTimeUs = 33579 + presentationTimeUs = 33584 sample: trackIndex = 0 dataHashCode = -945404910 size = 120 isKeyFrame = true - presentationTimeUs = 36495 + presentationTimeUs = 36500 sample: trackIndex = 0 dataHashCode = 1881048379 size = 88 isKeyFrame = true - presentationTimeUs = 38995 + presentationTimeUs = 39000 sample: trackIndex = 0 dataHashCode = 1059579897 size = 88 isKeyFrame = true - presentationTimeUs = 40828 + presentationTimeUs = 40834 sample: trackIndex = 0 dataHashCode = 1496098648 size = 84 isKeyFrame = true - presentationTimeUs = 42661 + presentationTimeUs = 42667 sample: trackIndex = 0 dataHashCode = 250093960 size = 751 isKeyFrame = true - presentationTimeUs = 44411 + presentationTimeUs = 44417 sample: trackIndex = 0 dataHashCode = 1895536226 size = 1045 isKeyFrame = true - presentationTimeUs = 59994 + presentationTimeUs = 60063 sample: trackIndex = 0 dataHashCode = 1723596464 size = 947 isKeyFrame = true - presentationTimeUs = 81744 + presentationTimeUs = 81834 sample: trackIndex = 0 dataHashCode = -978803114 size = 946 isKeyFrame = true - presentationTimeUs = 101410 + presentationTimeUs = 101563 sample: trackIndex = 0 dataHashCode = 387377078 size = 946 isKeyFrame = true - presentationTimeUs = 121076 + presentationTimeUs = 121271 sample: trackIndex = 0 dataHashCode = -132658698 size = 901 isKeyFrame = true - presentationTimeUs = 140742 + presentationTimeUs = 140980 sample: trackIndex = 0 dataHashCode = 1495036471 size = 899 isKeyFrame = true - presentationTimeUs = 159492 + presentationTimeUs = 159750 sample: trackIndex = 0 dataHashCode = 304440590 size = 878 isKeyFrame = true - presentationTimeUs = 178158 + presentationTimeUs = 178480 sample: trackIndex = 0 dataHashCode = -1955900344 size = 112 isKeyFrame = true - presentationTimeUs = 196408 + presentationTimeUs = 196771 sample: trackIndex = 0 dataHashCode = 88896626 size = 116 isKeyFrame = true - presentationTimeUs = 198741 + presentationTimeUs = 199105 sample: trackIndex = 1 dataHashCode = 2139021989