Rollback of 7e63997459
*** Original commit *** Add TransformerTestBuilderFactory to make transformer testable by apps *** PiperOrigin-RevId: 496342997
This commit is contained in:
parent
a974e60379
commit
8ee8910788
@ -26,7 +26,6 @@ dependencies {
|
|||||||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||||
implementation 'com.squareup.okhttp3:mockwebserver:' + okhttpVersion
|
implementation 'com.squareup.okhttp3:mockwebserver:' + okhttpVersion
|
||||||
implementation project(modulePrefix + 'lib-exoplayer')
|
implementation project(modulePrefix + 'lib-exoplayer')
|
||||||
implementation project(modulePrefix + ':lib-transformer')
|
|
||||||
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 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.test.utils;
|
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import androidx.media3.common.C;
|
|
||||||
import androidx.media3.common.util.Clock;
|
|
||||||
import androidx.media3.common.util.UnstableApi;
|
|
||||||
import androidx.media3.transformer.DefaultEncoderFactory;
|
|
||||||
import androidx.media3.transformer.DefaultMuxer;
|
|
||||||
import androidx.media3.transformer.Muxer;
|
|
||||||
import androidx.media3.transformer.Transformer;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a {@link Transformer.Builder} setting up some of the common resources needed for testing
|
|
||||||
* {@link Transformer}.
|
|
||||||
*/
|
|
||||||
@UnstableApi
|
|
||||||
public final class TestTransformerBuilderFactory {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
private static @MonotonicNonNull TestMuxer testMuxer;
|
|
||||||
private long maxDelayBetweenSamplesMs;
|
|
||||||
|
|
||||||
/** Creates a new instance */
|
|
||||||
public TestTransformerBuilderFactory(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
maxDelayBetweenSamplesMs = DefaultMuxer.Factory.DEFAULT_MAX_DELAY_BETWEEN_SAMPLES_MS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the muxer's {@linkplain Muxer#getMaxDelayBetweenSamplesMs() max delay} between samples.
|
|
||||||
*/
|
|
||||||
@CanIgnoreReturnValue
|
|
||||||
public TestTransformerBuilderFactory setMaxDelayBetweenSamplesMs(long maxDelayBetweenSamplesMs) {
|
|
||||||
this.maxDelayBetweenSamplesMs = maxDelayBetweenSamplesMs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a {@link Transformer.Builder} using the provided values or their defaults. */
|
|
||||||
@SuppressLint("VisibleForTests") // Suppresses warning on setting the clock outside of a test file
|
|
||||||
public Transformer.Builder create(boolean enableFallback) {
|
|
||||||
Clock clock = new FakeClock(/* isAutoAdvancing= */ true);
|
|
||||||
Muxer.Factory defaultMuxerFactory = new DefaultMuxer.Factory(maxDelayBetweenSamplesMs);
|
|
||||||
return new Transformer.Builder(context)
|
|
||||||
.setClock(clock)
|
|
||||||
.setMuxerFactory(new TestMuxerFactory(defaultMuxerFactory))
|
|
||||||
.setEncoderFactory(
|
|
||||||
new DefaultEncoderFactory.Builder(context).setEnableFallback(enableFallback).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the test muxer used in the {@link Transformer.Builder}.
|
|
||||||
*
|
|
||||||
* <p>This method should only be called after the transformation is completed.
|
|
||||||
*/
|
|
||||||
public TestMuxer getTestMuxer() {
|
|
||||||
return checkStateNotNull(testMuxer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class TestMuxerFactory implements Muxer.Factory {
|
|
||||||
|
|
||||||
private final Muxer.Factory defaultMuxerFactory;
|
|
||||||
|
|
||||||
public TestMuxerFactory(Muxer.Factory defaultMuxerFactory) {
|
|
||||||
this.defaultMuxerFactory = defaultMuxerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Muxer create(String path) throws Muxer.MuxerException {
|
|
||||||
testMuxer = new TestMuxer(path, defaultMuxerFactory);
|
|
||||||
return testMuxer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Muxer create(ParcelFileDescriptor parcelFileDescriptor) throws Muxer.MuxerException {
|
|
||||||
testMuxer = new TestMuxer("FD:" + parcelFileDescriptor.getFd(), defaultMuxerFactory);
|
|
||||||
return testMuxer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImmutableList<String> getSupportedSampleMimeTypes(@C.TrackType int trackType) {
|
|
||||||
return defaultMuxerFactory.getSupportedSampleMimeTypes(trackType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,6 @@ dependencies {
|
|||||||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||||
implementation 'org.robolectric:robolectric:' + robolectricVersion
|
implementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
implementation project(modulePrefix + 'lib-exoplayer')
|
implementation project(modulePrefix + 'lib-exoplayer')
|
||||||
implementation project(modulePrefix + ':lib-transformer')
|
|
||||||
implementation project(modulePrefix + 'test-utils')
|
implementation project(modulePrefix + 'test-utils')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,15 +16,10 @@
|
|||||||
package androidx.media3.test.utils.robolectric;
|
package androidx.media3.test.utils.robolectric;
|
||||||
|
|
||||||
import android.media.MediaCodecInfo;
|
import android.media.MediaCodecInfo;
|
||||||
import android.media.MediaCrypto;
|
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.view.Surface;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
|
||||||
import androidx.media3.transformer.EncoderUtil;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -35,247 +30,105 @@ import org.robolectric.shadows.ShadowMediaCodec;
|
|||||||
import org.robolectric.shadows.ShadowMediaCodecList;
|
import org.robolectric.shadows.ShadowMediaCodecList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JUnit @Rule to configure {@link ShadowMediaCodec} for transcoding or decoding.
|
* A JUnit @Rule to configure Roboelectric's {@link ShadowMediaCodec}.
|
||||||
*
|
*
|
||||||
* <p>Registers {@link org.robolectric.shadows.ShadowMediaCodec.CodecConfig} instances for ExoPlayer
|
* <p>Registers a {@link org.robolectric.shadows.ShadowMediaCodec.CodecConfig} for each audio/video
|
||||||
* and Transformer tests.
|
* MIME type known by ExoPlayer.
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public final class ShadowMediaCodecConfig extends ExternalResource {
|
public final class ShadowMediaCodecConfig extends ExternalResource {
|
||||||
|
|
||||||
private static final String EXOTEST_VIDEO_AVC = "exotest.video.avc";
|
|
||||||
private static final String EXOTEST_VIDEO_MPEG2 = "exotest.video.mpeg2";
|
|
||||||
private static final String EXOTEST_VIDEO_VP9 = "exotest.video.vp9";
|
|
||||||
private static final String EXOTEST_AUDIO_AAC = "exotest.audio.aac";
|
|
||||||
private static final String EXOTEST_AUDIO_AC3 = "exotest.audio.ac3";
|
|
||||||
private static final String EXOTEST_AUDIO_AC4 = "exotest.audio.ac4";
|
|
||||||
private static final String EXOTEST_AUDIO_E_AC3 = "exotest.audio.eac3";
|
|
||||||
private static final String EXOTEST_AUDIO_E_AC3_JOC = "exotest.audio.eac3joc";
|
|
||||||
private static final String EXOTEST_AUDIO_FLAC = "exotest.audio.flac";
|
|
||||||
private static final String EXOTEST_AUDIO_MPEG = "exotest.audio.mpeg";
|
|
||||||
private static final String EXOTEST_AUDIO_MPEG_L2 = "exotest.audio.mpegl2";
|
|
||||||
private static final String EXOTEST_AUDIO_OPUS = "exotest.audio.opus";
|
|
||||||
private static final String EXOTEST_AUDIO_VORBIS = "exotest.audio.vorbis";
|
|
||||||
private static final String EXOTEST_AUDIO_RAW = "exotest.audio.raw";
|
|
||||||
|
|
||||||
private final boolean forTranscoding;
|
|
||||||
|
|
||||||
private ShadowMediaCodecConfig(boolean forTranscoding) {
|
|
||||||
this.forTranscoding = forTranscoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates an instance that configures {@link ShadowMediaCodec} for Transformer transcoding. */
|
|
||||||
public static ShadowMediaCodecConfig forTranscoding() {
|
|
||||||
return new ShadowMediaCodecConfig(/* forTranscoding= */ true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates an instance that configures {@link ShadowMediaCodec} for Exoplayer decoding. */
|
|
||||||
public static ShadowMediaCodecConfig forAllSupportedMimeTypes() {
|
public static ShadowMediaCodecConfig forAllSupportedMimeTypes() {
|
||||||
return new ShadowMediaCodecConfig(/* forTranscoding= */ false);
|
return new ShadowMediaCodecConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void before() throws Throwable {
|
protected void before() throws Throwable {
|
||||||
if (forTranscoding) {
|
|
||||||
addTranscodingCodecs();
|
|
||||||
} else {
|
|
||||||
addDecodingCodecs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTranscodingCodecs() {
|
|
||||||
ShadowMediaCodec.CodecConfig codecConfig =
|
|
||||||
new ShadowMediaCodec.CodecConfig(
|
|
||||||
/* inputBufferSize= */ 10_000,
|
|
||||||
/* outputBufferSize= */ 10_000,
|
|
||||||
/* codec= */ (in, out) -> out.put(in));
|
|
||||||
addTransformerCodec(MimeTypes.AUDIO_AAC, codecConfig, /* isDecoder= */ true);
|
|
||||||
addTransformerCodec(MimeTypes.AUDIO_AC3, codecConfig, /* isDecoder= */ true);
|
|
||||||
addTransformerCodec(MimeTypes.AUDIO_AMR_NB, codecConfig, /* isDecoder= */ true);
|
|
||||||
addTransformerCodec(MimeTypes.AUDIO_AAC, codecConfig, /* 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");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
addTransformerCodec(MimeTypes.AUDIO_AMR_WB, throwingCodecConfig, /* isDecoder= */ true);
|
|
||||||
addTransformerCodec(MimeTypes.AUDIO_AMR_NB, throwingCodecConfig, /* isDecoder= */ false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDecodingCodecs() {
|
|
||||||
// Video codecs
|
// Video codecs
|
||||||
MediaCodecInfo.CodecProfileLevel avcProfileLevel =
|
MediaCodecInfo.CodecProfileLevel avcProfileLevel =
|
||||||
createProfileLevel(
|
createProfileLevel(
|
||||||
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
|
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
|
||||||
MediaCodecInfo.CodecProfileLevel.AVCLevel62);
|
MediaCodecInfo.CodecProfileLevel.AVCLevel62);
|
||||||
addExoplayerCodec(
|
configureCodec(
|
||||||
EXOTEST_VIDEO_AVC,
|
/* codecName= */ "exotest.video.avc",
|
||||||
MimeTypes.VIDEO_H264,
|
MimeTypes.VIDEO_H264,
|
||||||
generateDecodingCodecConfig(MimeTypes.VIDEO_H264),
|
|
||||||
ImmutableList.of(avcProfileLevel),
|
ImmutableList.of(avcProfileLevel),
|
||||||
ImmutableList.of(MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible));
|
ImmutableList.of(MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible));
|
||||||
|
|
||||||
MediaCodecInfo.CodecProfileLevel mpeg2ProfileLevel =
|
MediaCodecInfo.CodecProfileLevel mpeg2ProfileLevel =
|
||||||
createProfileLevel(
|
createProfileLevel(
|
||||||
MediaCodecInfo.CodecProfileLevel.MPEG2ProfileMain,
|
MediaCodecInfo.CodecProfileLevel.MPEG2ProfileMain,
|
||||||
MediaCodecInfo.CodecProfileLevel.MPEG2LevelML);
|
MediaCodecInfo.CodecProfileLevel.MPEG2LevelML);
|
||||||
addExoplayerCodec(
|
configureCodec(
|
||||||
EXOTEST_VIDEO_MPEG2,
|
/* codecName= */ "exotest.video.mpeg2",
|
||||||
MimeTypes.VIDEO_MPEG2,
|
MimeTypes.VIDEO_MPEG2,
|
||||||
generateDecodingCodecConfig(MimeTypes.VIDEO_MPEG2),
|
|
||||||
ImmutableList.of(mpeg2ProfileLevel),
|
ImmutableList.of(mpeg2ProfileLevel),
|
||||||
ImmutableList.of(MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible));
|
ImmutableList.of(MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible));
|
||||||
addExoplayerCodec(
|
configureCodec(
|
||||||
EXOTEST_VIDEO_VP9,
|
/* codecName= */ "exotest.video.vp9",
|
||||||
MimeTypes.VIDEO_VP9,
|
MimeTypes.VIDEO_VP9,
|
||||||
generateDecodingCodecConfig(MimeTypes.VIDEO_VP9),
|
|
||||||
ImmutableList.of(),
|
ImmutableList.of(),
|
||||||
ImmutableList.of(MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible));
|
ImmutableList.of(MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible));
|
||||||
|
|
||||||
// Audio codecs
|
// Audio codecs
|
||||||
addExoplayerCodec(
|
configureCodec("exotest.audio.aac", MimeTypes.AUDIO_AAC);
|
||||||
EXOTEST_AUDIO_AAC, MimeTypes.AUDIO_AAC, generateDecodingCodecConfig(MimeTypes.AUDIO_AAC));
|
configureCodec("exotest.audio.ac3", MimeTypes.AUDIO_AC3);
|
||||||
addExoplayerCodec(
|
configureCodec("exotest.audio.ac4", MimeTypes.AUDIO_AC4);
|
||||||
EXOTEST_AUDIO_AC3, MimeTypes.AUDIO_AC3, generateDecodingCodecConfig(MimeTypes.AUDIO_AC3));
|
configureCodec("exotest.audio.eac3", MimeTypes.AUDIO_E_AC3);
|
||||||
addExoplayerCodec(
|
configureCodec("exotest.audio.eac3joc", MimeTypes.AUDIO_E_AC3_JOC);
|
||||||
EXOTEST_AUDIO_AC4, MimeTypes.AUDIO_AC4, generateDecodingCodecConfig(MimeTypes.AUDIO_AC4));
|
configureCodec("exotest.audio.flac", MimeTypes.AUDIO_FLAC);
|
||||||
addExoplayerCodec(
|
configureCodec("exotest.audio.mpeg", MimeTypes.AUDIO_MPEG);
|
||||||
EXOTEST_AUDIO_E_AC3,
|
configureCodec("exotest.audio.mpegl2", MimeTypes.AUDIO_MPEG_L2);
|
||||||
MimeTypes.AUDIO_E_AC3,
|
configureCodec("exotest.audio.opus", MimeTypes.AUDIO_OPUS);
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_E_AC3));
|
configureCodec("exotest.audio.vorbis", MimeTypes.AUDIO_VORBIS);
|
||||||
addExoplayerCodec(
|
|
||||||
EXOTEST_AUDIO_E_AC3_JOC,
|
|
||||||
MimeTypes.AUDIO_E_AC3_JOC,
|
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_E_AC3_JOC));
|
|
||||||
addExoplayerCodec(
|
|
||||||
EXOTEST_AUDIO_FLAC,
|
|
||||||
MimeTypes.AUDIO_FLAC,
|
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_FLAC));
|
|
||||||
addExoplayerCodec(
|
|
||||||
EXOTEST_AUDIO_MPEG,
|
|
||||||
MimeTypes.AUDIO_MPEG,
|
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_MPEG));
|
|
||||||
addExoplayerCodec(
|
|
||||||
EXOTEST_AUDIO_MPEG_L2,
|
|
||||||
MimeTypes.AUDIO_MPEG_L2,
|
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_MPEG_L2));
|
|
||||||
addExoplayerCodec(
|
|
||||||
EXOTEST_AUDIO_OPUS,
|
|
||||||
MimeTypes.AUDIO_OPUS,
|
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_OPUS));
|
|
||||||
addExoplayerCodec(
|
|
||||||
EXOTEST_AUDIO_VORBIS,
|
|
||||||
MimeTypes.AUDIO_VORBIS,
|
|
||||||
generateDecodingCodecConfig(MimeTypes.AUDIO_VORBIS));
|
|
||||||
|
|
||||||
// Raw audio should use a bypass mode and never need this codec. However, to easily assert
|
// Raw audio should use a bypass mode and never need this codec. However, to easily assert
|
||||||
// failures of the bypass mode we want to detect when the raw audio is decoded by this class and
|
// failures of the bypass mode we want to detect when the raw audio is decoded by this class and
|
||||||
// thus we need a codec to output samples.
|
// thus we need a codec to output samples.
|
||||||
addExoplayerCodec(
|
configureCodec("exotest.audio.raw", MimeTypes.AUDIO_RAW);
|
||||||
EXOTEST_AUDIO_RAW, MimeTypes.AUDIO_RAW, generateDecodingCodecConfig(MimeTypes.AUDIO_RAW));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void after() {
|
protected void after() {
|
||||||
if (!forTranscoding) {
|
MediaCodecUtil.clearDecoderInfoCache();
|
||||||
MediaCodecUtil.clearDecoderInfoCache();
|
|
||||||
} else {
|
|
||||||
EncoderUtil.clearCachedEncoders();
|
|
||||||
}
|
|
||||||
ShadowMediaCodecList.reset();
|
ShadowMediaCodecList.reset();
|
||||||
ShadowMediaCodec.clearCodecs();
|
ShadowMediaCodec.clearCodecs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShadowMediaCodec.CodecConfig generateDecodingCodecConfig(String mimeType) {
|
private void configureCodec(String codecName, String mimeType) {
|
||||||
// TODO: Update ShadowMediaCodec to consider the MediaFormat.KEY_MAX_INPUT_SIZE value passed
|
configureCodec(
|
||||||
// to configure() so we don't have to specify large buffers here.
|
|
||||||
CodecImpl codec = new CodecImpl(mimeType);
|
|
||||||
return new ShadowMediaCodec.CodecConfig(
|
|
||||||
/* inputBufferSize= */ 100_000, /* outputBufferSize= */ 100_000, codec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTransformerCodec(
|
|
||||||
String mimeType, ShadowMediaCodec.CodecConfig codecConfig, boolean isDecoder) {
|
|
||||||
String codecName =
|
|
||||||
Util.formatInvariant(
|
|
||||||
isDecoder ? "transformertest.%s.decoder" : "transformertest.%s.encoder",
|
|
||||||
mimeType.replace('/', '.'));
|
|
||||||
addCodec(
|
|
||||||
codecName,
|
codecName,
|
||||||
mimeType,
|
mimeType,
|
||||||
codecConfig,
|
|
||||||
/* profileLevels= */ ImmutableList.of(),
|
|
||||||
/* colorFormats= */ ImmutableList.of(),
|
|
||||||
isDecoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addExoplayerCodec(
|
|
||||||
String codecName, String mimeType, ShadowMediaCodec.CodecConfig codecConfig) {
|
|
||||||
addExoplayerCodec(
|
|
||||||
codecName,
|
|
||||||
mimeType,
|
|
||||||
codecConfig,
|
|
||||||
/* profileLevels= */ ImmutableList.of(),
|
/* profileLevels= */ ImmutableList.of(),
|
||||||
/* colorFormats= */ ImmutableList.of());
|
/* colorFormats= */ ImmutableList.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addExoplayerCodec(
|
private void configureCodec(
|
||||||
String codecName,
|
String codecName,
|
||||||
String mimeType,
|
String mimeType,
|
||||||
ShadowMediaCodec.CodecConfig codecConfig,
|
|
||||||
List<MediaCodecInfo.CodecProfileLevel> profileLevels,
|
List<MediaCodecInfo.CodecProfileLevel> profileLevels,
|
||||||
List<Integer> colorFormats) {
|
List<Integer> colorFormats) {
|
||||||
addCodec(codecName, mimeType, codecConfig, profileLevels, colorFormats, /* isDecoder= */ true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addCodec(
|
|
||||||
String codecName,
|
|
||||||
String mimeType,
|
|
||||||
ShadowMediaCodec.CodecConfig codecConfig,
|
|
||||||
List<MediaCodecInfo.CodecProfileLevel> profileLevels,
|
|
||||||
List<Integer> colorFormats,
|
|
||||||
boolean isDecoder) {
|
|
||||||
MediaFormat mediaFormat = new MediaFormat();
|
MediaFormat mediaFormat = new MediaFormat();
|
||||||
mediaFormat.setString(MediaFormat.KEY_MIME, mimeType);
|
mediaFormat.setString(MediaFormat.KEY_MIME, mimeType);
|
||||||
MediaCodecInfoBuilder.CodecCapabilitiesBuilder capabilities =
|
MediaCodecInfoBuilder.CodecCapabilitiesBuilder capabilities =
|
||||||
MediaCodecInfoBuilder.CodecCapabilitiesBuilder.newBuilder()
|
MediaCodecInfoBuilder.CodecCapabilitiesBuilder.newBuilder().setMediaFormat(mediaFormat);
|
||||||
.setMediaFormat(mediaFormat)
|
|
||||||
.setIsEncoder(!isDecoder);
|
|
||||||
if (!profileLevels.isEmpty()) {
|
if (!profileLevels.isEmpty()) {
|
||||||
capabilities.setProfileLevels(profileLevels.toArray(new MediaCodecInfo.CodecProfileLevel[0]));
|
capabilities.setProfileLevels(profileLevels.toArray(new MediaCodecInfo.CodecProfileLevel[0]));
|
||||||
}
|
}
|
||||||
if (!colorFormats.isEmpty()) {
|
if (!colorFormats.isEmpty()) {
|
||||||
capabilities.setColorFormats(Ints.toArray(colorFormats));
|
capabilities.setColorFormats(Ints.toArray(colorFormats));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShadowMediaCodecList.addCodec(
|
ShadowMediaCodecList.addCodec(
|
||||||
MediaCodecInfoBuilder.newBuilder()
|
MediaCodecInfoBuilder.newBuilder()
|
||||||
.setName(codecName)
|
.setName(codecName)
|
||||||
.setIsEncoder(!isDecoder)
|
|
||||||
.setCapabilities(capabilities.build())
|
.setCapabilities(capabilities.build())
|
||||||
.build());
|
.build());
|
||||||
|
// TODO: Update ShadowMediaCodec to consider the MediaFormat.KEY_MAX_INPUT_SIZE value passed
|
||||||
if (isDecoder) {
|
// to configure() so we don't have to specify large buffers here.
|
||||||
ShadowMediaCodec.addDecoder(codecName, codecConfig);
|
CodecImpl codec = new CodecImpl(mimeType);
|
||||||
} else {
|
ShadowMediaCodec.addDecoder(
|
||||||
ShadowMediaCodec.addEncoder(codecName, codecConfig);
|
codecName,
|
||||||
}
|
new ShadowMediaCodec.CodecConfig(
|
||||||
|
/* inputBufferSize= */ 100_000, /* outputBufferSize= */ 100_000, codec));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaCodecInfo.CodecProfileLevel createProfileLevel(int profile, int level) {
|
private static MediaCodecInfo.CodecProfileLevel createProfileLevel(int profile, int level) {
|
||||||
|
@ -430,7 +430,7 @@ public final class Transformer {
|
|||||||
*/
|
*/
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public Builder setClock(Clock clock) {
|
/* package */ Builder setClock(Clock clock) {
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.listeners = listeners.copy(looper, clock, (listener, flags) -> {});
|
this.listeners = listeners.copy(looper, clock, (listener, flags) -> {});
|
||||||
return this;
|
return this;
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package androidx.media3.test.utils;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.test.utils.DumpableFormat;
|
||||||
import androidx.media3.transformer.Muxer;
|
import androidx.media3.test.utils.Dumper;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -28,7 +28,6 @@ import java.util.List;
|
|||||||
* testing purposes) and delegates the actual muxing operations to another {@link Muxer} created
|
* testing purposes) and delegates the actual muxing operations to another {@link Muxer} created
|
||||||
* using the factory provided.
|
* using the factory provided.
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
|
||||||
public final class TestMuxer implements Muxer, Dumper.Dumpable {
|
public final class TestMuxer implements Muxer, Dumper.Dumpable {
|
||||||
|
|
||||||
private final Muxer muxer;
|
private final Muxer muxer;
|
@ -29,11 +29,15 @@ import static org.mockito.Mockito.never;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.MediaCrypto;
|
||||||
|
import android.media.MediaFormat;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.view.Surface;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
@ -49,13 +53,14 @@ import androidx.media3.extractor.ExtractorOutput;
|
|||||||
import androidx.media3.extractor.ExtractorsFactory;
|
import androidx.media3.extractor.ExtractorsFactory;
|
||||||
import androidx.media3.extractor.PositionHolder;
|
import androidx.media3.extractor.PositionHolder;
|
||||||
import androidx.media3.test.utils.DumpFileAsserts;
|
import androidx.media3.test.utils.DumpFileAsserts;
|
||||||
import androidx.media3.test.utils.TestTransformerBuilderFactory;
|
import androidx.media3.test.utils.FakeClock;
|
||||||
import androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -69,17 +74,16 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.shadows.MediaCodecInfoBuilder;
|
||||||
|
import org.robolectric.shadows.ShadowMediaCodec;
|
||||||
|
import org.robolectric.shadows.ShadowMediaCodecList;
|
||||||
|
|
||||||
/** End-to-end test for {@link Transformer}. */
|
/** End-to-end test for {@link Transformer}. */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class TransformerEndToEndTest {
|
public final class TransformerEndToEndTest {
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final ShadowMediaCodecConfig mediaCodecConfig = ShadowMediaCodecConfig.forTranscoding();
|
|
||||||
|
|
||||||
private static final String ASSET_URI_PREFIX = "asset:///media/";
|
private static final String ASSET_URI_PREFIX = "asset:///media/";
|
||||||
private static final String FILE_VIDEO_ONLY = "mp4/sample_18byte_nclx_colr.mp4";
|
private static final String FILE_VIDEO_ONLY = "mp4/sample_18byte_nclx_colr.mp4";
|
||||||
private static final String FILE_AUDIO_VIDEO = "mp4/sample.mp4";
|
private static final String FILE_AUDIO_VIDEO = "mp4/sample.mp4";
|
||||||
@ -96,39 +100,39 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private String outputPath;
|
private String outputPath;
|
||||||
|
private TestMuxer testMuxer;
|
||||||
|
private FakeClock clock;
|
||||||
private ProgressHolder progressHolder;
|
private ProgressHolder progressHolder;
|
||||||
private TestTransformerBuilderFactory testTransformerBuilderFactory;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
context = ApplicationProvider.getApplicationContext();
|
context = ApplicationProvider.getApplicationContext();
|
||||||
outputPath = Util.createTempFile(context, "TransformerTest").getPath();
|
outputPath = Util.createTempFile(context, "TransformerTest").getPath();
|
||||||
|
clock = new FakeClock(/* isAutoAdvancing= */ true);
|
||||||
progressHolder = new ProgressHolder();
|
progressHolder = new ProgressHolder();
|
||||||
testTransformerBuilderFactory = new TestTransformerBuilderFactory(context);
|
createEncodersAndDecoders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
Files.delete(Paths.get(outputPath));
|
Files.delete(Paths.get(outputPath));
|
||||||
|
removeEncodersAndDecoders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_videoOnlyPassthrough_completesSuccessfully() throws Exception {
|
public void startTransformation_videoOnlyPassthrough_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||||
context, testTransformerBuilderFactory.getTestMuxer(), getDumpFileName(FILE_VIDEO_ONLY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_audioOnlyPassthrough_completesSuccessfully() throws Exception {
|
public void startTransformation_audioOnlyPassthrough_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER);
|
||||||
|
|
||||||
@ -136,16 +140,13 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_ENCODER));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_ENCODER));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_audioOnlyTranscoding_completesSuccessfully() throws Exception {
|
public void startTransformation_audioOnlyTranscoding_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setTransformationRequest(
|
.setTransformationRequest(
|
||||||
new TransformationRequest.Builder()
|
new TransformationRequest.Builder()
|
||||||
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
|
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
|
||||||
@ -157,29 +158,24 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_ENCODER + ".aac"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_ENCODER + ".aac"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception {
|
public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
context, testTransformerBuilderFactory.getTestMuxer(), getDumpFileName(FILE_AUDIO_VIDEO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_audioAndVideo_withClippingStartAtKeyFrame_completesSuccessfully()
|
public void startTransformation_audioAndVideo_withClippingStartAtKeyFrame_completesSuccessfully()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem =
|
MediaItem mediaItem =
|
||||||
new MediaItem.Builder()
|
new MediaItem.Builder()
|
||||||
.setUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S)
|
.setUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S)
|
||||||
@ -196,15 +192,14 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context,
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
testMuxer,
|
||||||
getDumpFileName(FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S + ".clipped"));
|
getDumpFileName(FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S + ".clipped"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_withSubtitles_completesSuccessfully() throws Exception {
|
public void startTransformation_withSubtitles_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setTransformationRequest(
|
.setTransformationRequest(
|
||||||
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build())
|
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build())
|
||||||
.build();
|
.build();
|
||||||
@ -213,17 +208,13 @@ public final class TransformerEndToEndTest {
|
|||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SUBTITLES));
|
||||||
context,
|
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_WITH_SUBTITLES));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_successiveTransformations_completesSuccessfully()
|
public void startTransformation_successiveTransformations_completesSuccessfully()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
// Transform first media item.
|
// Transform first media item.
|
||||||
@ -235,14 +226,12 @@ public final class TransformerEndToEndTest {
|
|||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
context, testTransformerBuilderFactory.getTestMuxer(), getDumpFileName(FILE_AUDIO_VIDEO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_concurrentTransformations_throwsError() throws Exception {
|
public void startTransformation_concurrentTransformations_throwsError() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
@ -254,44 +243,33 @@ public final class TransformerEndToEndTest {
|
|||||||
@Test
|
@Test
|
||||||
public void startTransformation_removeAudio_completesSuccessfully() throws Exception {
|
public void startTransformation_removeAudio_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false).setRemoveAudio(true).build();
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setRemoveAudio(true)
|
|
||||||
.build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".noaudio"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_VIDEO + ".noaudio"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_removeVideo_completesSuccessfully() throws Exception {
|
public void startTransformation_removeVideo_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false).setRemoveVideo(true).build();
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setRemoveVideo(true)
|
|
||||||
.build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".novideo"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_VIDEO + ".novideo"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_silentAudio_completesSuccessfully() throws Exception {
|
public void startTransformation_silentAudio_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.experimentalSetForceSilentAudio(true)
|
.experimentalSetForceSilentAudio(true)
|
||||||
.build();
|
.build();
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
@ -300,9 +278,7 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".silentaudio"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_VIDEO + ".silentaudio"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -310,8 +286,7 @@ public final class TransformerEndToEndTest {
|
|||||||
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
|
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
|
||||||
sonicAudioProcessor.setOutputSampleRateHz(48000);
|
sonicAudioProcessor.setOutputSampleRateHz(48000);
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setAudioProcessors(ImmutableList.of(sonicAudioProcessor))
|
.setAudioProcessors(ImmutableList.of(sonicAudioProcessor))
|
||||||
.build();
|
.build();
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
@ -320,9 +295,7 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".48000hz"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_VIDEO + ".48000hz"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -331,8 +304,7 @@ public final class TransformerEndToEndTest {
|
|||||||
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
|
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
|
||||||
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
|
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.addListener(mockListener1)
|
.addListener(mockListener1)
|
||||||
.addListener(mockListener2)
|
.addListener(mockListener2)
|
||||||
.addListener(mockListener3)
|
.addListener(mockListener3)
|
||||||
@ -353,8 +325,7 @@ public final class TransformerEndToEndTest {
|
|||||||
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
|
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
|
||||||
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
|
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.addListener(mockListener1)
|
.addListener(mockListener1)
|
||||||
.addListener(mockListener2)
|
.addListener(mockListener2)
|
||||||
.addListener(mockListener3)
|
.addListener(mockListener3)
|
||||||
@ -381,8 +352,7 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformationRequest fallbackTransformationRequest =
|
TransformationRequest fallbackTransformationRequest =
|
||||||
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
|
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ true)
|
||||||
.create(/* enableFallback= */ true)
|
|
||||||
.addListener(mockListener1)
|
.addListener(mockListener1)
|
||||||
.addListener(mockListener2)
|
.addListener(mockListener2)
|
||||||
.addListener(mockListener3)
|
.addListener(mockListener3)
|
||||||
@ -407,8 +377,7 @@ public final class TransformerEndToEndTest {
|
|||||||
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
|
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
|
||||||
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
|
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
|
||||||
Transformer transformer1 =
|
Transformer transformer1 =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.addListener(mockListener1)
|
.addListener(mockListener1)
|
||||||
.addListener(mockListener2)
|
.addListener(mockListener2)
|
||||||
.addListener(mockListener3)
|
.addListener(mockListener3)
|
||||||
@ -427,8 +396,7 @@ public final class TransformerEndToEndTest {
|
|||||||
@Test
|
@Test
|
||||||
public void startTransformation_flattenForSlowMotion_completesSuccessfully() throws Exception {
|
public void startTransformation_flattenForSlowMotion_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setTransformationRequest(
|
.setTransformationRequest(
|
||||||
new TransformationRequest.Builder().setFlattenForSlowMotion(true).build())
|
new TransformationRequest.Builder().setFlattenForSlowMotion(true).build())
|
||||||
.build();
|
.build();
|
||||||
@ -437,10 +405,7 @@ public final class TransformerEndToEndTest {
|
|||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SEF_SLOW_MOTION));
|
||||||
context,
|
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_WITH_SEF_SLOW_MOTION));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -455,10 +420,7 @@ public final class TransformerEndToEndTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false).addListener(listener).build();
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.addListener(listener)
|
|
||||||
.build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
@ -474,8 +436,7 @@ public final class TransformerEndToEndTest {
|
|||||||
public void startTransformation_withAudioEncoderFormatUnsupported_completesWithError()
|
public void startTransformation_withAudioEncoderFormatUnsupported_completesWithError()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setTransformationRequest(
|
.setTransformationRequest(
|
||||||
new TransformationRequest.Builder()
|
new TransformationRequest.Builder()
|
||||||
.setAudioMimeType(
|
.setAudioMimeType(
|
||||||
@ -496,8 +457,7 @@ public final class TransformerEndToEndTest {
|
|||||||
public void startTransformation_withAudioDecoderFormatUnsupported_completesWithError()
|
public void startTransformation_withAudioDecoderFormatUnsupported_completesWithError()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setTransformationRequest(
|
.setTransformationRequest(
|
||||||
new TransformationRequest.Builder()
|
new TransformationRequest.Builder()
|
||||||
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
|
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
|
||||||
@ -515,8 +475,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_withIoError_completesWithError() throws Exception {
|
public void startTransformation_withIoError_completesWithError() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri("asset:///non-existing-path.mp4");
|
MediaItem mediaItem = MediaItem.fromUri("asset:///non-existing-path.mp4");
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
@ -536,19 +495,14 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformationRequest fallbackTransformationRequest =
|
TransformationRequest fallbackTransformationRequest =
|
||||||
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
|
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false).addListener(mockListener).build();
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.addListener(mockListener)
|
|
||||||
.build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_MUXER + ".fallback"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_MUXER + ".fallback"));
|
|
||||||
verify(mockListener)
|
verify(mockListener)
|
||||||
.onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
|
.onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
|
||||||
}
|
}
|
||||||
@ -562,19 +516,14 @@ public final class TransformerEndToEndTest {
|
|||||||
TransformationRequest fallbackTransformationRequest =
|
TransformationRequest fallbackTransformationRequest =
|
||||||
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
|
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ true).addListener(mockListener).build();
|
||||||
.create(/* enableFallback= */ true)
|
|
||||||
.addListener(mockListener)
|
|
||||||
.build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_MUXER + ".fallback"));
|
||||||
testTransformerBuilderFactory.getTestMuxer(),
|
|
||||||
getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_MUXER + ".fallback"));
|
|
||||||
verify(mockListener)
|
verify(mockListener)
|
||||||
.onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
|
.onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
|
||||||
}
|
}
|
||||||
@ -584,11 +533,11 @@ public final class TransformerEndToEndTest {
|
|||||||
MediaSource.Factory mediaSourceFactory =
|
MediaSource.Factory mediaSourceFactory =
|
||||||
new DefaultMediaSourceFactory(
|
new DefaultMediaSourceFactory(
|
||||||
context, new SlowExtractorsFactory(/* delayBetweenReadsMs= */ 10));
|
context, new SlowExtractorsFactory(/* delayBetweenReadsMs= */ 10));
|
||||||
|
Muxer.Factory muxerFactory = new TestMuxerFactory(/* maxDelayBetweenSamplesMs= */ 1);
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false)
|
||||||
.setMaxDelayBetweenSamplesMs(1)
|
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.setMediaSourceFactory(mediaSourceFactory)
|
.setMediaSourceFactory(mediaSourceFactory)
|
||||||
|
.setMuxerFactory(muxerFactory)
|
||||||
.build();
|
.build();
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
@ -602,24 +551,20 @@ public final class TransformerEndToEndTest {
|
|||||||
@Test
|
@Test
|
||||||
public void startTransformation_withUnsetMaxDelayBetweenSamples_completesSuccessfully()
|
public void startTransformation_withUnsetMaxDelayBetweenSamples_completesSuccessfully()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
Muxer.Factory muxerFactory = new TestMuxerFactory(/* maxDelayBetweenSamplesMs= */ C.TIME_UNSET);
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory
|
createTransformerBuilder(/* enableFallback= */ false).setMuxerFactory(muxerFactory).build();
|
||||||
.setMaxDelayBetweenSamplesMs(C.TIME_UNSET)
|
|
||||||
.create(/* enableFallback= */ false)
|
|
||||||
.build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
context, testTransformerBuilderFactory.getTestMuxer(), getDumpFileName(FILE_AUDIO_VIDEO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_afterCancellation_completesSuccessfully() throws Exception {
|
public void startTransformation_afterCancellation_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
@ -630,8 +575,7 @@ public final class TransformerEndToEndTest {
|
|||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
context, testTransformerBuilderFactory.getTestMuxer(), getDumpFileName(FILE_AUDIO_VIDEO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -640,7 +584,7 @@ public final class TransformerEndToEndTest {
|
|||||||
anotherThread.start();
|
anotherThread.start();
|
||||||
Looper looper = anotherThread.getLooper();
|
Looper looper = anotherThread.getLooper();
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).setLooper(looper).build();
|
createTransformerBuilder(/* enableFallback= */ false).setLooper(looper).build();
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
AtomicReference<Exception> exception = new AtomicReference<>();
|
AtomicReference<Exception> exception = new AtomicReference<>();
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
@ -660,14 +604,12 @@ public final class TransformerEndToEndTest {
|
|||||||
countDownLatch.await();
|
countDownLatch.await();
|
||||||
|
|
||||||
assertThat(exception.get()).isNull();
|
assertThat(exception.get()).isNull();
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
context, testTransformerBuilderFactory.getTestMuxer(), getDumpFileName(FILE_AUDIO_VIDEO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_fromWrongThread_throwsError() throws Exception {
|
public void startTransformation_fromWrongThread_throwsError() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
||||||
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
||||||
@ -692,8 +634,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
|
public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
AtomicInteger previousProgressState =
|
AtomicInteger previousProgressState =
|
||||||
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
||||||
@ -739,8 +680,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception {
|
public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
List<Integer> progresses = new ArrayList<>();
|
List<Integer> progresses = new ArrayList<>();
|
||||||
Handler progressHandler =
|
Handler progressHandler =
|
||||||
@ -775,8 +715,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception {
|
public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
|
|
||||||
@Transformer.ProgressState int stateBeforeTransform = transformer.getProgress(progressHolder);
|
@Transformer.ProgressState int stateBeforeTransform = transformer.getProgress(progressHolder);
|
||||||
@ -790,8 +729,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_unknownDuration_returnsConsistentStates() throws Exception {
|
public void getProgress_unknownDuration_returnsConsistentStates() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_UNKNOWN_DURATION);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_UNKNOWN_DURATION);
|
||||||
AtomicInteger previousProgressState =
|
AtomicInteger previousProgressState =
|
||||||
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
||||||
@ -834,8 +772,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_fromWrongThread_throwsError() throws Exception {
|
public void getProgress_fromWrongThread_throwsError() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
||||||
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
@ -859,8 +796,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cancel_afterCompletion_doesNotThrow() throws Exception {
|
public void cancel_afterCompletion_doesNotThrow() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
@ -870,8 +806,7 @@ public final class TransformerEndToEndTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cancel_fromWrongThread_throwsError() throws Exception {
|
public void cancel_fromWrongThread_throwsError() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
|
||||||
testTransformerBuilderFactory.create(/* enableFallback= */ false).build();
|
|
||||||
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
||||||
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
@ -893,10 +828,147 @@ public final class TransformerEndToEndTest {
|
|||||||
assertThat(illegalStateException.get()).isNotNull();
|
assertThat(illegalStateException.get()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Transformer.Builder createTransformerBuilder(boolean enableFallback) {
|
||||||
|
return new Transformer.Builder(context)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.setEncoderFactory(
|
||||||
|
new DefaultEncoderFactory.Builder(context).setEnableFallback(enableFallback).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeEncodersAndDecoders() {
|
||||||
|
ShadowMediaCodec.clearCodecs();
|
||||||
|
ShadowMediaCodecList.reset();
|
||||||
|
EncoderUtil.clearCachedEncoders();
|
||||||
|
}
|
||||||
|
|
||||||
private static String getDumpFileName(String originalFileName) {
|
private static String getDumpFileName(String originalFileName) {
|
||||||
return DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '.' + DUMP_FILE_EXTENSION;
|
return DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '.' + DUMP_FILE_EXTENSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class TestMuxerFactory implements Muxer.Factory {
|
||||||
|
|
||||||
|
private final Muxer.Factory defaultMuxerFactory;
|
||||||
|
|
||||||
|
public TestMuxerFactory() {
|
||||||
|
defaultMuxerFactory = new DefaultMuxer.Factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestMuxerFactory(long maxDelayBetweenSamplesMs) {
|
||||||
|
defaultMuxerFactory = new DefaultMuxer.Factory(maxDelayBetweenSamplesMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Muxer create(String path) throws Muxer.MuxerException {
|
||||||
|
testMuxer = new TestMuxer(path, defaultMuxerFactory);
|
||||||
|
return testMuxer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Muxer create(ParcelFileDescriptor parcelFileDescriptor) throws Muxer.MuxerException {
|
||||||
|
testMuxer = new TestMuxer("FD:" + parcelFileDescriptor.getFd(), defaultMuxerFactory);
|
||||||
|
return testMuxer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImmutableList<String> getSupportedSampleMimeTypes(@C.TrackType int trackType) {
|
||||||
|
return defaultMuxerFactory.getSupportedSampleMimeTypes(trackType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final class SlowExtractorsFactory implements ExtractorsFactory {
|
private static final class SlowExtractorsFactory implements ExtractorsFactory {
|
||||||
|
|
||||||
private final long delayBetweenReadsMs;
|
private final long delayBetweenReadsMs;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user