Pass BufferInfo in writeSampleData() method in Transformer/Muxer.java

This is to eventually replace Transformer/Muxer.java with Muxer/Muxer.java

PiperOrigin-RevId: 627043808
This commit is contained in:
sheenachhabra 2024-04-22 08:20:59 -07:00 committed by Copybara-Service
parent 86ef571644
commit 03a041c452
8 changed files with 46 additions and 45 deletions

View File

@ -15,7 +15,7 @@
*/ */
package androidx.media3.muxer; package androidx.media3.muxer;
import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
@ -32,8 +32,7 @@ public interface Muxer {
TrackToken addTrack(Format format); TrackToken addTrack(Format format);
/** Writes encoded sample data. */ /** Writes encoded sample data. */
void writeSampleData( void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo)
throws IOException; throws IOException;
/** Adds {@linkplain Metadata.Entry metadata} about the output file. */ /** Adds {@linkplain Metadata.Entry metadata} about the output file. */

View File

@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import android.content.Context; import android.content.Context;
import android.media.MediaCodec.BufferInfo;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Effect; import androidx.media3.common.Effect;
@ -449,18 +450,17 @@ public class TransformerPauseResumeTest {
} }
@Override @Override
public void writeSampleData( public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
throws MuxerException { throws MuxerException {
if (trackToken == videoTrackToken if (trackToken == videoTrackToken
&& presentationTimeUs >= DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME) { && bufferInfo.presentationTimeUs >= DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME) {
if (!notifiedListener) { if (!notifiedListener) {
listener.onFrameBlocked(); listener.onFrameBlocked();
notifiedListener = true; notifiedListener = true;
} }
return; return;
} }
wrappedMuxer.writeSampleData(trackToken, data, presentationTimeUs, flags); wrappedMuxer.writeSampleData(trackToken, data, bufferInfo);
} }
@Override @Override

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.transformer; package androidx.media3.transformer;
import android.media.MediaCodec.BufferInfo;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
@ -70,10 +71,9 @@ public final class DefaultMuxer implements Muxer {
} }
@Override @Override
public void writeSampleData( public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
throws MuxerException { throws MuxerException {
muxer.writeSampleData(trackToken, data, presentationTimeUs, flags); muxer.writeSampleData(trackToken, data, bufferInfo);
} }
@Override @Override

View File

@ -21,7 +21,7 @@ import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.MediaCodec; import android.media.MediaCodec.BufferInfo;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.media.MediaMuxer; import android.media.MediaMuxer;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -80,7 +80,6 @@ import java.util.Map;
private final MediaMuxer mediaMuxer; private final MediaMuxer mediaMuxer;
private final long videoDurationUs; private final long videoDurationUs;
private final MediaCodec.BufferInfo bufferInfo;
private final Map<TrackToken, Long> trackTokenToLastPresentationTimeUs; private final Map<TrackToken, Long> trackTokenToLastPresentationTimeUs;
private final Map<TrackToken, Long> trackTokenToPresentationTimeOffsetUs; private final Map<TrackToken, Long> trackTokenToPresentationTimeOffsetUs;
@ -92,7 +91,6 @@ import java.util.Map;
private FrameworkMuxer(MediaMuxer mediaMuxer, long videoDurationMs) { private FrameworkMuxer(MediaMuxer mediaMuxer, long videoDurationMs) {
this.mediaMuxer = mediaMuxer; this.mediaMuxer = mediaMuxer;
this.videoDurationUs = Util.msToUs(videoDurationMs); this.videoDurationUs = Util.msToUs(videoDurationMs);
bufferInfo = new MediaCodec.BufferInfo();
trackTokenToLastPresentationTimeUs = new HashMap<>(); trackTokenToLastPresentationTimeUs = new HashMap<>();
trackTokenToPresentationTimeOffsetUs = new HashMap<>(); trackTokenToPresentationTimeOffsetUs = new HashMap<>();
} }
@ -133,10 +131,9 @@ import java.util.Map;
} }
@Override @Override
public void writeSampleData( public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
throws MuxerException { throws MuxerException {
long presentationTimeUs = bufferInfo.presentationTimeUs;
if (videoDurationUs != C.TIME_UNSET if (videoDurationUs != C.TIME_UNSET
&& trackToken == videoTrackToken && trackToken == videoTrackToken
&& presentationTimeUs > videoDurationUs) { && presentationTimeUs > videoDurationUs) {
@ -149,14 +146,10 @@ import java.util.Map;
startMuxer(); startMuxer();
} }
int offset = data.position();
int size = data.limit() - offset;
long presentationTimeOffsetUs = long presentationTimeOffsetUs =
trackTokenToPresentationTimeOffsetUs.getOrDefault(trackToken, 0L); trackTokenToPresentationTimeOffsetUs.getOrDefault(trackToken, 0L);
presentationTimeUs += presentationTimeOffsetUs; presentationTimeUs += presentationTimeOffsetUs;
bufferInfo.set(offset, size, presentationTimeUs, TransformerUtil.getMediaCodecFlags(flags));
long lastSamplePresentationTimeUs = long lastSamplePresentationTimeUs =
trackTokenToLastPresentationTimeUs.getOrDefault(trackToken, 0L); trackTokenToLastPresentationTimeUs.getOrDefault(trackToken, 0L);
// writeSampleData blocks on old API versions, so check here to avoid calling the method. // writeSampleData blocks on old API versions, so check here to avoid calling the method.
@ -176,13 +169,17 @@ import java.util.Map;
+ " < " + " < "
+ lastSamplePresentationTimeUs + lastSamplePresentationTimeUs
+ ") unsupported when using negative PTS workaround"); + ") unsupported when using negative PTS workaround");
bufferInfo.set(bufferInfo.offset, bufferInfo.size, presentationTimeUs, bufferInfo.flags);
try { try {
checkState(trackToken instanceof TrackTokenImpl); checkState(trackToken instanceof TrackTokenImpl);
mediaMuxer.writeSampleData(((TrackTokenImpl) trackToken).trackIndex, data, bufferInfo); mediaMuxer.writeSampleData(((TrackTokenImpl) trackToken).trackIndex, data, bufferInfo);
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw new MuxerException( throw new MuxerException(
"Failed to write sample for presentationTimeUs=" + presentationTimeUs + ", size=" + size, "Failed to write sample for presentationTimeUs="
+ presentationTimeUs
+ ", size="
+ bufferInfo.size,
e); e);
} }
} }
@ -208,11 +205,13 @@ import java.util.Map;
} }
if (videoDurationUs != C.TIME_UNSET && videoTrackToken != null) { if (videoDurationUs != C.TIME_UNSET && videoTrackToken != null) {
writeSampleData( BufferInfo bufferInfo = new BufferInfo();
videoTrackToken, bufferInfo.set(
ByteBuffer.allocateDirect(0), /* newOffset= */ 0,
/* newSize= */ 0,
videoDurationUs, videoDurationUs,
C.BUFFER_FLAG_END_OF_STREAM); TransformerUtil.getMediaCodecFlags(C.BUFFER_FLAG_END_OF_STREAM));
writeSampleData(checkNotNull(videoTrackToken), ByteBuffer.allocateDirect(0), bufferInfo);
} }
isStarted = false; isStarted = false;

View File

@ -159,14 +159,12 @@ public final class InAppMuxer implements Muxer {
private final androidx.media3.muxer.Muxer muxer; private final androidx.media3.muxer.Muxer muxer;
private final @Nullable MetadataProvider metadataProvider; private final @Nullable MetadataProvider metadataProvider;
private final BufferInfo bufferInfo;
private final Set<Metadata.Entry> metadataEntries; private final Set<Metadata.Entry> metadataEntries;
private InAppMuxer( private InAppMuxer(
androidx.media3.muxer.Muxer muxer, @Nullable MetadataProvider metadataProvider) { androidx.media3.muxer.Muxer muxer, @Nullable MetadataProvider metadataProvider) {
this.muxer = muxer; this.muxer = muxer;
this.metadataProvider = metadataProvider; this.metadataProvider = metadataProvider;
bufferInfo = new BufferInfo();
metadataEntries = new LinkedHashSet<>(); metadataEntries = new LinkedHashSet<>();
} }
@ -180,19 +178,17 @@ public final class InAppMuxer implements Muxer {
} }
@Override @Override
public void writeSampleData( public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
throws MuxerException { throws MuxerException {
int size = data.remaining();
bufferInfo.set(
data.position(), size, presentationTimeUs, TransformerUtil.getMediaCodecFlags(flags));
try { try {
muxer.writeSampleData(trackToken, data, bufferInfo); muxer.writeSampleData(trackToken, data, bufferInfo);
} catch (IOException e) { } catch (IOException e) {
throw new MuxerException( throw new MuxerException(
"Failed to write sample for presentationTimeUs=" + presentationTimeUs + ", size=" + size, "Failed to write sample for presentationTimeUs="
+ bufferInfo.presentationTimeUs
+ ", size="
+ bufferInfo.size,
e); e);
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.transformer; package androidx.media3.transformer;
import android.media.MediaCodec.BufferInfo;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
@ -84,13 +85,10 @@ public interface Muxer {
* @param trackToken The {@link TrackToken} of the track, previously returned by {@link * @param trackToken The {@link TrackToken} of the track, previously returned by {@link
* #addTrack(Format)}. * #addTrack(Format)}.
* @param data A buffer containing the sample data to write to the container. * @param data A buffer containing the sample data to write to the container.
* @param presentationTimeUs The presentation time of the sample in microseconds. * @param bufferInfo The {@link BufferInfo} of the sample.
* @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.
* @throws MuxerException If the muxer fails to write the sample. * @throws MuxerException If the muxer fails to write the sample.
*/ */
void writeSampleData( void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
throws MuxerException; throws MuxerException;
/** Adds {@linkplain Metadata.Entry metadata} about the output file. */ /** Adds {@linkplain Metadata.Entry metadata} about the output file. */

View File

@ -28,6 +28,7 @@ import static java.lang.Math.max;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.media.MediaCodec.BufferInfo;
import android.util.SparseArray; import android.util.SparseArray;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
@ -147,6 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final ScheduledExecutorService abortScheduledExecutorService; private final ScheduledExecutorService abortScheduledExecutorService;
private final @MonotonicNonNull Format appendVideoFormat; private final @MonotonicNonNull Format appendVideoFormat;
private final long maxDelayBetweenSamplesMs; private final long maxDelayBetweenSamplesMs;
private final BufferInfo bufferInfo;
private boolean isReady; private boolean isReady;
private boolean isEnded; private boolean isEnded;
@ -206,6 +208,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
previousTrackType = C.TRACK_TYPE_NONE; previousTrackType = C.TRACK_TYPE_NONE;
firstVideoPresentationTimeUs = C.TIME_UNSET; firstVideoPresentationTimeUs = C.TIME_UNSET;
abortScheduledExecutorService = Util.newSingleThreadScheduledExecutor(TIMER_THREAD_NAME); abortScheduledExecutorService = Util.newSingleThreadScheduledExecutor(TIMER_THREAD_NAME);
bufferInfo = new BufferInfo();
} }
/** /**
@ -552,8 +555,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
resetAbortTimer(); resetAbortTimer();
checkStateNotNull(muxer); checkStateNotNull(muxer);
muxer.writeSampleData( bufferInfo.set(
trackInfo.trackToken, data, presentationTimeUs, isKeyFrame ? C.BUFFER_FLAG_KEY_FRAME : 0); 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) { if (trackType == C.TRACK_TYPE_VIDEO) {
DebugTraceUtil.logEvent(DebugTraceUtil.EVENT_MUXER_WRITE_SAMPLE_VIDEO, presentationTimeUs); DebugTraceUtil.logEvent(DebugTraceUtil.EVENT_MUXER_WRITE_SAMPLE_VIDEO, presentationTimeUs);
} else if (trackType == C.TRACK_TYPE_AUDIO) { } else if (trackType == C.TRACK_TYPE_AUDIO) {

View File

@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType; import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType;
import android.media.MediaCodec.BufferInfo;
import android.util.SparseArray; import android.util.SparseArray;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
@ -122,15 +123,16 @@ public final class CapturingMuxer implements Muxer, Dumpable {
} }
@Override @Override
public void writeSampleData( public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo)
TrackToken trackToken, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
throws MuxerException { throws MuxerException {
@C.TrackType int trackType = checkNotNull(trackTokenToType.get(trackToken)); @C.TrackType int trackType = checkNotNull(trackTokenToType.get(trackToken));
dumpableStreamByTrackType dumpableStreamByTrackType
.get(trackType) .get(trackType)
.addSample( .addSample(
data, (flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME, presentationTimeUs); data,
wrappedMuxer.writeSampleData(trackToken, data, presentationTimeUs, flags); (bufferInfo.flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME,
bufferInfo.presentationTimeUs);
wrappedMuxer.writeSampleData(trackToken, data, bufferInfo);
} }
@Override @Override