Split TransformerEndToEndTest
Split test/ TransformerEndToEndTest into SingleMediaItemEndToEndTest and SingleSequenceEndToEndTest to reduce the file size and split the tests by category. PiperOrigin-RevId: 515039502
This commit is contained in:
parent
bf60302cf2
commit
6d623bfad7
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.transformer;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.transformer.TestUtil.ASSET_URI_PREFIX;
|
||||
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_VIDEO;
|
||||
import static androidx.media3.transformer.TestUtil.createEncodersAndDecoders;
|
||||
import static androidx.media3.transformer.TestUtil.createTransformerBuilder;
|
||||
import static androidx.media3.transformer.TestUtil.getDumpFileName;
|
||||
import static androidx.media3.transformer.TestUtil.removeEncodersAndDecoders;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.media3.common.Effect;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.effect.RgbFilter;
|
||||
import androidx.media3.test.utils.DumpFileAsserts;
|
||||
import androidx.media3.transformer.TestUtil.TestMuxerFactory.TestMuxerHolder;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* End-to-end test for exporting a single {@link EditedMediaItemSequence} containing multiple {@link
|
||||
* EditedMediaItem} instances with {@link Transformer}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class SequenceExportTest {
|
||||
|
||||
private Context context;
|
||||
private String outputPath;
|
||||
private TestMuxerHolder testMuxerHolder;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
context = ApplicationProvider.getApplicationContext();
|
||||
outputPath = Util.createTempFile(context, "TransformerTest").getPath();
|
||||
testMuxerHolder = new TestMuxerHolder();
|
||||
createEncodersAndDecoders();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
Files.delete(Paths.get(outputPath));
|
||||
removeEncodersAndDecoders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_concatenateMediaItemsWithSameFormat_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem).build();
|
||||
EditedMediaItemSequence editedMediaItemSequence =
|
||||
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem, editedMediaItem));
|
||||
Composition composition =
|
||||
new Composition.Builder(ImmutableList.of(editedMediaItemSequence))
|
||||
.setTransmuxAudio(true)
|
||||
.setTransmuxVideo(true)
|
||||
.build();
|
||||
|
||||
transformer.start(composition, outputPath);
|
||||
TransformerTestRunner.runLooper(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
checkNotNull(testMuxerHolder.testMuxer),
|
||||
getDumpFileName(FILE_AUDIO_VIDEO + ".concatenated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_concatenateMediaItemsWithSameFormatAndEffects_completesSuccessfully()
|
||||
throws Exception {
|
||||
Transformer transformer =
|
||||
createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
|
||||
sonicAudioProcessor.setPitch(2f);
|
||||
Effects effects =
|
||||
new Effects(ImmutableList.of(sonicAudioProcessor), /* videoEffects= */ ImmutableList.of());
|
||||
// The video track must be removed in order for the export to end. Indeed, the
|
||||
// Robolectric decoder just copies the input buffers to the output and the audio timestamps are
|
||||
// therefore computed based on the encoded samples (see [internal: b/178685617]). As a result,
|
||||
// the audio timestamps are much smaller than they should be and the muxer waits for more audio
|
||||
// samples before writing video samples.
|
||||
EditedMediaItem editedMediaItem =
|
||||
new EditedMediaItem.Builder(mediaItem).setEffects(effects).setRemoveVideo(true).build();
|
||||
EditedMediaItemSequence editedMediaItemSequence =
|
||||
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem, editedMediaItem));
|
||||
Composition composition =
|
||||
new Composition.Builder(ImmutableList.of(editedMediaItemSequence)).build();
|
||||
|
||||
transformer.start(composition, outputPath);
|
||||
TransformerTestRunner.runLooper(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
checkNotNull(testMuxerHolder.testMuxer),
|
||||
getDumpFileName(FILE_AUDIO_VIDEO + ".concatenated_with_high_pitch_and_no_video"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_concatenateSilenceAndAudio_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
EditedMediaItem noAudioEditedMediaItem =
|
||||
new EditedMediaItem.Builder(mediaItem).setRemoveAudio(true).build();
|
||||
EditedMediaItem audioEditedMediaItem = new EditedMediaItem.Builder(mediaItem).build();
|
||||
EditedMediaItemSequence sequence =
|
||||
new EditedMediaItemSequence(ImmutableList.of(noAudioEditedMediaItem, audioEditedMediaItem));
|
||||
Composition composition =
|
||||
new Composition.Builder(ImmutableList.of(sequence))
|
||||
.experimentalSetForceAudioTrack(true)
|
||||
.setTransmuxVideo(true)
|
||||
.build();
|
||||
|
||||
transformer.start(composition, outputPath);
|
||||
TransformerTestRunner.runLooper(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
checkNotNull(testMuxerHolder.testMuxer),
|
||||
getDumpFileName(FILE_AUDIO_VIDEO + ".silence_then_audio"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_concatenateSilenceAndAudioWithEffects_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
|
||||
sonicAudioProcessor.setPitch(2f);
|
||||
Effects effects =
|
||||
new Effects(ImmutableList.of(sonicAudioProcessor), /* videoEffects= */ ImmutableList.of());
|
||||
EditedMediaItem noAudioEditedMediaItem =
|
||||
new EditedMediaItem.Builder(mediaItem).setRemoveAudio(true).setEffects(effects).build();
|
||||
EditedMediaItem audioEditedMediaItem =
|
||||
new EditedMediaItem.Builder(mediaItem).setEffects(effects).build();
|
||||
EditedMediaItemSequence sequence =
|
||||
new EditedMediaItemSequence(ImmutableList.of(noAudioEditedMediaItem, audioEditedMediaItem));
|
||||
Composition composition =
|
||||
new Composition.Builder(ImmutableList.of(sequence))
|
||||
.experimentalSetForceAudioTrack(true)
|
||||
.setTransmuxVideo(true)
|
||||
.build();
|
||||
|
||||
transformer.start(composition, outputPath);
|
||||
TransformerTestRunner.runLooper(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
checkNotNull(testMuxerHolder.testMuxer),
|
||||
getDumpFileName(FILE_AUDIO_VIDEO + ".silence_then_audio_with_effects"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_multipleMediaItemsAndTransmux_transmux() throws Exception {
|
||||
Transformer transformer =
|
||||
createTransformerBuilder(testMuxerHolder, /* enableFallback= */ false).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
|
||||
sonicAudioProcessor.setPitch(2f);
|
||||
Effect videoEffect = RgbFilter.createGrayscaleFilter();
|
||||
Effects effects =
|
||||
new Effects(ImmutableList.of(sonicAudioProcessor), ImmutableList.of(videoEffect));
|
||||
EditedMediaItem editedMediaItem =
|
||||
new EditedMediaItem.Builder(mediaItem).setEffects(effects).build();
|
||||
EditedMediaItemSequence editedMediaItemSequence =
|
||||
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem, editedMediaItem));
|
||||
Composition composition =
|
||||
new Composition.Builder(ImmutableList.of(editedMediaItemSequence))
|
||||
.setTransmuxAudio(true)
|
||||
.setTransmuxVideo(true)
|
||||
.build();
|
||||
|
||||
transformer.start(composition, outputPath);
|
||||
TransformerTestRunner.runLooper(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
checkNotNull(testMuxerHolder.testMuxer),
|
||||
getDumpFileName(FILE_AUDIO_VIDEO + ".concatenated"));
|
||||
}
|
||||
}
|
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.transformer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Looper;
|
||||
import android.view.Surface;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.test.utils.FakeClock;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.primitives.Ints;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.robolectric.shadows.MediaCodecInfoBuilder;
|
||||
import org.robolectric.shadows.ShadowMediaCodec;
|
||||
import org.robolectric.shadows.ShadowMediaCodecList;
|
||||
|
||||
/** Utility class for {@link Transformer} unit tests */
|
||||
@UnstableApi
|
||||
public final class TestUtil {
|
||||
|
||||
public static final class TestMuxerFactory implements Muxer.Factory {
|
||||
|
||||
public static final class TestMuxerHolder {
|
||||
@Nullable public TestMuxer testMuxer;
|
||||
}
|
||||
|
||||
private final TestMuxerHolder testMuxerHolder;
|
||||
private final Muxer.Factory defaultMuxerFactory;
|
||||
|
||||
public TestMuxerFactory(TestMuxerHolder testMuxerHolder) {
|
||||
this(testMuxerHolder, /* maxDelayBetweenSamplesMs= */ C.TIME_UNSET);
|
||||
}
|
||||
|
||||
public TestMuxerFactory(TestMuxerHolder testMuxerHolder, long maxDelayBetweenSamplesMs) {
|
||||
this.testMuxerHolder = testMuxerHolder;
|
||||
defaultMuxerFactory = new DefaultMuxer.Factory(maxDelayBetweenSamplesMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Muxer create(String path) throws Muxer.MuxerException {
|
||||
testMuxerHolder.testMuxer = new TestMuxer(path, defaultMuxerFactory);
|
||||
return testMuxerHolder.testMuxer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> getSupportedSampleMimeTypes(@C.TrackType int trackType) {
|
||||
return defaultMuxerFactory.getSupportedSampleMimeTypes(trackType);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class FakeAssetLoader implements AssetLoader {
|
||||
|
||||
public static final class Factory implements AssetLoader.Factory {
|
||||
|
||||
private final @SupportedOutputTypes int supportedOutputTypes;
|
||||
@Nullable private final AtomicReference<SampleConsumer> sampleConsumerRef;
|
||||
|
||||
public Factory(
|
||||
@SupportedOutputTypes int supportedOutputTypes,
|
||||
@Nullable AtomicReference<SampleConsumer> sampleConsumerRef) {
|
||||
this.supportedOutputTypes = supportedOutputTypes;
|
||||
this.sampleConsumerRef = sampleConsumerRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetLoader createAssetLoader(
|
||||
EditedMediaItem editedMediaItem, Looper looper, Listener listener) {
|
||||
return new FakeAssetLoader(listener, supportedOutputTypes, sampleConsumerRef);
|
||||
}
|
||||
}
|
||||
|
||||
private final AssetLoader.Listener listener;
|
||||
private final @SupportedOutputTypes int supportedOutputTypes;
|
||||
@Nullable private final AtomicReference<SampleConsumer> sampleConsumerRef;
|
||||
|
||||
public FakeAssetLoader(
|
||||
Listener listener,
|
||||
@SupportedOutputTypes int supportedOutputTypes,
|
||||
@Nullable AtomicReference<SampleConsumer> sampleConsumerRef) {
|
||||
this.listener = listener;
|
||||
this.supportedOutputTypes = supportedOutputTypes;
|
||||
this.sampleConsumerRef = sampleConsumerRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
listener.onDurationUs(10_000_000);
|
||||
listener.onTrackCount(1);
|
||||
Format format =
|
||||
new Format.Builder()
|
||||
.setSampleMimeType(MimeTypes.AUDIO_AAC)
|
||||
.setSampleRate(44100)
|
||||
.setChannelCount(2)
|
||||
.build();
|
||||
try {
|
||||
listener.onTrackAdded(
|
||||
format, supportedOutputTypes, /* streamStartPositionUs= */ 0, /* streamOffsetUs= */ 0);
|
||||
|
||||
SampleConsumer sampleConsumer = listener.onOutputFormat(format);
|
||||
if (sampleConsumerRef != null) {
|
||||
sampleConsumerRef.set(sampleConsumer);
|
||||
}
|
||||
} catch (ExportException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Transformer.ProgressState int getProgress(ProgressHolder progressHolder) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<Integer, String> getDecoderNames() {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {}
|
||||
}
|
||||
|
||||
public static final String ASSET_URI_PREFIX = "asset:///media/";
|
||||
public static final String FILE_VIDEO_ONLY = "mp4/sample_18byte_nclx_colr.mp4";
|
||||
public static final String FILE_AUDIO_VIDEO = "mp4/sample.mp4";
|
||||
public static final String FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S =
|
||||
"mp4/sample_with_increasing_timestamps_320w_240h.mp4";
|
||||
public static final String FILE_WITH_SUBTITLES = "mkv/sample_with_srt.mkv";
|
||||
public static final String FILE_WITH_SEF_SLOW_MOTION = "mp4/sample_sef_slow_motion.mp4";
|
||||
public static final String FILE_AUDIO_UNSUPPORTED_BY_DECODER = "amr/sample_wb.amr";
|
||||
public static final String FILE_AUDIO_UNSUPPORTED_BY_ENCODER = "amr/sample_nb.amr";
|
||||
public static final String FILE_AUDIO_UNSUPPORTED_BY_MUXER = "mp4/sample_ac3.mp4";
|
||||
public static final String FILE_UNKNOWN_DURATION = "mp4/sample_fragmented.mp4";
|
||||
|
||||
private static final String DUMP_FILE_OUTPUT_DIRECTORY = "transformerdumps";
|
||||
private static final String DUMP_FILE_EXTENSION = "dump";
|
||||
|
||||
private TestUtil() {}
|
||||
|
||||
public static void createEncodersAndDecoders() {
|
||||
ShadowMediaCodec.CodecConfig codecConfig =
|
||||
new ShadowMediaCodec.CodecConfig(
|
||||
/* inputBufferSize= */ 10_000,
|
||||
/* outputBufferSize= */ 10_000,
|
||||
/* codec= */ (in, out) -> out.put(in));
|
||||
addCodec(
|
||||
MimeTypes.AUDIO_AAC,
|
||||
codecConfig,
|
||||
/* colorFormats= */ ImmutableList.of(),
|
||||
/* isDecoder= */ true);
|
||||
addCodec(
|
||||
MimeTypes.AUDIO_AC3,
|
||||
codecConfig,
|
||||
/* colorFormats= */ ImmutableList.of(),
|
||||
/* isDecoder= */ true);
|
||||
addCodec(
|
||||
MimeTypes.AUDIO_AMR_NB,
|
||||
codecConfig,
|
||||
/* colorFormats= */ ImmutableList.of(),
|
||||
/* isDecoder= */ true);
|
||||
addCodec(
|
||||
MimeTypes.AUDIO_AAC,
|
||||
codecConfig,
|
||||
/* colorFormats= */ ImmutableList.of(),
|
||||
/* isDecoder= */ false);
|
||||
|
||||
ShadowMediaCodec.CodecConfig throwingCodecConfig =
|
||||
new ShadowMediaCodec.CodecConfig(
|
||||
/* inputBufferSize= */ 10_000,
|
||||
/* outputBufferSize= */ 10_000,
|
||||
new ShadowMediaCodec.CodecConfig.Codec() {
|
||||
|
||||
@Override
|
||||
public void process(ByteBuffer in, ByteBuffer out) {
|
||||
out.put(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigured(
|
||||
MediaFormat format,
|
||||
@Nullable Surface surface,
|
||||
@Nullable MediaCrypto crypto,
|
||||
int flags) {
|
||||
throw new IllegalArgumentException("Format unsupported");
|
||||
}
|
||||
});
|
||||
|
||||
addCodec(
|
||||
MimeTypes.AUDIO_AMR_WB,
|
||||
throwingCodecConfig,
|
||||
/* colorFormats= */ ImmutableList.of(),
|
||||
/* isDecoder= */ true);
|
||||
addCodec(
|
||||
MimeTypes.AUDIO_AMR_NB,
|
||||
throwingCodecConfig,
|
||||
/* colorFormats= */ ImmutableList.of(),
|
||||
/* isDecoder= */ false);
|
||||
}
|
||||
|
||||
public static void removeEncodersAndDecoders() {
|
||||
ShadowMediaCodec.clearCodecs();
|
||||
ShadowMediaCodecList.reset();
|
||||
EncoderUtil.clearCachedEncoders();
|
||||
}
|
||||
|
||||
public static Transformer.Builder createTransformerBuilder(
|
||||
TestMuxerFactory.TestMuxerHolder testMuxerHolder, boolean enableFallback) {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
return new Transformer.Builder(context)
|
||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
||||
.setMuxerFactory(new TestMuxerFactory(testMuxerHolder))
|
||||
.setEncoderFactory(
|
||||
new DefaultEncoderFactory.Builder(context).setEnableFallback(enableFallback).build());
|
||||
}
|
||||
|
||||
public static String getDumpFileName(String originalFileName) {
|
||||
return DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '.' + DUMP_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
private static void addCodec(
|
||||
String mimeType,
|
||||
ShadowMediaCodec.CodecConfig codecConfig,
|
||||
List<Integer> colorFormats,
|
||||
boolean isDecoder) {
|
||||
String codecName =
|
||||
Util.formatInvariant(
|
||||
isDecoder ? "exo.%s.decoder" : "exo.%s.encoder", mimeType.replace('/', '-'));
|
||||
if (isDecoder) {
|
||||
ShadowMediaCodec.addDecoder(codecName, codecConfig);
|
||||
} else {
|
||||
ShadowMediaCodec.addEncoder(codecName, codecConfig);
|
||||
}
|
||||
|
||||
MediaFormat mediaFormat = new MediaFormat();
|
||||
mediaFormat.setString(MediaFormat.KEY_MIME, mimeType);
|
||||
MediaCodecInfoBuilder.CodecCapabilitiesBuilder codecCapabilities =
|
||||
MediaCodecInfoBuilder.CodecCapabilitiesBuilder.newBuilder()
|
||||
.setMediaFormat(mediaFormat)
|
||||
.setIsEncoder(!isDecoder);
|
||||
|
||||
if (!colorFormats.isEmpty()) {
|
||||
codecCapabilities.setColorFormats(Ints.toArray(colorFormats));
|
||||
}
|
||||
|
||||
ShadowMediaCodecList.addCodec(
|
||||
MediaCodecInfoBuilder.newBuilder()
|
||||
.setName(codecName)
|
||||
.setIsEncoder(!isDecoder)
|
||||
.setCapabilities(codecCapabilities.build())
|
||||
.build());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user