Change muxer instrumentation tests to robolectric

These tests were earlier using `MediaExtractor`, hence
they were in androidTest. Now `MediaExtractor` has been
replaced with `media3 MediaExtractorCompat` so these
test can be robolectric.

PiperOrigin-RevId: 715424470
This commit is contained in:
sheenachhabra 2025-01-14 10:02:17 -08:00 committed by Copybara-Service
parent fbf9be2f00
commit 1b2e391971
7 changed files with 143 additions and 235 deletions

View File

@ -58,12 +58,12 @@ dependencies {
testImplementation project(modulePrefix + 'test-data') testImplementation project(modulePrefix + 'test-data')
testImplementation 'org.robolectric:robolectric:' + robolectricVersion testImplementation 'org.robolectric:robolectric:' + robolectricVersion
testImplementation 'com.google.truth:truth:' + truthVersion testImplementation 'com.google.truth:truth:' + truthVersion
testImplementation project(modulePrefix + 'lib-exoplayer')
androidTestImplementation 'junit:junit:' + junitVersion androidTestImplementation 'junit:junit:' + junitVersion
androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion
androidTestImplementation 'com.google.truth:truth:' + truthVersion androidTestImplementation 'com.google.truth:truth:' + truthVersion
androidTestImplementation project(modulePrefix + 'test-utils') androidTestImplementation project(modulePrefix + 'test-utils')
androidTestImplementation project(modulePrefix + 'lib-extractor') androidTestImplementation project(modulePrefix + 'lib-extractor')
androidTestImplementation project(modulePrefix + 'lib-exoplayer')
} }
ext { ext {

View File

@ -1,75 +0,0 @@
/*
* Copyright 2023 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.muxer;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaCodec;
import androidx.media3.common.util.MediaFormatUtil;
import androidx.media3.exoplayer.MediaExtractorCompat;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/** Utilities for muxer test cases. */
/* package */ final class AndroidMuxerTestUtil {
private static final String MP4_FILE_ASSET_DIRECTORY = "media/mp4/";
private static final String DUMP_FILE_OUTPUT_DIRECTORY = "muxerdumps";
private static final String DUMP_FILE_EXTENSION = "dump";
private AndroidMuxerTestUtil() {}
public static String getExpectedDumpFilePath(String originalFileName) {
return DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '.' + DUMP_FILE_EXTENSION;
}
public static void feedInputDataToMuxer(Context context, Muxer muxer, String inputFileName)
throws IOException, MuxerException {
MediaExtractorCompat extractor = new MediaExtractorCompat(context);
AssetFileDescriptor fd =
context.getResources().getAssets().openFd(MP4_FILE_ASSET_DIRECTORY + inputFileName);
extractor.setDataSource(fd);
List<Integer> addedTracks = new ArrayList<>();
for (int i = 0; i < extractor.getTrackCount(); i++) {
int trackId =
muxer.addTrack(MediaFormatUtil.createFormatFromMediaFormat(extractor.getTrackFormat(i)));
addedTracks.add(trackId);
extractor.selectTrack(i);
}
do {
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.flags = extractor.getSampleFlags();
bufferInfo.offset = 0;
bufferInfo.presentationTimeUs = extractor.getSampleTime();
int sampleSize = (int) extractor.getSampleSize();
bufferInfo.size = sampleSize;
ByteBuffer sampleBuffer = ByteBuffer.allocateDirect(sampleSize);
extractor.readSampleData(sampleBuffer, /* offset= */ 0);
sampleBuffer.rewind();
muxer.writeSampleData(
addedTracks.get(extractor.getSampleTrackIndex()), sampleBuffer, bufferInfo);
} while (extractor.advance());
extractor.release();
fd.close();
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright 2023 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.muxer;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.muxer.AndroidMuxerTestUtil.feedInputDataToMuxer;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.media3.container.Mp4TimestampData;
import androidx.media3.extractor.mp4.Mp4Extractor;
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
import androidx.media3.test.utils.DumpFileAsserts;
import androidx.media3.test.utils.FakeExtractorOutput;
import androidx.media3.test.utils.TestUtil;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.FileOutputStream;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
/** End to end instrumentation tests for {@link Mp4Muxer}. */
@RunWith(AndroidJUnit4.class)
public class Mp4MuxerEndToEndNonParameterizedAndroidTest {
private static final String H265_HDR10_MP4 = "hdr10-720p.mp4";
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
private final Context context = ApplicationProvider.getApplicationContext();
private @MonotonicNonNull String outputPath;
private @MonotonicNonNull FileOutputStream outputStream;
@Before
public void setUp() throws Exception {
outputPath = temporaryFolder.newFile("muxeroutput.mp4").getPath();
outputStream = new FileOutputStream(outputPath);
}
@After
public void tearDown() throws IOException {
checkNotNull(outputStream).close();
}
@Test
public void createMp4File_muxerNotClosed_createsPartiallyWrittenValidFile() throws Exception {
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(checkNotNull(outputStream)).build();
mp4Muxer.addMetadataEntry(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
feedInputDataToMuxer(context, mp4Muxer, H265_HDR10_MP4);
// Muxer not closed.
// Audio sample written = 192 out of 195.
// Video sample written = 125 out of 127.
// Output is still a valid MP4 file.
FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(new Mp4Extractor(), checkNotNull(outputPath));
DumpFileAsserts.assertOutput(
context,
fakeExtractorOutput,
AndroidMuxerTestUtil.getExpectedDumpFilePath("partial_" + H265_HDR10_MP4));
}
@Test
public void createMp4File_withSampleBatchingDisabled_matchesExpected() throws Exception {
@Nullable Mp4Muxer mp4Muxer = null;
try {
mp4Muxer =
new Mp4Muxer.Builder(checkNotNull(outputStream)).setSampleBatchingEnabled(false).build();
mp4Muxer.addMetadataEntry(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
feedInputDataToMuxer(context, mp4Muxer, checkNotNull(H265_HDR10_MP4));
} finally {
if (mp4Muxer != null) {
mp4Muxer.close();
}
}
FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(
new Mp4Extractor(new DefaultSubtitleParserFactory()), checkNotNull(outputPath));
DumpFileAsserts.assertOutput(
context,
fakeExtractorOutput,
AndroidMuxerTestUtil.getExpectedDumpFilePath("sample_batching_disabled_" + H265_HDR10_MP4));
}
@Test
public void createMp4File_withSampleBatchingAndAttemptStreamableOutputDisabled_matchesExpected()
throws Exception {
@Nullable Mp4Muxer mp4Muxer = null;
try {
mp4Muxer =
new Mp4Muxer.Builder(checkNotNull(outputStream))
.setSampleBatchingEnabled(false)
.setAttemptStreamableOutputEnabled(false)
.build();
mp4Muxer.addMetadataEntry(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
feedInputDataToMuxer(context, mp4Muxer, checkNotNull(H265_HDR10_MP4));
} finally {
if (mp4Muxer != null) {
mp4Muxer.close();
}
}
FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(
new Mp4Extractor(new DefaultSubtitleParserFactory()), checkNotNull(outputPath));
DumpFileAsserts.assertOutput(
context,
fakeExtractorOutput,
AndroidMuxerTestUtil.getExpectedDumpFilePath(
"sample_batching_and_attempt_streamable_output_disabled_" + H265_HDR10_MP4));
}
}

View File

@ -16,7 +16,7 @@
package androidx.media3.muxer; package androidx.media3.muxer;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.muxer.AndroidMuxerTestUtil.feedInputDataToMuxer; import static androidx.media3.muxer.MuxerTestUtil.feedInputDataToMuxer;
import android.content.Context; import android.content.Context;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -38,13 +38,13 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.robolectric.ParameterizedRobolectricTestRunner;
import org.junit.runners.Parameterized.Parameter; import org.robolectric.ParameterizedRobolectricTestRunner.Parameter;
import org.junit.runners.Parameterized.Parameters; import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
/** End to end instrumentation tests for {@link FragmentedMp4Muxer}. */ /** End to end instrumentation tests for {@link FragmentedMp4Muxer}. */
@RunWith(Parameterized.class) @RunWith(ParameterizedRobolectricTestRunner.class)
public class FragmentedMp4MuxerEndToEndAndroidTest { public class FragmentedMp4MuxerEndToEndTest {
private static final String H264_WITH_PYRAMID_B_FRAMES_MP4 = private static final String H264_WITH_PYRAMID_B_FRAMES_MP4 =
"bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4"; "bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4";
private static final String H265_HDR10_MP4 = "hdr10-720p.mp4"; private static final String H265_HDR10_MP4 = "hdr10-720p.mp4";
@ -96,7 +96,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest {
DumpFileAsserts.assertOutput( DumpFileAsserts.assertOutput(
context, context,
fakeExtractorOutput, fakeExtractorOutput,
AndroidMuxerTestUtil.getExpectedDumpFilePath(inputFile + "_fragmented")); MuxerTestUtil.getExpectedDumpFilePath(inputFile + "_fragmented"));
} }
@Test @Test
@ -123,6 +123,6 @@ public class FragmentedMp4MuxerEndToEndAndroidTest {
DumpFileAsserts.assertOutput( DumpFileAsserts.assertOutput(
context, context,
dumpableMp4Box, dumpableMp4Box,
AndroidMuxerTestUtil.getExpectedDumpFilePath(H265_HDR10_MP4 + "_fragmented_box_structure")); MuxerTestUtil.getExpectedDumpFilePath(H265_HDR10_MP4 + "_fragmented_box_structure"));
} }
} }

View File

@ -16,7 +16,7 @@
package androidx.media3.muxer; package androidx.media3.muxer;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.muxer.AndroidMuxerTestUtil.feedInputDataToMuxer; import static androidx.media3.muxer.MuxerTestUtil.feedInputDataToMuxer;
import android.content.Context; import android.content.Context;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -36,13 +36,13 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.robolectric.ParameterizedRobolectricTestRunner;
import org.junit.runners.Parameterized.Parameter; import org.robolectric.ParameterizedRobolectricTestRunner.Parameter;
import org.junit.runners.Parameterized.Parameters; import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
/** End to end parameterized instrumentation tests for {@link Mp4Muxer}. */ /** End to end parameterized tests for {@link Mp4Muxer}. */
@RunWith(Parameterized.class) @RunWith(ParameterizedRobolectricTestRunner.class)
public class Mp4MuxerEndToEndParameterizedAndroidTest { public class Mp4MuxerEndToEndParameterizedTest {
// Video Codecs // Video Codecs
private static final String H263_3GP = "bbb_176x144_128kbps_15fps_h263.3gp"; private static final String H263_3GP = "bbb_176x144_128kbps_15fps_h263.3gp";
private static final String H264_MP4 = "sample_no_bframes.mp4"; private static final String H264_MP4 = "sample_no_bframes.mp4";
@ -126,6 +126,6 @@ public class Mp4MuxerEndToEndParameterizedAndroidTest {
FakeExtractorOutput fakeExtractorOutput = FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(new Mp4Extractor(), checkNotNull(outputPath)); TestUtil.extractAllSamplesFromFilePath(new Mp4Extractor(), checkNotNull(outputPath));
DumpFileAsserts.assertOutput( DumpFileAsserts.assertOutput(
context, fakeExtractorOutput, AndroidMuxerTestUtil.getExpectedDumpFilePath(inputFile)); context, fakeExtractorOutput, MuxerTestUtil.getExpectedDumpFilePath(inputFile));
} }
} }

View File

@ -15,9 +15,11 @@
*/ */
package androidx.media3.muxer; package androidx.media3.muxer;
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 static androidx.media3.muxer.Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS;
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT; import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA; import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA;
import static androidx.media3.muxer.MuxerTestUtil.feedInputDataToMuxer;
import static androidx.media3.muxer.MuxerTestUtil.getFakeSampleAndSampleInfo; import static androidx.media3.muxer.MuxerTestUtil.getFakeSampleAndSampleInfo;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
@ -53,6 +55,7 @@ import org.junit.runner.RunWith;
public class Mp4MuxerEndToEndTest { public class Mp4MuxerEndToEndTest {
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
private static final String H265_HDR10_MP4 = "hdr10-720p.mp4";
private final Context context = ApplicationProvider.getApplicationContext(); private final Context context = ApplicationProvider.getApplicationContext();
@Test @Test
@ -117,6 +120,30 @@ public class Mp4MuxerEndToEndTest {
assertThat(outputFileBytes).isEmpty(); assertThat(outputFileBytes).isEmpty();
} }
@Test
public void createMp4File_muxerNotClosed_createsPartiallyWrittenValidFile() throws Exception {
String outputPath = temporaryFolder.newFile().getPath();
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputPath)).build();
mp4Muxer.addMetadataEntry(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
feedInputDataToMuxer(context, mp4Muxer, H265_HDR10_MP4);
// Muxer not closed.
// Audio sample written = 192 out of 195.
// Video sample written = 125 out of 127.
// Output is still a valid MP4 file.
FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(
new Mp4Extractor(new DefaultSubtitleParserFactory()), checkNotNull(outputPath));
DumpFileAsserts.assertOutput(
context,
fakeExtractorOutput,
MuxerTestUtil.getExpectedDumpFilePath("partial_" + H265_HDR10_MP4));
}
@Test @Test
public void createMp4File_withSameTracksOffset_matchesExpected() throws Exception { public void createMp4File_withSameTracksOffset_matchesExpected() throws Exception {
String outputFilePath = temporaryFolder.newFile().getPath(); String outputFilePath = temporaryFolder.newFile().getPath();
@ -813,6 +840,63 @@ public class Mp4MuxerEndToEndTest {
assertThat(fakeExtractorOutput.seekMap.getDurationUs()).isEqualTo(400L); assertThat(fakeExtractorOutput.seekMap.getDurationUs()).isEqualTo(400L);
} }
@Test
public void createMp4File_withSampleBatchingDisabled_matchesExpected() throws Exception {
String outputPath = temporaryFolder.newFile().getPath();
Mp4Muxer mp4Muxer =
new Mp4Muxer.Builder(new FileOutputStream(outputPath))
.setSampleBatchingEnabled(false)
.build();
mp4Muxer.addMetadataEntry(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
try {
feedInputDataToMuxer(context, mp4Muxer, checkNotNull(H265_HDR10_MP4));
} finally {
mp4Muxer.close();
}
FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(
new Mp4Extractor(new DefaultSubtitleParserFactory()), checkNotNull(outputPath));
DumpFileAsserts.assertOutput(
context,
fakeExtractorOutput,
MuxerTestUtil.getExpectedDumpFilePath("sample_batching_disabled_" + H265_HDR10_MP4));
}
@Test
public void createMp4File_withSampleBatchingAndAttemptStreamableOutputDisabled_matchesExpected()
throws Exception {
String outputPath = temporaryFolder.newFile().getPath();
Mp4Muxer mp4Muxer =
new Mp4Muxer.Builder(new FileOutputStream(outputPath))
.setSampleBatchingEnabled(false)
.setAttemptStreamableOutputEnabled(false)
.build();
mp4Muxer.addMetadataEntry(
new Mp4TimestampData(
/* creationTimestampSeconds= */ 100_000_000L,
/* modificationTimestampSeconds= */ 500_000_000L));
try {
feedInputDataToMuxer(context, mp4Muxer, checkNotNull(H265_HDR10_MP4));
} finally {
mp4Muxer.close();
}
FakeExtractorOutput fakeExtractorOutput =
TestUtil.extractAllSamplesFromFilePath(
new Mp4Extractor(new DefaultSubtitleParserFactory()), checkNotNull(outputPath));
DumpFileAsserts.assertOutput(
context,
fakeExtractorOutput,
MuxerTestUtil.getExpectedDumpFilePath(
"sample_batching_and_attempt_streamable_output_disabled_" + H265_HDR10_MP4));
}
private static void writeFakeSamples(Mp4Muxer muxer, int trackId, int sampleCount) private static void writeFakeSamples(Mp4Muxer muxer, int trackId, int sampleCount)
throws MuxerException { throws MuxerException {
for (int i = 0; i < sampleCount; i++) { for (int i = 0; i < sampleCount; i++) {

View File

@ -18,13 +18,20 @@ package androidx.media3.muxer;
import static androidx.media3.common.MimeTypes.AUDIO_AAC; import static androidx.media3.common.MimeTypes.AUDIO_AAC;
import static androidx.media3.common.MimeTypes.VIDEO_H264; import static androidx.media3.common.MimeTypes.VIDEO_H264;
import android.content.Context;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo; import android.media.MediaCodec.BufferInfo;
import android.net.Uri;
import android.util.Pair; import android.util.Pair;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.util.MediaFormatUtil;
import androidx.media3.exoplayer.MediaExtractorCompat;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.io.BaseEncoding; import com.google.common.io.BaseEncoding;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/** Utilities for muxer test cases. */ /** Utilities for muxer test cases. */
/* package */ class MuxerTestUtil { /* package */ class MuxerTestUtil {
@ -53,6 +60,7 @@ import java.nio.ByteBuffer;
.decode( .decode(
"0000000167F4000A919B2BF3CB3640000003004000000C83C48965800000000168EBE3C448000001658884002BFFFEF5DBF32CAE4A43FF"); "0000000167F4000A919B2BF3CB3640000003004000000C83C48965800000000168EBE3C448000001658884002BFFFEF5DBF32CAE4A43FF");
private static final String MP4_FILE_ASSET_DIRECTORY = "asset:///media/mp4/";
private static final String DUMP_FILE_OUTPUT_DIRECTORY = "muxerdumps"; private static final String DUMP_FILE_OUTPUT_DIRECTORY = "muxerdumps";
private static final String DUMP_FILE_EXTENSION = "dump"; private static final String DUMP_FILE_EXTENSION = "dump";
@ -73,5 +81,39 @@ import java.nio.ByteBuffer;
return new Pair<>(sampleDirectBuffer, bufferInfo); return new Pair<>(sampleDirectBuffer, bufferInfo);
} }
public static void feedInputDataToMuxer(Context context, Muxer muxer, String inputFileName)
throws IOException, MuxerException {
MediaExtractorCompat extractor = new MediaExtractorCompat(context);
Uri fileUri = Uri.parse(MP4_FILE_ASSET_DIRECTORY + inputFileName);
extractor.setDataSource(fileUri, /* offset= */ 0);
List<Integer> addedTracks = new ArrayList<>();
for (int i = 0; i < extractor.getTrackCount(); i++) {
int trackId =
muxer.addTrack(MediaFormatUtil.createFormatFromMediaFormat(extractor.getTrackFormat(i)));
addedTracks.add(trackId);
extractor.selectTrack(i);
}
do {
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.flags = extractor.getSampleFlags();
bufferInfo.offset = 0;
bufferInfo.presentationTimeUs = extractor.getSampleTime();
int sampleSize = (int) extractor.getSampleSize();
bufferInfo.size = sampleSize;
ByteBuffer sampleBuffer = ByteBuffer.allocateDirect(sampleSize);
extractor.readSampleData(sampleBuffer, /* offset= */ 0);
sampleBuffer.rewind();
muxer.writeSampleData(
addedTracks.get(extractor.getSampleTrackIndex()), sampleBuffer, bufferInfo);
} while (extractor.advance());
extractor.release();
}
private MuxerTestUtil() {} private MuxerTestUtil() {}
} }