diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java index 5b2145af93..4e91cae79f 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java @@ -15,7 +15,7 @@ */ package androidx.media3.muxer; -import android.media.MediaCodec; +import android.media.MediaCodec.BufferInfo; import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.util.UnstableApi; @@ -32,8 +32,7 @@ public interface Muxer { TrackToken addTrack(Format format); /** Writes encoded sample data. */ - void writeSampleData( - TrackToken trackToken, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo) + void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws IOException; /** Adds {@linkplain Metadata.Entry metadata} about the output file. */ diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java index 00aededb46..b97a96e672 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java @@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat; import static java.util.concurrent.TimeUnit.SECONDS; import android.content.Context; +import android.media.MediaCodec.BufferInfo; import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.Effect; @@ -449,18 +450,17 @@ public class TransformerPauseResumeTest { } @Override - public void writeSampleData( - TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags) + public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { if (trackToken == videoTrackToken - && presentationTimeUs >= DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME) { + && bufferInfo.presentationTimeUs >= DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME) { if (!notifiedListener) { listener.onFrameBlocked(); notifiedListener = true; } return; } - wrappedMuxer.writeSampleData(trackToken, data, presentationTimeUs, flags); + wrappedMuxer.writeSampleData(trackToken, data, bufferInfo); } @Override diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java index ed8c52bcb5..50f3d37386 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java @@ -15,6 +15,7 @@ */ package androidx.media3.transformer; +import android.media.MediaCodec.BufferInfo; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.Metadata; @@ -70,10 +71,9 @@ public final class DefaultMuxer implements Muxer { } @Override - public void writeSampleData( - TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags) + public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { - muxer.writeSampleData(trackToken, data, presentationTimeUs, flags); + muxer.writeSampleData(trackToken, data, bufferInfo); } @Override diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java index 33ff0a08ec..f3a5ab2443 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java @@ -21,7 +21,7 @@ import static androidx.media3.common.util.Util.SDK_INT; import static androidx.media3.common.util.Util.castNonNull; import android.annotation.SuppressLint; -import android.media.MediaCodec; +import android.media.MediaCodec.BufferInfo; import android.media.MediaFormat; import android.media.MediaMuxer; import androidx.annotation.Nullable; @@ -80,7 +80,6 @@ import java.util.Map; private final MediaMuxer mediaMuxer; private final long videoDurationUs; - private final MediaCodec.BufferInfo bufferInfo; private final Map trackTokenToLastPresentationTimeUs; private final Map trackTokenToPresentationTimeOffsetUs; @@ -92,7 +91,6 @@ import java.util.Map; private FrameworkMuxer(MediaMuxer mediaMuxer, long videoDurationMs) { this.mediaMuxer = mediaMuxer; this.videoDurationUs = Util.msToUs(videoDurationMs); - bufferInfo = new MediaCodec.BufferInfo(); trackTokenToLastPresentationTimeUs = new HashMap<>(); trackTokenToPresentationTimeOffsetUs = new HashMap<>(); } @@ -133,10 +131,9 @@ import java.util.Map; } @Override - public void writeSampleData( - TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags) + public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { - + long presentationTimeUs = bufferInfo.presentationTimeUs; if (videoDurationUs != C.TIME_UNSET && trackToken == videoTrackToken && presentationTimeUs > videoDurationUs) { @@ -149,14 +146,10 @@ import java.util.Map; startMuxer(); } - int offset = data.position(); - int size = data.limit() - offset; - long presentationTimeOffsetUs = trackTokenToPresentationTimeOffsetUs.getOrDefault(trackToken, 0L); presentationTimeUs += presentationTimeOffsetUs; - bufferInfo.set(offset, size, presentationTimeUs, TransformerUtil.getMediaCodecFlags(flags)); long lastSamplePresentationTimeUs = trackTokenToLastPresentationTimeUs.getOrDefault(trackToken, 0L); // writeSampleData blocks on old API versions, so check here to avoid calling the method. @@ -176,13 +169,17 @@ import java.util.Map; + " < " + lastSamplePresentationTimeUs + ") unsupported when using negative PTS workaround"); + bufferInfo.set(bufferInfo.offset, bufferInfo.size, presentationTimeUs, bufferInfo.flags); try { checkState(trackToken instanceof TrackTokenImpl); mediaMuxer.writeSampleData(((TrackTokenImpl) trackToken).trackIndex, data, bufferInfo); } catch (RuntimeException e) { throw new MuxerException( - "Failed to write sample for presentationTimeUs=" + presentationTimeUs + ", size=" + size, + "Failed to write sample for presentationTimeUs=" + + presentationTimeUs + + ", size=" + + bufferInfo.size, e); } } @@ -208,11 +205,13 @@ import java.util.Map; } if (videoDurationUs != C.TIME_UNSET && videoTrackToken != null) { - writeSampleData( - videoTrackToken, - ByteBuffer.allocateDirect(0), + BufferInfo bufferInfo = new BufferInfo(); + bufferInfo.set( + /* newOffset= */ 0, + /* newSize= */ 0, videoDurationUs, - C.BUFFER_FLAG_END_OF_STREAM); + TransformerUtil.getMediaCodecFlags(C.BUFFER_FLAG_END_OF_STREAM)); + writeSampleData(checkNotNull(videoTrackToken), ByteBuffer.allocateDirect(0), bufferInfo); } isStarted = false; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java index caabf2fc60..d8f56a6930 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java @@ -159,14 +159,12 @@ public final class InAppMuxer implements Muxer { private final androidx.media3.muxer.Muxer muxer; private final @Nullable MetadataProvider metadataProvider; - private final BufferInfo bufferInfo; private final Set metadataEntries; private InAppMuxer( androidx.media3.muxer.Muxer muxer, @Nullable MetadataProvider metadataProvider) { this.muxer = muxer; this.metadataProvider = metadataProvider; - bufferInfo = new BufferInfo(); metadataEntries = new LinkedHashSet<>(); } @@ -180,19 +178,17 @@ public final class InAppMuxer implements Muxer { } @Override - public void writeSampleData( - TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags) + public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { - int size = data.remaining(); - bufferInfo.set( - data.position(), size, presentationTimeUs, TransformerUtil.getMediaCodecFlags(flags)); - try { muxer.writeSampleData(trackToken, data, bufferInfo); } catch (IOException e) { throw new MuxerException( - "Failed to write sample for presentationTimeUs=" + presentationTimeUs + ", size=" + size, + "Failed to write sample for presentationTimeUs=" + + bufferInfo.presentationTimeUs + + ", size=" + + bufferInfo.size, e); } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java index 255da05f3c..3cf37b8dd6 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Muxer.java @@ -15,6 +15,7 @@ */ package androidx.media3.transformer; +import android.media.MediaCodec.BufferInfo; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.Metadata; @@ -84,13 +85,10 @@ public interface Muxer { * @param trackToken The {@link TrackToken} of the track, previously returned by {@link * #addTrack(Format)}. * @param data A buffer containing the sample data to write to the container. - * @param presentationTimeUs The presentation time of the sample in microseconds. - * @param flags The {@link C.BufferFlags} associated with the data. Only {@link - * C#BUFFER_FLAG_KEY_FRAME} and {@link C#BUFFER_FLAG_END_OF_STREAM} are supported. + * @param bufferInfo The {@link BufferInfo} of the sample. * @throws MuxerException If the muxer fails to write the sample. */ - void writeSampleData( - TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags) + void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException; /** Adds {@linkplain Metadata.Entry metadata} about the output file. */ diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java index cdba362fd9..3a189b3d03 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java @@ -28,6 +28,7 @@ import static java.lang.Math.max; import static java.lang.annotation.ElementType.TYPE_USE; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import android.media.MediaCodec.BufferInfo; import android.util.SparseArray; import androidx.annotation.IntDef; import androidx.annotation.IntRange; @@ -147,6 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private final ScheduledExecutorService abortScheduledExecutorService; private final @MonotonicNonNull Format appendVideoFormat; private final long maxDelayBetweenSamplesMs; + private final BufferInfo bufferInfo; private boolean isReady; private boolean isEnded; @@ -206,6 +208,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; previousTrackType = C.TRACK_TYPE_NONE; firstVideoPresentationTimeUs = C.TIME_UNSET; abortScheduledExecutorService = Util.newSingleThreadScheduledExecutor(TIMER_THREAD_NAME); + bufferInfo = new BufferInfo(); } /** @@ -552,8 +555,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; resetAbortTimer(); checkStateNotNull(muxer); - muxer.writeSampleData( - trackInfo.trackToken, data, presentationTimeUs, isKeyFrame ? C.BUFFER_FLAG_KEY_FRAME : 0); + bufferInfo.set( + data.position(), + data.remaining(), + presentationTimeUs, + TransformerUtil.getMediaCodecFlags(isKeyFrame ? C.BUFFER_FLAG_KEY_FRAME : 0)); + muxer.writeSampleData(trackInfo.trackToken, data, bufferInfo); if (trackType == C.TRACK_TYPE_VIDEO) { DebugTraceUtil.logEvent(DebugTraceUtil.EVENT_MUXER_WRITE_SAMPLE_VIDEO, presentationTimeUs); } else if (trackType == C.TRACK_TYPE_AUDIO) { diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java b/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java index 6249de0278..c6bbce2c87 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java @@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType; +import android.media.MediaCodec.BufferInfo; import android.util.SparseArray; import androidx.annotation.Nullable; import androidx.media3.common.C; @@ -122,15 +123,16 @@ public final class CapturingMuxer implements Muxer, Dumpable { } @Override - public void writeSampleData( - TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags) + public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { @C.TrackType int trackType = checkNotNull(trackTokenToType.get(trackToken)); dumpableStreamByTrackType .get(trackType) .addSample( - data, (flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME, presentationTimeUs); - wrappedMuxer.writeSampleData(trackToken, data, presentationTimeUs, flags); + data, + (bufferInfo.flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME, + bufferInfo.presentationTimeUs); + wrappedMuxer.writeSampleData(trackToken, data, bufferInfo); } @Override