mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Skip decoder input buffers for encrypted content
Previous assertion was incorrect. Per-frame initialization vectors are written to the output stream in `FragmentedMp4Extractor` PiperOrigin-RevId: 742203717
This commit is contained in:
parent
427daef350
commit
73fa820828
@ -17,13 +17,19 @@ package androidx.media3.exoplayer.drm;
|
|||||||
|
|
||||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.PlaybackException;
|
import androidx.media3.common.PlaybackException;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.util.ConditionVariable;
|
import androidx.media3.common.util.ConditionVariable;
|
||||||
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.exoplayer.DecoderCounters;
|
||||||
|
import androidx.media3.exoplayer.DefaultRenderersFactory;
|
||||||
import androidx.media3.exoplayer.ExoPlayer;
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
@ -97,4 +103,73 @@ public final class DrmPlaybackTest {
|
|||||||
getInstrumentation().waitForIdleSync();
|
getInstrumentation().waitForIdleSync();
|
||||||
assertThat(playbackException.get()).isNull();
|
assertThat(playbackException.get()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearkeyPlayback_withLateThresholdToDropDecoderInput_dropsInputBuffers()
|
||||||
|
throws Exception {
|
||||||
|
// The API 21 emulator doesn't have a secure decoder. Due to b/18678462 MediaCodecUtil pretends
|
||||||
|
// that there is a secure decoder so we must only run this test on API 21 - i.e. we cannot
|
||||||
|
// assumeTrue() on getDecoderInfos.
|
||||||
|
assumeTrue(Util.SDK_INT > 21);
|
||||||
|
Context context = getInstrumentation().getContext();
|
||||||
|
MockWebServer mockWebServer = new MockWebServer();
|
||||||
|
mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(CLEARKEY_RESPONSE));
|
||||||
|
mockWebServer.start();
|
||||||
|
|
||||||
|
MediaItem mediaItem =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri("asset:///media/drm/sample_fragmented_clearkey.mp4")
|
||||||
|
.setDrmConfiguration(
|
||||||
|
new MediaItem.DrmConfiguration.Builder(C.CLEARKEY_UUID)
|
||||||
|
.setLicenseUri(mockWebServer.url("license").toString())
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
AtomicReference<ExoPlayer> player = new AtomicReference<>();
|
||||||
|
ConditionVariable playbackComplete = new ConditionVariable();
|
||||||
|
AtomicReference<PlaybackException> playbackException = new AtomicReference<>();
|
||||||
|
AtomicReference<DecoderCounters> decoderCountersAtomicReference = new AtomicReference<>();
|
||||||
|
getInstrumentation()
|
||||||
|
.runOnMainSync(
|
||||||
|
() -> {
|
||||||
|
player.set(
|
||||||
|
new ExoPlayer.Builder(
|
||||||
|
context,
|
||||||
|
new DefaultRenderersFactory(context)
|
||||||
|
.experimentalSetLateThresholdToDropDecoderInputUs(-100_000_000L),
|
||||||
|
new DefaultMediaSourceFactory(context)
|
||||||
|
.experimentalSetCodecsToParseWithinGopSampleDependencies(
|
||||||
|
C.VIDEO_CODEC_FLAG_H264))
|
||||||
|
.build());
|
||||||
|
player
|
||||||
|
.get()
|
||||||
|
.addListener(
|
||||||
|
new Player.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onPlaybackStateChanged(@Player.State int playbackState) {
|
||||||
|
if (playbackState == Player.STATE_ENDED) {
|
||||||
|
decoderCountersAtomicReference.set(
|
||||||
|
player.get().getVideoDecoderCounters());
|
||||||
|
playbackComplete.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlayerError(PlaybackException error) {
|
||||||
|
playbackException.set(error);
|
||||||
|
playbackComplete.open();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
player.get().setMediaItem(mediaItem);
|
||||||
|
player.get().prepare();
|
||||||
|
player.get().play();
|
||||||
|
});
|
||||||
|
|
||||||
|
playbackComplete.block();
|
||||||
|
getInstrumentation().runOnMainSync(() -> player.get().release());
|
||||||
|
getInstrumentation().waitForIdleSync();
|
||||||
|
assertThat(playbackException.get()).isNull();
|
||||||
|
// Which input buffers are dropped first depends on the number of MediaCodec buffer slots.
|
||||||
|
// This means the asserts cannot be isEqualTo.
|
||||||
|
assertThat(decoderCountersAtomicReference.get().droppedInputBufferCount).isAtLeast(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1527,11 +1527,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
// Make sure to decode and render the last frame.
|
// Make sure to decode and render the last frame.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (buffer.isEncrypted()) {
|
|
||||||
// Commonly used decryption algorithms require updating the initialization vector for each
|
|
||||||
// block processed. Skipping input buffers before the decoder is not allowed.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
boolean shouldSkipDecoderInputBuffer = isBufferBeforeStartTime(buffer);
|
boolean shouldSkipDecoderInputBuffer = isBufferBeforeStartTime(buffer);
|
||||||
if (!shouldSkipDecoderInputBuffer && !shouldDropDecoderInputBuffers) {
|
if (!shouldSkipDecoderInputBuffer && !shouldDropDecoderInputBuffers) {
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user