Remove data capturing logic from ShadowMediaCodecConfig

We're now using CapturingRenderersFactory everywhere

PiperOrigin-RevId: 348018988
This commit is contained in:
ibaker 2020-12-17 15:39:51 +00:00 committed by Oliver Woodman
parent 0d1dac93c4
commit 466826e673
3 changed files with 33 additions and 131 deletions

View File

@ -22,10 +22,8 @@ import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.testutil.CapturingRenderersFactory; import com.google.android.exoplayer2.testutil.CapturingRenderersFactory;
import com.google.android.exoplayer2.testutil.Dumper; import com.google.android.exoplayer2.testutil.Dumper;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -39,17 +37,13 @@ import java.util.List;
*/ */
public final class PlaybackOutput implements Dumper.Dumpable { public final class PlaybackOutput implements Dumper.Dumpable {
@Nullable private final ShadowMediaCodecConfig codecConfig; private final CapturingRenderersFactory capturingRenderersFactory;
@Nullable private final CapturingRenderersFactory capturingRenderersFactory;
private final List<Metadata> metadatas; private final List<Metadata> metadatas;
private final List<List<Cue>> subtitles; private final List<List<Cue>> subtitles;
private PlaybackOutput( private PlaybackOutput(
SimpleExoPlayer player, SimpleExoPlayer player, CapturingRenderersFactory capturingRenderersFactory) {
@Nullable ShadowMediaCodecConfig codecConfig,
@Nullable CapturingRenderersFactory capturingRenderersFactory) {
this.codecConfig = codecConfig;
this.capturingRenderersFactory = capturingRenderersFactory; this.capturingRenderersFactory = capturingRenderersFactory;
metadatas = Collections.synchronizedList(new ArrayList<>()); metadatas = Collections.synchronizedList(new ArrayList<>());
@ -75,27 +69,12 @@ public final class PlaybackOutput implements Dumper.Dumpable {
*/ */
public static PlaybackOutput register( public static PlaybackOutput register(
SimpleExoPlayer player, CapturingRenderersFactory capturingRenderersFactory) { SimpleExoPlayer player, CapturingRenderersFactory capturingRenderersFactory) {
return new PlaybackOutput(player, /* codecConfig= */ null, capturingRenderersFactory); return new PlaybackOutput(player, capturingRenderersFactory);
}
/** @deprecated Use {@link #register(SimpleExoPlayer, CapturingRenderersFactory)}. */
@Deprecated
public static PlaybackOutput register(
SimpleExoPlayer player, ShadowMediaCodecConfig mediaCodecConfig) {
return new PlaybackOutput(player, mediaCodecConfig, /* capturingRenderersFactory= */ null);
} }
@Override @Override
public void dump(Dumper dumper) { public void dump(Dumper dumper) {
if (codecConfig != null) { capturingRenderersFactory.dump(dumper);
ImmutableMap<String, TeeCodec> codecs = codecConfig.getCodecs();
ImmutableList<String> mimeTypes = ImmutableList.sortedCopyOf(codecs.keySet());
for (String mimeType : mimeTypes) {
dumper.add(Assertions.checkNotNull(codecs.get(mimeType)));
}
} else {
Assertions.checkNotNull(capturingRenderersFactory).dump(dumper);
}
dumpMetadata(dumper); dumpMetadata(dumper);
dumpSubtitles(dumper); dumpSubtitles(dumper);

View File

@ -15,17 +15,13 @@
*/ */
package com.google.android.exoplayer2.robolectric; package com.google.android.exoplayer2.robolectric;
import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaFormat; import android.media.MediaFormat;
import com.google.android.exoplayer2.testutil.CapturingRenderersFactory;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import java.util.HashMap; import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import java.util.Map;
import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;
import org.robolectric.shadows.MediaCodecInfoBuilder; import org.robolectric.shadows.MediaCodecInfoBuilder;
import org.robolectric.shadows.ShadowMediaCodec; import org.robolectric.shadows.ShadowMediaCodec;
@ -35,30 +31,14 @@ import org.robolectric.shadows.ShadowMediaCodecList;
* A JUnit @Rule to configure Roboelectric's {@link ShadowMediaCodec}. * A JUnit @Rule to configure Roboelectric's {@link ShadowMediaCodec}.
* *
* <p>Registers a {@link org.robolectric.shadows.ShadowMediaCodec.CodecConfig} for each audio/video * <p>Registers a {@link org.robolectric.shadows.ShadowMediaCodec.CodecConfig} for each audio/video
* MIME type known by ExoPlayer, and provides access to the bytes passed to these via {@link * MIME type known by ExoPlayer.
* TeeCodec}.
*/ */
public final class ShadowMediaCodecConfig extends ExternalResource { public final class ShadowMediaCodecConfig extends ExternalResource {
private final Map<String, TeeCodec> codecsByMimeType;
private ShadowMediaCodecConfig() {
this.codecsByMimeType = new HashMap<>();
}
public static ShadowMediaCodecConfig forAllSupportedMimeTypes() { public static ShadowMediaCodecConfig forAllSupportedMimeTypes() {
return new ShadowMediaCodecConfig(); return new ShadowMediaCodecConfig();
} }
/**
* @deprecated Use {@link CapturingRenderersFactory} to access {@link MediaCodec} interactions
* instead.
*/
@Deprecated
public ImmutableMap<String, TeeCodec> getCodecs() {
return ImmutableMap.copyOf(codecsByMimeType);
}
@Override @Override
protected void before() throws Throwable { protected void before() throws Throwable {
// Video codecs // Video codecs
@ -101,7 +81,6 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
@Override @Override
protected void after() { protected void after() {
codecsByMimeType.clear();
ShadowMediaCodecList.reset(); ShadowMediaCodecList.reset();
ShadowMediaCodec.clearCodecs(); ShadowMediaCodec.clearCodecs();
} }
@ -136,12 +115,11 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
.build()); .build());
// TODO: Update ShadowMediaCodec to consider the MediaFormat.KEY_MAX_INPUT_SIZE value passed // TODO: Update ShadowMediaCodec to consider the MediaFormat.KEY_MAX_INPUT_SIZE value passed
// to configure() so we don't have to specify large buffers here. // to configure() so we don't have to specify large buffers here.
TeeCodec codec = new TeeCodec(mimeType); CodecImpl codec = new CodecImpl(mimeType);
ShadowMediaCodec.addDecoder( ShadowMediaCodec.addDecoder(
codecName, codecName,
new ShadowMediaCodec.CodecConfig( new ShadowMediaCodec.CodecConfig(
/* inputBufferSize= */ 100_000, /* outputBufferSize= */ 100_000, codec)); /* inputBufferSize= */ 100_000, /* outputBufferSize= */ 100_000, codec));
codecsByMimeType.put(mimeType, codec);
} }
private static MediaCodecInfo.CodecProfileLevel createProfileLevel(int profile, int level) { private static MediaCodecInfo.CodecProfileLevel createProfileLevel(int profile, int level) {
@ -150,4 +128,30 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
profileLevel.level = level; profileLevel.level = level;
return profileLevel; return profileLevel;
} }
/**
* A {@link ShadowMediaCodec.CodecConfig.Codec} that passes data through without modifying it.
*
* <p>Note: This currently drops all audio data - removing this restriction is tracked in
* [internal b/174737370].
*/
private static final class CodecImpl implements ShadowMediaCodec.CodecConfig.Codec {
private final String mimeType;
public CodecImpl(String mimeType) {
this.mimeType = mimeType;
}
@Override
public void process(ByteBuffer in, ByteBuffer out) {
byte[] bytes = new byte[in.remaining()];
in.get(bytes);
// TODO(internal b/174737370): Output audio bytes as well.
if (!MimeTypes.isAudio(mimeType)) {
out.put(bytes);
}
}
}
} }

View File

@ -1,81 +0,0 @@
/*
* Copyright (C) 2020 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 com.google.android.exoplayer2.robolectric;
import android.media.MediaCodec;
import com.google.android.exoplayer2.testutil.CapturingRenderersFactory;
import com.google.android.exoplayer2.testutil.Dumper;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.robolectric.shadows.ShadowMediaCodec;
/**
* @deprecated Use {@link CapturingRenderersFactory} to access {@link MediaCodec} interactions
* instead.
*/
@Deprecated
public final class TeeCodec implements ShadowMediaCodec.CodecConfig.Codec, Dumper.Dumpable {
private final String mimeType;
private final List<byte[]> receivedBuffers;
public TeeCodec(String mimeType) {
this.mimeType = mimeType;
this.receivedBuffers = Collections.synchronizedList(new ArrayList<>());
}
@Override
public void process(ByteBuffer in, ByteBuffer out) {
byte[] bytes = new byte[in.remaining()];
in.get(bytes);
receivedBuffers.add(bytes);
if (!MimeTypes.isAudio(mimeType)) {
// Don't output audio bytes, because ShadowAudioTrack doesn't advance the playback position so
// playback never completes.
// TODO: Update ShadowAudioTrack to advance the playback position in a realistic way.
out.put(bytes);
}
}
@Override
public void dump(Dumper dumper) {
if (receivedBuffers.isEmpty()) {
return;
}
dumper.startBlock("MediaCodec (" + mimeType + ")");
dumper.add("buffers.length", receivedBuffers.size());
for (int i = 0; i < receivedBuffers.size(); i++) {
dumper.add("buffers[" + i + "]", receivedBuffers.get(i));
}
dumper.endBlock();
}
/**
* Return the buffers received by this codec.
*
* <p>The list is sorted in the order the buffers were passed to {@link #process(ByteBuffer,
* ByteBuffer)}.
*/
public ImmutableList<byte[]> getReceivedBuffers() {
return ImmutableList.copyOf(receivedBuffers);
}
}