diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/C2Mp3TimestampTracker.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/C2Mp3TimestampTracker.java deleted file mode 100644 index 3b143b3b76..0000000000 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/C2Mp3TimestampTracker.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package androidx.media3.exoplayer.mediacodec; - -import static java.lang.Math.max; - -import androidx.media3.common.C; -import androidx.media3.common.Format; -import androidx.media3.common.util.Assertions; -import androidx.media3.common.util.Log; -import androidx.media3.decoder.DecoderInputBuffer; -import androidx.media3.extractor.MpegAudioUtil; -import java.nio.ByteBuffer; - -/** - * Tracks the number of processed samples to calculate an accurate current timestamp, matching the - * calculations made in the Codec2 Mp3 decoder. - */ -/* package */ final class C2Mp3TimestampTracker { - - private static final long DECODER_DELAY_FRAMES = 529; - private static final String TAG = "C2Mp3TimestampTracker"; - - private long anchorTimestampUs; - private long processedFrames; - private boolean seenInvalidMpegAudioHeader; - - /** - * Resets the timestamp tracker. - * - *
This should be done when the codec is flushed.
- */
- public void reset() {
- anchorTimestampUs = 0;
- processedFrames = 0;
- seenInvalidMpegAudioHeader = false;
- }
-
- /**
- * Updates the tracker with the given input buffer and returns the expected output timestamp.
- *
- * @param format The format associated with the buffer.
- * @param buffer The current input buffer.
- * @return The expected output presentation time, in microseconds.
- */
- public long updateAndGetPresentationTimeUs(Format format, DecoderInputBuffer buffer) {
- if (processedFrames == 0) {
- anchorTimestampUs = buffer.timeUs;
- }
-
- if (seenInvalidMpegAudioHeader) {
- return buffer.timeUs;
- }
-
- ByteBuffer data = Assertions.checkNotNull(buffer.data);
- int sampleHeaderData = 0;
- for (int i = 0; i < 4; i++) {
- sampleHeaderData <<= 8;
- sampleHeaderData |= data.get(i) & 0xFF;
- }
-
- int frameCount = MpegAudioUtil.parseMpegAudioFrameSampleCount(sampleHeaderData);
- if (frameCount == C.LENGTH_UNSET) {
- seenInvalidMpegAudioHeader = true;
- processedFrames = 0;
- anchorTimestampUs = buffer.timeUs;
- Log.w(TAG, "MPEG audio header is invalid.");
- return buffer.timeUs;
- }
- long currentBufferTimestampUs = getBufferTimestampUs(format.sampleRate);
- processedFrames += frameCount;
- return currentBufferTimestampUs;
- }
-
- /**
- * Returns the timestamp of the last buffer that will be produced if the stream ends at the
- * current position, in microseconds.
- *
- * @param format The format associated with input buffers.
- * @return The timestamp of the last buffer that will be produced if the stream ends at the
- * current position, in microseconds.
- */
- public long getLastOutputBufferPresentationTimeUs(Format format) {
- return getBufferTimestampUs(format.sampleRate);
- }
-
- private long getBufferTimestampUs(long sampleRate) {
- // This calculation matches the timestamp calculation in the Codec2 Mp3 Decoder.
- // https://cs.android.com/android/platform/superproject/+/main:frameworks/av/media/codec2/components/mp3/C2SoftMp3Dec.cpp;l=464;drc=ed134640332fea70ca4b05694289d91a5265bb46
- return anchorTimestampUs
- + max(0, (processedFrames - DECODER_DELAY_FRAMES) * C.MICROS_PER_SECOND / sampleRate);
- }
-}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java
index cfecc4b4f9..83cdeef82a 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java
@@ -378,7 +378,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean codecNeedsAdaptationWorkaroundBuffer;
private boolean shouldSkipAdaptationWorkaroundOutputBuffer;
private boolean codecNeedsEosPropagation;
- @Nullable private C2Mp3TimestampTracker c2Mp3TimestampTracker;
private long codecHotswapDeadlineMs;
private int inputIndex;
private int outputIndex;
@@ -956,9 +955,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
largestQueuedPresentationTimeUs = C.TIME_UNSET;
lastBufferInStreamPresentationTimeUs = C.TIME_UNSET;
lastProcessedOutputBufferTimeUs = C.TIME_UNSET;
- if (c2Mp3TimestampTracker != null) {
- c2Mp3TimestampTracker.reset();
- }
codecDrainState = DRAIN_STATE_NONE;
codecDrainAction = DRAIN_ACTION_NONE;
// Reconfiguration data sent shortly before the flush may not have been processed by the
@@ -979,7 +975,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
resetCodecStateForFlush();
pendingPlaybackException = null;
- c2Mp3TimestampTracker = null;
availableCodecInfos = null;
codecInfo = null;
codecInputFormat = null;
@@ -1202,9 +1197,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
this.codecNeedsAdaptationWorkaroundBuffer =
codecAdaptationWorkaroundMode != ADAPTATION_WORKAROUND_MODE_NEVER;
}
- if ("c2.android.mp3.decoder".equals(codecInfo.name)) {
- c2Mp3TimestampTracker = new C2Mp3TimestampTracker();
- }
if (getState() == STATE_STARTED) {
codecHotswapDeadlineMs = getClock().elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS;
@@ -1396,19 +1388,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
long presentationTimeUs = buffer.timeUs;
- if (c2Mp3TimestampTracker != null) {
- presentationTimeUs =
- c2Mp3TimestampTracker.updateAndGetPresentationTimeUs(inputFormat, buffer);
- // When draining the C2 MP3 decoder it produces an extra non-empty buffer with a timestamp
- // after all queued input buffer timestamps (unlike other decoders, which generally propagate
- // the input timestamps to output buffers 1:1). To detect the end of the stream when this
- // buffer is dequeued we override the largest queued timestamp accordingly.
- largestQueuedPresentationTimeUs =
- max(
- largestQueuedPresentationTimeUs,
- c2Mp3TimestampTracker.getLastOutputBufferPresentationTimeUs(inputFormat));
- }
-
if (waitingForFirstSampleInFormat) {
if (!pendingOutputStreamChanges.isEmpty()) {
pendingOutputStreamChanges.peekLast().formatQueue.add(presentationTimeUs, inputFormat);
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/C2Mp3TimestampTrackerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/C2Mp3TimestampTrackerTest.java
deleted file mode 100644
index fb76a4dbce..0000000000
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/C2Mp3TimestampTrackerTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.media3.exoplayer.mediacodec;
-
-import static androidx.media3.test.utils.TestUtil.createByteArray;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.media3.common.Format;
-import androidx.media3.common.MimeTypes;
-import androidx.media3.decoder.DecoderInputBuffer;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Unit tests for {@link C2Mp3TimestampTracker}. */
-@RunWith(AndroidJUnit4.class)
-public final class C2Mp3TimestampTrackerTest {
-
- private static final Format FORMAT =
- new Format.Builder()
- .setSampleMimeType(MimeTypes.AUDIO_MPEG)
- .setChannelCount(2)
- .setSampleRate(44_100)
- .build();
-
- private C2Mp3TimestampTracker timestampTracker;
- private DecoderInputBuffer buffer;
- private DecoderInputBuffer invalidBuffer;
-
- @Before
- public void setUp() {
- timestampTracker = new C2Mp3TimestampTracker();
- buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
- buffer.data = ByteBuffer.wrap(createByteArray(0xFF, 0xFB, 0xE8, 0x3C));
- buffer.timeUs = 100_000;
- invalidBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
- invalidBuffer.data = ByteBuffer.wrap(createByteArray(0, 0, 0, 0));
- invalidBuffer.timeUs = 120_000;
- }
-
- @Test
- public void handleBuffers_outputsCorrectTimestamps() {
- List