diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 05f65585c6..7d789eb7de 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -38,6 +38,8 @@ * Muxers: * Renamed `setSampleCopyEnabled()` method to `setSampleCopyingEnabled()` in both `Mp4Muxer.Builder` and `FragmentedMp4Muxer.Builder`. + * `Mp4Muxer.addTrack()` and `FragmentedMp4Muxer.addTrack()` now return an + `int` track id instead of a `TrackToken`. * IMA extension: * Session: * Fix bug where calling a `Player` method on a `MediaController` connected diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java index 14a1d62bc0..b628f6fdd8 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/AndroidMuxerTestUtil.java @@ -44,11 +44,11 @@ import java.util.List; context.getResources().getAssets().openFd(MP4_FILE_ASSET_DIRECTORY + inputFileName); extractor.setDataSource(fd); - List addedTracks = new ArrayList<>(); + List addedTracks = new ArrayList<>(); for (int i = 0; i < extractor.getTrackCount(); i++) { - Muxer.TrackToken trackToken = + int trackId = muxer.addTrack(MediaFormatUtil.createFormatFromMediaFormat(extractor.getTrackFormat(i))); - addedTracks.add(trackToken); + addedTracks.add(trackId); extractor.selectTrack(i); } diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java index a9e489e6fe..a32569c019 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Muxer.java @@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkNotNull; import android.media.MediaCodec.BufferInfo; +import android.util.SparseArray; import androidx.media3.common.Format; import androidx.media3.common.Metadata; import androidx.media3.common.util.UnstableApi; @@ -64,10 +65,9 @@ import java.nio.ByteBuffer; *

To create a fragmented MP4 file, the caller must: * *

* @@ -76,8 +76,8 @@ import java.nio.ByteBuffer; * */ @UnstableApi @@ -121,10 +121,10 @@ public final class FragmentedMp4Muxer implements Muxer { /** * Sets whether to enable the sample copy. * - *

If the sample copy is enabled, {@link #writeSampleData(TrackToken, ByteBuffer, - * BufferInfo)} copies the input {@link ByteBuffer} and {@link BufferInfo} before it returns, so - * it is safe to reuse them immediately. Otherwise, the muxer takes ownership of the {@link - * ByteBuffer} and the {@link BufferInfo} and the caller must not modify them. + *

If the sample copy is enabled, {@link #writeSampleData(int, ByteBuffer, BufferInfo)} + * copies the input {@link ByteBuffer} and {@link BufferInfo} before it returns, so it is safe + * to reuse them immediately. Otherwise, the muxer takes ownership of the {@link ByteBuffer} and + * the {@link BufferInfo} and the caller must not modify them. * *

The default value is {@code true}. */ @@ -142,6 +142,7 @@ public final class FragmentedMp4Muxer implements Muxer { private final FragmentedMp4Writer fragmentedMp4Writer; private final MetadataCollector metadataCollector; + private final SparseArray trackIdToTrack; private FragmentedMp4Muxer( OutputStream outputStream, long fragmentDurationMs, boolean sampleCopyEnabled) { @@ -154,11 +155,14 @@ public final class FragmentedMp4Muxer implements Muxer { AnnexBToAvccConverter.DEFAULT, fragmentDurationMs, sampleCopyEnabled); + trackIdToTrack = new SparseArray<>(); } @Override - public TrackToken addTrack(Format format) { - return fragmentedMp4Writer.addTrack(/* sortKey= */ 1, format); + public int addTrack(Format format) { + Track track = fragmentedMp4Writer.addTrack(/* sortKey= */ 1, format); + trackIdToTrack.append(track.id, track); + return track.id; } /** @@ -171,7 +175,7 @@ public final class FragmentedMp4Muxer implements Muxer { * *

Note: Out of order B-frames are currently not supported. * - * @param trackToken The {@link TrackToken} for which this sample is being written. + * @param trackId The track id for which this sample is being written. * @param byteBuffer The encoded sample. The muxer takes ownership of the buffer if {@link * Builder#setSampleCopyingEnabled(boolean) sample copying} is disabled. Otherwise, the * position of the buffer is updated but the caller retains ownership. @@ -179,10 +183,10 @@ public final class FragmentedMp4Muxer implements Muxer { * @throws MuxerException If there is any error while writing data to the disk. */ @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException { try { - fragmentedMp4Writer.writeSampleData(trackToken, byteBuffer, bufferInfo); + fragmentedMp4Writer.writeSampleData(trackIdToTrack.get(trackId), byteBuffer, bufferInfo); } catch (IOException e) { throw new MuxerException( "Failed to write sample for presentationTimeUs=" diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java index 3cef62cd5b..3094b02b4a 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java @@ -33,7 +33,6 @@ import android.media.MediaCodec.BufferInfo; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.Util; -import androidx.media3.muxer.Muxer.TrackToken; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.io.OutputStream; @@ -122,6 +121,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private boolean headerCreated; private long minInputPresentationTimeUs; private long maxTrackDurationUs; + private int nextTrackId; /** * Creates an instance. @@ -153,8 +153,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; currentFragmentSequenceNumber = 1; } - public TrackToken addTrack(int sortKey, Format format) { - Track track = new Track(format, sampleCopyEnabled); + public Track addTrack(int sortKey, Format format) { + Track track = new Track(nextTrackId++, format, sampleCopyEnabled); tracks.add(track); if (MimeTypes.isVideo(format.sampleMimeType)) { videoTrack = track; @@ -162,15 +162,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; return track; } - public void writeSampleData( - TrackToken token, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo) + public void writeSampleData(Track track, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo) throws IOException { - checkArgument(token instanceof Track); if (!headerCreated) { createHeader(); headerCreated = true; } - Track track = (Track) token; if (shouldFlushPendingSamples(track, bufferInfo)) { createFragment(); } diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java index 8658dbaaa2..5c0537fe8c 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -89,9 +89,9 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; *

To create an MP4 container file, the caller must: * *

* @@ -100,8 +100,8 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; * @@ -252,10 +252,10 @@ public final class Mp4Muxer implements Muxer { /** * Sets whether to enable the sample copy. * - *

If the sample copy is enabled, {@link #writeSampleData(TrackToken, ByteBuffer, - * BufferInfo)} copies the input {@link ByteBuffer} and {@link BufferInfo} before it returns, so - * it is safe to reuse them immediately. Otherwise, the muxer takes ownership of the {@link - * ByteBuffer} and the {@link BufferInfo} and the caller must not modify them. + *

If the sample copy is enabled, {@link #writeSampleData(int, ByteBuffer, BufferInfo)} + * copies the input {@link ByteBuffer} and {@link BufferInfo} before it returns, so it is safe + * to reuse them immediately. Otherwise, the muxer takes ownership of the {@link ByteBuffer} and + * the {@link BufferInfo} and the caller must not modify them. * *

The default value is {@code true}. */ @@ -269,7 +269,7 @@ public final class Mp4Muxer implements Muxer { * Sets whether to enable sample batching. * *

If sample batching is enabled, samples are written in batches for each track, otherwise - * samples are written as they {@linkplain #writeSampleData(TrackToken, ByteBuffer, BufferInfo) + * samples are written as they {@linkplain #writeSampleData(int, ByteBuffer, BufferInfo) * arrive}. * *

The default value is {@code true}. @@ -348,6 +348,7 @@ public final class Mp4Muxer implements Muxer { @Nullable private final Mp4AtFileParameters mp4AtFileParameters; private final MetadataCollector metadataCollector; private final Mp4Writer mp4Writer; + private final List trackIdToTrack; private final List auxiliaryTracks; @Nullable private String cacheFilePath; @@ -355,6 +356,8 @@ public final class Mp4Muxer implements Muxer { @Nullable private MetadataCollector auxiliaryTracksMetadataCollector; @Nullable private Mp4Writer auxiliaryTracksMp4Writer; + private int nextTrackId; + private Mp4Muxer( FileOutputStream outputStream, @LastSampleDurationBehavior int lastFrameDurationBehavior, @@ -383,6 +386,7 @@ public final class Mp4Muxer implements Muxer { sampleCopyEnabled, sampleBatchingEnabled, attemptStreamableOutputEnabled); + trackIdToTrack = new ArrayList<>(); auxiliaryTracks = new ArrayList<>(); } @@ -395,11 +399,12 @@ public final class Mp4Muxer implements Muxer { *

The order of tracks remains same in which they are added. * * @param format The {@link Format} for the track. - * @return A unique {@link TrackToken}. It should be used in {@link #writeSampleData}. + * @return A unique track id. The track id is non-negative. It should be used in {@link + * #writeSampleData}. * @throws MuxerException If an error occurs while adding track. */ @Override - public TrackToken addTrack(Format format) throws MuxerException { + public int addTrack(Format format) throws MuxerException { return addTrack(/* sortKey= */ 1, format); } @@ -410,31 +415,37 @@ public final class Mp4Muxer implements Muxer { * other tracks. * *

The final order of tracks is determined by the provided sort key. Tracks with a lower sort - * key will always have a lower track id than tracks with a higher sort key. Ordering between - * tracks with the same sort key is not specified. + * key will be written before tracks with a higher sort key. Ordering between tracks with the same + * sort key is not specified. * * @param sortKey The key used for sorting the track list. * @param format The {@link Format} for the track. - * @return A unique {@link TrackToken}. It should be used in {@link #writeSampleData}. + * @return A unique track id. The track id is non-negative. It should be used in {@link + * #writeSampleData}. * @throws MuxerException If an error occurs while adding track. */ - public TrackToken addTrack(int sortKey, Format format) throws MuxerException { + public int addTrack(int sortKey, Format format) throws MuxerException { + Track track; if (outputFileFormat == FILE_FORMAT_MP4_WITH_AUXILIARY_TRACKS_EXTENSION && isAuxiliaryTrack(format)) { if (checkNotNull(mp4AtFileParameters).shouldInterleaveSamples) { // Auxiliary tracks are handled by the primary Mp4Writer. - return mp4Writer.addAuxiliaryTrack(sortKey, format); + track = mp4Writer.addAuxiliaryTrack(nextTrackId++, sortKey, format); + } else { + // Auxiliary tracks are handled by the auxiliary tracks Mp4Writer. + try { + ensureSetupForAuxiliaryTracks(); + } catch (FileNotFoundException e) { + throw new MuxerException("Cache file not found", e); + } + track = auxiliaryTracksMp4Writer.addTrack(nextTrackId++, sortKey, format); + auxiliaryTracks.add(track); } - try { - ensureSetupForAuxiliaryTracks(); - } catch (FileNotFoundException e) { - throw new MuxerException("Cache file not found", e); - } - Track track = auxiliaryTracksMp4Writer.addTrack(sortKey, format); - auxiliaryTracks.add(track); - return track; + } else { + track = mp4Writer.addTrack(nextTrackId++, sortKey, format); } - return mp4Writer.addTrack(sortKey, format); + trackIdToTrack.add(track); + return track.id; } /** @@ -442,13 +453,13 @@ public final class Mp4Muxer implements Muxer { * *

When sample batching is {@linkplain Mp4Muxer.Builder#setSampleBatchingEnabled(boolean) * enabled}, provide sample data ({@link ByteBuffer}, {@link BufferInfo}) that won't be modified - * after calling the {@link #writeSampleData(TrackToken, ByteBuffer, BufferInfo)} method, unless - * sample copying is also {@linkplain Mp4Muxer.Builder#setSampleCopyingEnabled(boolean) enabled}. - * This ensures data integrity within the batch. If sample copying is {@linkplain + * after calling the {@link #writeSampleData(int, ByteBuffer, BufferInfo)} method, unless sample + * copying is also {@linkplain Mp4Muxer.Builder#setSampleCopyingEnabled(boolean) enabled}. This + * ensures data integrity within the batch. If sample copying is {@linkplain * Mp4Muxer.Builder#setSampleCopyingEnabled(boolean) enabled}, it's safe to modify the data after * the method returns, as the muxer internally creates a sample copy. * - * @param trackToken The {@link TrackToken} for which this sample is being written. + * @param trackId The track id for which this sample is being written. * @param byteBuffer The encoded sample. The muxer takes ownership of the buffer if {@link * Builder#setSampleCopyingEnabled(boolean) sample copying} is disabled. Otherwise, the * position of the buffer is updated but the caller retains ownership. @@ -456,12 +467,11 @@ public final class Mp4Muxer implements Muxer { * @throws MuxerException If an error occurs while writing data to the output file. */ @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException { - checkState(trackToken instanceof Track); - Track track = (Track) trackToken; + Track track = trackIdToTrack.get(trackId); try { - if (auxiliaryTracks.contains(trackToken)) { + if (auxiliaryTracks.contains(track)) { checkNotNull(auxiliaryTracksMp4Writer).writeSampleData(track, byteBuffer, bufferInfo); } else { mp4Writer.writeSampleData(track, byteBuffer, bufferInfo); diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java index 40186c7a14..43686b12ba 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java @@ -111,12 +111,13 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * Adds a track of the given {@link Format}. * + * @param trackId The track id for the track. * @param sortKey The key used for sorting the track list. * @param format The {@link Format} for the track. * @return A unique {@link Track}. It should be used in {@link #writeSampleData}. */ - public Track addTrack(int sortKey, Format format) { - Track track = new Track(format, sortKey, sampleCopyEnabled); + public Track addTrack(int trackId, int sortKey, Format format) { + Track track = new Track(trackId, format, sortKey, sampleCopyEnabled); tracks.add(track); Collections.sort(tracks, (a, b) -> Integer.compare(a.sortKey, b.sortKey)); return track; @@ -127,12 +128,13 @@ import java.util.concurrent.atomic.AtomicBoolean; * *

See {@link MuxerUtil#isAuxiliaryTrack(Format)} for auxiliary tracks. * + * @param trackId The track id for the track. * @param sortKey The key used for sorting the track list. * @param format The {@link Format} for the track. * @return A unique {@link Track}. It should be used in {@link #writeSampleData}. */ - public Track addAuxiliaryTrack(int sortKey, Format format) { - Track track = new Track(format, sortKey, sampleCopyEnabled); + public Track addAuxiliaryTrack(int trackId, int sortKey, Format format) { + Track track = new Track(trackId, format, sortKey, sampleCopyEnabled); auxiliaryTracks.add(track); Collections.sort(auxiliaryTracks, (a, b) -> Integer.compare(a.sortKey, b.sortKey)); return track; 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 f171601232..373c108711 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Muxer.java @@ -44,29 +44,24 @@ public interface Muxer { ImmutableList getSupportedSampleMimeTypes(@C.TrackType int trackType); } - /** A token representing an added track. */ - interface TrackToken {} - /** * Adds a track of the given media format. * * @param format The {@link Format} of the track. - * @return The {@link TrackToken} for this track, which should be passed to {@link - * #writeSampleData}. + * @return A track id for this track, which should be passed to {@link #writeSampleData}. * @throws MuxerException If the muxer encounters a problem while adding the track. */ - TrackToken addTrack(Format format) throws MuxerException; + int addTrack(Format format) throws MuxerException; /** * Writes encoded sample data. * - * @param trackToken The {@link TrackToken} of the track, previously returned by {@link - * #addTrack(Format)}. + * @param trackId The track id, previously returned by {@link #addTrack(Format)}. * @param byteBuffer A buffer containing the sample data to write to the container. * @param bufferInfo The {@link BufferInfo} of the sample. * @throws MuxerException If the muxer fails to write the sample. */ - void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) + void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException; /** Adds {@linkplain Metadata.Entry metadata} about the output file. */ diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Track.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Track.java index 75866bec8d..9c1fdc3974 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Track.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Track.java @@ -22,7 +22,6 @@ import android.media.MediaCodec.BufferInfo; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; -import androidx.media3.muxer.Muxer.TrackToken; import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.ArrayList; @@ -30,7 +29,8 @@ import java.util.Deque; import java.util.List; /** Represents a single track (audio, video, metadata etc.). */ -/* package */ final class Track implements TrackToken { +/* package */ final class Track { + public final int id; public final Format format; public final int sortKey; public final List writtenSamples; @@ -44,18 +44,20 @@ import java.util.List; private final boolean sampleCopyEnabled; /** Creates an instance with {@code sortKey} set to 1. */ - public Track(Format format, boolean sampleCopyEnabled) { - this(format, /* sortKey= */ 1, sampleCopyEnabled); + public Track(int trackId, Format format, boolean sampleCopyEnabled) { + this(trackId, format, /* sortKey= */ 1, sampleCopyEnabled); } /** * Creates an instance. * + * @param trackId A unique id for the track. * @param format The {@link Format} for the track. * @param sortKey The key used for sorting the track list. * @param sampleCopyEnabled Whether sample copying is enabled. */ - public Track(Format format, int sortKey, boolean sampleCopyEnabled) { + public Track(int trackId, Format format, int sortKey, boolean sampleCopyEnabled) { + id = trackId; this.format = format; this.sortKey = sortKey; this.sampleCopyEnabled = sampleCopyEnabled; diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java index 75c0eb19be..5ac1a197c8 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -35,7 +35,6 @@ import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.extractor.text.DefaultSubtitleParserFactory; -import androidx.media3.muxer.Muxer.TrackToken; import androidx.media3.test.utils.DumpFileAsserts; import androidx.media3.test.utils.DumpableMp4Box; import androidx.media3.test.utils.FakeExtractorOutput; @@ -83,8 +82,8 @@ public class Mp4MuxerEndToEndTest { /* value= */ Util.getUtf8Bytes("StringValue"), MdtaMetadataEntry.TYPE_INDICATOR_STRING)); muxer.addMetadataEntry(new XmpData(xmpBytes)); - TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } @@ -136,12 +135,12 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 300L); try { - TrackToken track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); // Add same track again but with different samples. - TrackToken track2 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track2 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track2, track2Sample1.first, track2Sample1.second); mp4Muxer.writeSampleData(track2, track2Sample2.first, track2Sample2.second); } finally { @@ -180,12 +179,12 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 200L); try { - TrackToken track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); // Add same track again but with different samples. - TrackToken track2 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track2 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track2, track2Sample1.first, track2Sample1.second); mp4Muxer.writeSampleData(track2, track2Sample2.first, track2Sample2.second); } finally { @@ -218,7 +217,7 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 300L); try { - TrackToken track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); mp4Muxer.writeSampleData(track1, track1Sample3.first, track1Sample3.second); @@ -257,7 +256,7 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 2_000L); try { - TrackToken track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); mp4Muxer.writeSampleData(track1, track1Sample3.first, track1Sample3.second); @@ -301,12 +300,12 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 23_001_033_192L); try { - TrackToken track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); mp4Muxer.writeSampleData(track1, track1Sample3.first, track1Sample3.second); mp4Muxer.writeSampleData(track1, track1Sample4.first, track1Sample4.second); - TrackToken track2 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track2 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track2, track2Sample1.first, track2Sample1.second); mp4Muxer.writeSampleData(track2, track2Sample2.first, track2Sample2.second); mp4Muxer.writeSampleData(track2, track2Sample3.first, track2Sample3.second); @@ -337,7 +336,7 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L); try { - TrackToken track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track1 = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); // Add same track again but without any samples. @@ -365,11 +364,11 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT); + int trackId = muxer.addTrack(FAKE_VIDEO_FORMAT); for (int i = 0; i < 50_000; i++) { Pair sampleAndSampleInfo = getFakeSampleAndSampleInfo(/* presentationTimeUs= */ i); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } } finally { muxer.close(); @@ -397,11 +396,11 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT); + int trackId = muxer.addTrack(FAKE_VIDEO_FORMAT); for (int i = 0; i < 1_000; i++) { Pair sampleAndSampleInfo = getFakeSampleAndSampleInfo(/* presentationTimeUs= */ i); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } } finally { muxer.close(); @@ -448,24 +447,24 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken primaryVideoTrackToken = muxer.addTrack(FAKE_VIDEO_FORMAT); - TrackToken sharpVideoTrackToken = + int primaryVideoTrackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + int sharpVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_ORIGINAL) .build()); - TrackToken depthLinearVideoTrackToken = + int depthLinearVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR) .build()); - writeFakeSamples(muxer, primaryVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, sharpVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, depthLinearVideoTrackToken, /* sampleCount= */ 5); + writeFakeSamples(muxer, primaryVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, sharpVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, depthLinearVideoTrackId, /* sampleCount= */ 5); } finally { muxer.close(); } @@ -490,24 +489,24 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken primaryVideoTrackToken = muxer.addTrack(FAKE_VIDEO_FORMAT); - TrackToken sharpVideoTrackToken = + int primaryVideoTrackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + int sharpVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_ORIGINAL) .build()); - TrackToken depthLinearVideoTrackToken = + int depthLinearVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR) .build()); - writeFakeSamples(muxer, primaryVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, sharpVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, depthLinearVideoTrackToken, /* sampleCount= */ 5); + writeFakeSamples(muxer, primaryVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, sharpVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, depthLinearVideoTrackId, /* sampleCount= */ 5); } finally { muxer.close(); } @@ -540,24 +539,24 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken primaryVideoTrackToken = muxer.addTrack(FAKE_VIDEO_FORMAT); - TrackToken sharpVideoTrackToken = + int primaryVideoTrackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + int sharpVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_ORIGINAL) .build()); - TrackToken depthLinearVideoTrackToken = + int depthLinearVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR) .build()); - writeFakeSamples(muxer, primaryVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, sharpVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, depthLinearVideoTrackToken, /* sampleCount= */ 5); + writeFakeSamples(muxer, primaryVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, sharpVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, depthLinearVideoTrackId, /* sampleCount= */ 5); } finally { muxer.close(); } @@ -591,24 +590,24 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken primaryVideoTrackToken = muxer.addTrack(FAKE_VIDEO_FORMAT); - TrackToken sharpVideoTrackToken = + int primaryVideoTrackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + int sharpVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_ORIGINAL) .build()); - TrackToken depthLinearVideoTrackToken = + int depthLinearVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR) .build()); - writeFakeSamples(muxer, primaryVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, sharpVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, depthLinearVideoTrackToken, /* sampleCount= */ 5); + writeFakeSamples(muxer, primaryVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, sharpVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, depthLinearVideoTrackId, /* sampleCount= */ 5); } finally { muxer.close(); } @@ -642,24 +641,24 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken primaryVideoTrackToken = muxer.addTrack(FAKE_VIDEO_FORMAT); - TrackToken sharpVideoTrackToken = + int primaryVideoTrackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + int sharpVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_ORIGINAL) .build()); - TrackToken depthLinearVideoTrackToken = + int depthLinearVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR) .build()); - writeFakeSamples(muxer, primaryVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, sharpVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, depthLinearVideoTrackToken, /* sampleCount= */ 5); + writeFakeSamples(muxer, primaryVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, sharpVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, depthLinearVideoTrackId, /* sampleCount= */ 5); } finally { muxer.close(); } @@ -693,24 +692,24 @@ public class Mp4MuxerEndToEndTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken primaryVideoTrackToken = muxer.addTrack(FAKE_VIDEO_FORMAT); - TrackToken sharpVideoTrackToken = + int primaryVideoTrackId = muxer.addTrack(FAKE_VIDEO_FORMAT); + int sharpVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_ORIGINAL) .build()); - TrackToken depthLinearVideoTrackToken = + int depthLinearVideoTrackId = muxer.addTrack( FAKE_VIDEO_FORMAT .buildUpon() .setRoleFlags(C.ROLE_FLAG_AUXILIARY) .setAuxiliaryTrackType(C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR) .build()); - writeFakeSamples(muxer, primaryVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, sharpVideoTrackToken, /* sampleCount= */ 5); - writeFakeSamples(muxer, depthLinearVideoTrackToken, /* sampleCount= */ 5); + writeFakeSamples(muxer, primaryVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, sharpVideoTrackId, /* sampleCount= */ 5); + writeFakeSamples(muxer, depthLinearVideoTrackId, /* sampleCount= */ 5); } finally { muxer.close(); } @@ -751,7 +750,7 @@ public class Mp4MuxerEndToEndTest { long expectedDurationUs = 1_000L; try { - TrackToken track = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track, sample1.first, sample1.second); mp4Muxer.writeSampleData(track, sample2.first, sample2.second); mp4Muxer.writeSampleData(track, sample3.first, sample3.second); @@ -798,7 +797,7 @@ public class Mp4MuxerEndToEndTest { getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 300L); try { - TrackToken track = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); + int track = mp4Muxer.addTrack(FAKE_VIDEO_FORMAT); mp4Muxer.writeSampleData(track, sample1.first, sample1.second); mp4Muxer.writeSampleData(track, sample2.first, sample2.second); mp4Muxer.writeSampleData(track, sample3.first, sample3.second); @@ -814,12 +813,12 @@ public class Mp4MuxerEndToEndTest { assertThat(fakeExtractorOutput.seekMap.getDurationUs()).isEqualTo(400L); } - private static void writeFakeSamples(Mp4Muxer muxer, TrackToken trackToken, int sampleCount) + private static void writeFakeSamples(Mp4Muxer muxer, int trackId, int sampleCount) throws MuxerException { for (int i = 0; i < sampleCount; i++) { Pair sampleAndSampleInfo = getFakeSampleAndSampleInfo(/* presentationTimeUs= */ i); - muxer.writeSampleData(trackToken, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } } } diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java index 1419c892f3..0c5d005e52 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerMetadataTest.java @@ -33,7 +33,6 @@ import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.extractor.text.DefaultSubtitleParserFactory; -import androidx.media3.muxer.Muxer.TrackToken; import androidx.media3.test.utils.DumpFileAsserts; import androidx.media3.test.utils.DumpableMp4Box; import androidx.media3.test.utils.FakeExtractorOutput; @@ -66,8 +65,8 @@ public class Mp4MuxerMetadataTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } @@ -92,8 +91,8 @@ public class Mp4MuxerMetadataTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); muxer.addMetadataEntry(new Mp4OrientationData(/* orientation= */ 90)); } finally { @@ -120,8 +119,8 @@ public class Mp4MuxerMetadataTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); muxer.addMetadataEntry(new Mp4OrientationData(/* orientation= */ 180)); } finally { @@ -148,8 +147,8 @@ public class Mp4MuxerMetadataTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); muxer.addMetadataEntry(new Mp4OrientationData(/* orientation= */ 270)); } finally { @@ -176,8 +175,8 @@ public class Mp4MuxerMetadataTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); muxer.addMetadataEntry(new Mp4LocationData(/* latitude= */ 33.0f, /* longitude= */ -120f)); } finally { muxer.close(); @@ -203,8 +202,8 @@ public class Mp4MuxerMetadataTest { new Mp4TimestampData( /* creationTimestampSeconds= */ 1_000_000L, /* modificationTimestampSeconds= */ 5_000_000L)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } @@ -233,8 +232,8 @@ public class Mp4MuxerMetadataTest { muxer.addMetadataEntry( new MdtaMetadataEntry( KEY_ANDROID_CAPTURE_FPS, Util.toByteArray(captureFps), TYPE_INDICATOR_FLOAT32)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } @@ -262,8 +261,8 @@ public class Mp4MuxerMetadataTest { muxer.addMetadataEntry( new MdtaMetadataEntry( "SomeStringKey", Util.getUtf8Bytes("Some Random String"), TYPE_INDICATOR_STRING)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } @@ -289,10 +288,10 @@ public class Mp4MuxerMetadataTest { muxer.addMetadataEntry( new MdtaMetadataEntry(metadataKey, metadataValue, TYPE_INDICATOR_STRING)); } - TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT); + int trackId = muxer.addTrack(FAKE_VIDEO_FORMAT); try { - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); assertThat(sampleAndSampleInfo.first.remaining()).isEqualTo(0); } finally { muxer.close(); @@ -313,8 +312,8 @@ public class Mp4MuxerMetadataTest { muxer.addMetadataEntry( new MdtaMetadataEntry( "SomeStringKey", Util.toByteArray(floatValue), TYPE_INDICATOR_FLOAT32)); - TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } @@ -342,8 +341,8 @@ public class Mp4MuxerMetadataTest { Context context = ApplicationProvider.getApplicationContext(); byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA); muxer.addMetadataEntry(new XmpData(xmpBytes)); - TrackToken token = muxer.addTrack(0, FAKE_VIDEO_FORMAT); - muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + int trackId = muxer.addTrack(0, FAKE_VIDEO_FORMAT); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); } finally { muxer.close(); } 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 90105893e1..2e7d59fa3f 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java @@ -24,7 +24,6 @@ import static org.junit.Assume.assumeFalse; import android.content.Context; import android.media.MediaCodec.BufferInfo; -import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.Effect; import androidx.media3.common.Format; @@ -448,7 +447,7 @@ public class TransformerPauseResumeTest { private final FrameBlockingMuxer.Listener listener; private boolean notifiedListener; - @Nullable private TrackToken videoTrackToken; + private int videoTrackId; private FrameBlockingMuxer(Muxer wrappedMuxer, FrameBlockingMuxer.Listener listener) { this.wrappedMuxer = wrappedMuxer; @@ -456,18 +455,18 @@ public class TransformerPauseResumeTest { } @Override - public TrackToken addTrack(Format format) throws MuxerException { - TrackToken trackToken = wrappedMuxer.addTrack(format); + public int addTrack(Format format) throws MuxerException { + int trackId = wrappedMuxer.addTrack(format); if (MimeTypes.isVideo(format.sampleMimeType)) { - videoTrackToken = trackToken; + videoTrackId = trackId; } - return trackToken; + return trackId; } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { - if (trackToken == videoTrackToken + if (trackId == videoTrackId && bufferInfo.presentationTimeUs >= DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME) { if (!notifiedListener) { listener.onFrameBlocked(); @@ -475,7 +474,7 @@ public class TransformerPauseResumeTest { } return; } - wrappedMuxer.writeSampleData(trackToken, data, bufferInfo); + wrappedMuxer.writeSampleData(trackId, 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 6a338ac71a..3c2b747fc0 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultMuxer.java @@ -84,14 +84,14 @@ public final class DefaultMuxer implements Muxer { } @Override - public TrackToken addTrack(Format format) throws MuxerException { + public int addTrack(Format format) throws MuxerException { return muxer.addTrack(format); } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException { - muxer.writeSampleData(trackToken, byteBuffer, bufferInfo); + muxer.writeSampleData(trackId, byteBuffer, 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 20b3ed8c7c..34744a8c9c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/FrameworkMuxer.java @@ -24,7 +24,7 @@ import android.annotation.SuppressLint; import android.media.MediaCodec.BufferInfo; import android.media.MediaFormat; import android.media.MediaMuxer; -import androidx.annotation.Nullable; +import android.util.SparseArray; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.Metadata; @@ -40,9 +40,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; import java.lang.reflect.Field; import java.nio.ByteBuffer; -import java.util.HashMap; import java.util.Locale; -import java.util.Map; /** {@link Muxer} implementation that uses a {@link MediaMuxer}. */ /* package */ final class FrameworkMuxer implements Muxer { @@ -105,13 +103,14 @@ import java.util.Map; private static final ImmutableList SUPPORTED_AUDIO_SAMPLE_MIME_TYPES = ImmutableList.of(MimeTypes.AUDIO_AAC, MimeTypes.AUDIO_AMR_NB, MimeTypes.AUDIO_AMR_WB); private static final String TAG = "FrameworkMuxer"; + private static final int TRACK_ID_UNSET = -1; private final MediaMuxer mediaMuxer; private final long videoDurationUs; - private final Map trackTokenToLastPresentationTimeUs; - private final Map trackTokenToPresentationTimeOffsetUs; + private final SparseArray trackIdToLastPresentationTimeUs; + private final SparseArray trackIdToPresentationTimeOffsetUs; - @Nullable private TrackToken videoTrackToken; + private int videoTrackId; private boolean isStarted; private boolean isReleased; @@ -119,12 +118,13 @@ import java.util.Map; private FrameworkMuxer(MediaMuxer mediaMuxer, long videoDurationUs) { this.mediaMuxer = mediaMuxer; this.videoDurationUs = videoDurationUs; - trackTokenToLastPresentationTimeUs = new HashMap<>(); - trackTokenToPresentationTimeOffsetUs = new HashMap<>(); + trackIdToLastPresentationTimeUs = new SparseArray<>(); + trackIdToPresentationTimeOffsetUs = new SparseArray<>(); + videoTrackId = TRACK_ID_UNSET; } @Override - public TrackToken addTrack(Format format) throws MuxerException { + public int addTrack(Format format) throws MuxerException { String sampleMimeType = checkNotNull(format.sampleMimeType); MediaFormat mediaFormat; boolean isVideo = MimeTypes.isVideo(sampleMimeType); @@ -150,20 +150,19 @@ import java.util.Map; throw new MuxerException("Failed to add track with format=" + format, e); } - TrackToken trackToken = new TrackTokenImpl(trackIndex); if (isVideo) { - videoTrackToken = trackToken; + videoTrackId = trackIndex; } - return trackToken; + return trackIndex; } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { long presentationTimeUs = bufferInfo.presentationTimeUs; if (videoDurationUs != C.TIME_UNSET - && trackToken == videoTrackToken + && trackId == videoTrackId && presentationTimeUs > videoDurationUs) { Log.w( TAG, @@ -176,20 +175,18 @@ import java.util.Map; } if (!isStarted) { if (Util.SDK_INT < 30 && presentationTimeUs < 0) { - trackTokenToPresentationTimeOffsetUs.put(trackToken, -presentationTimeUs); + trackIdToPresentationTimeOffsetUs.put(trackId, -presentationTimeUs); } startMuxer(); } long presentationTimeOffsetUs = - trackTokenToPresentationTimeOffsetUs.containsKey(trackToken) - ? trackTokenToPresentationTimeOffsetUs.get(trackToken) - : 0; + trackIdToPresentationTimeOffsetUs.get(trackId, /* valueIfKeyNotFound= */ 0L); presentationTimeUs += presentationTimeOffsetUs; long lastSamplePresentationTimeUs = - trackTokenToLastPresentationTimeUs.containsKey(trackToken) - ? trackTokenToLastPresentationTimeUs.get(trackToken) + Util.contains(trackIdToLastPresentationTimeUs, trackId) + ? trackIdToLastPresentationTimeUs.get(trackId) : 0; // writeSampleData blocks on old API versions, so check here to avoid calling the method. checkState( @@ -199,7 +196,7 @@ import java.util.Map; + " < " + lastSamplePresentationTimeUs + ") unsupported on this API version"); - trackTokenToLastPresentationTimeUs.put(trackToken, presentationTimeUs); + trackIdToLastPresentationTimeUs.put(trackId, presentationTimeUs); checkState( presentationTimeOffsetUs == 0 || presentationTimeUs >= 0, @@ -212,8 +209,8 @@ import java.util.Map; bufferInfo.set(bufferInfo.offset, bufferInfo.size, presentationTimeUs, bufferInfo.flags); try { - checkState(trackToken instanceof TrackTokenImpl); - mediaMuxer.writeSampleData(((TrackTokenImpl) trackToken).trackIndex, data, bufferInfo); + + mediaMuxer.writeSampleData(trackId, data, bufferInfo); } catch (RuntimeException e) { throw new MuxerException( "Failed to write sample for presentationTimeUs=" @@ -244,14 +241,14 @@ import java.util.Map; startMuxer(); } - if (videoDurationUs != C.TIME_UNSET && videoTrackToken != null) { + if (videoDurationUs != C.TIME_UNSET && videoTrackId != TRACK_ID_UNSET) { BufferInfo bufferInfo = new BufferInfo(); bufferInfo.set( /* newOffset= */ 0, /* newSize= */ 0, videoDurationUs, TransformerUtil.getMediaCodecFlags(C.BUFFER_FLAG_END_OF_STREAM)); - writeSampleData(checkNotNull(videoTrackToken), ByteBuffer.allocateDirect(0), bufferInfo); + writeSampleData(videoTrackId, ByteBuffer.allocateDirect(0), bufferInfo); } isStarted = false; @@ -314,12 +311,4 @@ import java.util.Map; } return supportedMimeTypes.build(); } - - private static class TrackTokenImpl implements TrackToken { - public final int trackIndex; - - public TrackTokenImpl(int trackIndex) { - this.trackIndex = trackIndex; - } - } } 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 5d7ef25b54..ddfd1fc325 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/InAppMuxer.java @@ -15,7 +15,6 @@ */ package androidx.media3.transformer; -import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.muxer.Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS; import android.media.MediaCodec; @@ -207,13 +206,14 @@ public final class InAppMuxer implements Muxer { } private static final String TAG = "InAppMuxer"; + private static final int TRACK_ID_UNSET = -1; private final Muxer muxer; @Nullable private final MetadataProvider metadataProvider; private final long videoDurationUs; private final Set metadataEntries; - @Nullable private TrackToken videoTrackToken; + private int videoTrackId; private InAppMuxer( Muxer muxer, @Nullable MetadataProvider metadataProvider, long videoDurationUs) { @@ -221,23 +221,24 @@ public final class InAppMuxer implements Muxer { this.metadataProvider = metadataProvider; this.videoDurationUs = videoDurationUs; metadataEntries = new LinkedHashSet<>(); + videoTrackId = TRACK_ID_UNSET; } @Override - public TrackToken addTrack(Format format) throws MuxerException { - TrackToken trackToken = muxer.addTrack(format); + public int addTrack(Format format) throws MuxerException { + int trackId = muxer.addTrack(format); if (MimeTypes.isVideo(format.sampleMimeType)) { muxer.addMetadataEntry(new Mp4OrientationData(format.rotationDegrees)); - videoTrackToken = trackToken; + videoTrackId = trackId; } - return trackToken; + return trackId; } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer byteBuffer, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo) throws MuxerException { if (videoDurationUs != C.TIME_UNSET - && trackToken == videoTrackToken + && trackId == videoTrackId && bufferInfo.presentationTimeUs > videoDurationUs) { Log.w( TAG, @@ -248,7 +249,7 @@ public final class InAppMuxer implements Muxer { videoDurationUs)); return; } - muxer.writeSampleData(trackToken, byteBuffer, bufferInfo); + muxer.writeSampleData(trackId, byteBuffer, bufferInfo); } @Override @@ -260,14 +261,14 @@ public final class InAppMuxer implements Muxer { @Override public void close() throws MuxerException { - if (videoDurationUs != C.TIME_UNSET && videoTrackToken != null) { + if (videoDurationUs != C.TIME_UNSET && videoTrackId != TRACK_ID_UNSET) { BufferInfo bufferInfo = new BufferInfo(); bufferInfo.set( /* newOffset= */ 0, /* newSize= */ 0, videoDurationUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); - writeSampleData(checkNotNull(videoTrackToken), ByteBuffer.allocateDirect(0), bufferInfo); + writeSampleData(videoTrackId, ByteBuffer.allocateDirect(0), bufferInfo); } writeMetadata(); muxer.close(); 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 01283632ba..b8c96dcb90 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java @@ -48,7 +48,6 @@ import androidx.media3.common.util.Util; import androidx.media3.container.NalUnitUtil; import androidx.media3.effect.DebugTraceUtil; import androidx.media3.muxer.Muxer; -import androidx.media3.muxer.Muxer.TrackToken; import androidx.media3.muxer.MuxerException; import com.google.common.collect.ImmutableList; import java.io.File; @@ -580,7 +579,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; data.remaining(), presentationTimeUs, TransformerUtil.getMediaCodecFlags(isKeyFrame ? C.BUFFER_FLAG_KEY_FRAME : 0)); - muxer.writeSampleData(trackInfo.trackToken, data, bufferInfo); + muxer.writeSampleData(trackInfo.trackId, data, bufferInfo); DebugTraceUtil.logEvent( COMPONENT_MUXER, @@ -749,16 +748,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private static final class TrackInfo { public final Format format; - public final TrackToken trackToken; + public final int trackId; public long startTimeUs; public long bytesWritten; public int sampleCount; public long timeUs; - public TrackInfo(Format format, TrackToken trackToken) { + public TrackInfo(Format format, int trackId) { this.format = format; - this.trackToken = trackToken; + this.trackId = trackId; } /** diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/NoWriteMuxer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/NoWriteMuxer.java index 6f25d63ecb..b02d948f19 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/NoWriteMuxer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/NoWriteMuxer.java @@ -63,13 +63,12 @@ import java.nio.ByteBuffer; } @Override - public TrackToken addTrack(Format format) { - return new TrackToken() {}; + public int addTrack(Format format) { + return 0; } @Override - public void writeSampleData( - TrackToken trackToken, ByteBuffer data, MediaCodec.BufferInfo bufferInfo) {} + public void writeSampleData(int trackId, ByteBuffer data, MediaCodec.BufferInfo bufferInfo) {} @Override public void addMetadataEntry(Metadata.Entry metadataEntry) {} 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 ed0868548b..c969591651 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/CapturingMuxer.java @@ -38,8 +38,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; /** * A {@link Dumpable} {@link Muxer} implementation that supports dumping information about all @@ -88,7 +86,7 @@ public final class CapturingMuxer implements Muxer, Dumpable { private final boolean handleAudioAsPcm; private final SparseArray dumpableFormatByTrackType; private final SparseArray dumpableStreamByTrackType; - private final Map trackTokenToType; + private final SparseArray trackIdToType; private final ArrayList metadataList; private boolean released; @@ -98,18 +96,18 @@ public final class CapturingMuxer implements Muxer, Dumpable { this.handleAudioAsPcm = handleAudioAsPcm; dumpableFormatByTrackType = new SparseArray<>(); dumpableStreamByTrackType = new SparseArray<>(); - trackTokenToType = new HashMap<>(); + trackIdToType = new SparseArray<>(); metadataList = new ArrayList<>(); } // Muxer implementation. @Override - public TrackToken addTrack(Format format) throws MuxerException { - TrackToken trackToken = wrappedMuxer.addTrack(format); + public int addTrack(Format format) throws MuxerException { + int trackId = wrappedMuxer.addTrack(format); @C.TrackType int trackType = getProcessedTrackType(format.sampleMimeType); - trackTokenToType.put(trackToken, trackType); + trackIdToType.put(trackId, trackType); dumpableFormatByTrackType.append( trackType, new DumpableFormat(format, /* tag= */ Util.getTrackTypeString(trackType))); @@ -120,20 +118,20 @@ public final class CapturingMuxer implements Muxer, Dumpable { ? new DumpablePcmAudioStream(trackType) : new DumpableStream(trackType)); - return trackToken; + return trackId; } @Override - public void writeSampleData(TrackToken trackToken, ByteBuffer data, BufferInfo bufferInfo) + public void writeSampleData(int trackId, ByteBuffer data, BufferInfo bufferInfo) throws MuxerException { - @C.TrackType int trackType = checkNotNull(trackTokenToType.get(trackToken)); + @C.TrackType int trackType = checkNotNull(trackIdToType.get(trackId)); dumpableStreamByTrackType .get(trackType) .addSample( data, (bufferInfo.flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME, bufferInfo.presentationTimeUs); - wrappedMuxer.writeSampleData(trackToken, data, bufferInfo); + wrappedMuxer.writeSampleData(trackId, data, bufferInfo); } @Override