Commit 55f696e1 by olly Committed by Oliver Woodman

Fix spurious failures due to late decoding.

By default, if a codec is instantiated during an ongoing
playback, ExoPlayer will render the first frame that it
receives (so that there's "something other than black"
drawn to the surface). This frame is the key-frame before
the current playback position, and may be as much as 5
seconds behind the current position. ExoPlayer then drops
subsequent frames that are late until it's caught up to
the current position again.

For GTS tests that are counting dropped frames, this is
not desirable behavior, since it will cause spurious test
failures in cases where DummySurface is not supported.
This change overrides the default behavior so that the
player instead skips (rather than drops) frames until it's
caught up to the current playback position, and only then
renders the first frame.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=170175944
parent a3be9376
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer2.testutil; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer2.testutil;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.os.Handler; import android.os.Handler;
import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
...@@ -25,9 +27,12 @@ import com.google.android.exoplayer2.Renderer; ...@@ -25,9 +27,12 @@ import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import com.google.android.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
...@@ -66,6 +71,7 @@ public class DebugRenderersFactory extends DefaultRenderersFactory { ...@@ -66,6 +71,7 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
private int queueSize; private int queueSize;
private int bufferCount; private int bufferCount;
private int minimumInsertIndex; private int minimumInsertIndex;
private boolean skipToPositionBeforeRenderingFirstFrame;
public DebugMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, public DebugMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
long allowedJoiningTimeMs, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, long allowedJoiningTimeMs, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
...@@ -76,9 +82,22 @@ public class DebugRenderersFactory extends DefaultRenderersFactory { ...@@ -76,9 +82,22 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
} }
@Override @Override
protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format,
MediaCrypto crypto) throws DecoderQueryException {
// If the codec is being initialized whilst the renderer is started, default behavior is to
// render the first frame (i.e. the keyframe before the current position), then drop frames up
// to the current playback position. For test runs that place a maximum limit on the number of
// dropped frames allowed, this is not desired behavior. Hence we skip (rather than drop)
// frames up to the current playback position [Internal: b/66494991].
skipToPositionBeforeRenderingFirstFrame = getState() == Renderer.STATE_STARTED;
super.configureCodec(codecInfo, codec, format, crypto);
}
@Override
protected void releaseCodec() { protected void releaseCodec() {
super.releaseCodec(); super.releaseCodec();
clearTimestamps(); clearTimestamps();
skipToPositionBeforeRenderingFirstFrame = false;
} }
@Override @Override
...@@ -103,6 +122,34 @@ public class DebugRenderersFactory extends DefaultRenderersFactory { ...@@ -103,6 +122,34 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
} }
@Override @Override
protected boolean processOutputBuffer(long positionUs, long elapsedRealtimeUs, MediaCodec codec,
ByteBuffer buffer, int bufferIndex, int bufferFlags, long bufferPresentationTimeUs,
boolean shouldSkip) {
if (skipToPositionBeforeRenderingFirstFrame && bufferPresentationTimeUs < positionUs) {
// After the codec has been initialized, don't render the first frame until we've caught up
// to the playback position. Else test runs on devices that do not support dummy surface
// will drop frames between rendering the first one and catching up [Internal: b/66494991].
shouldSkip = true;
}
return super.processOutputBuffer(positionUs, elapsedRealtimeUs, codec, buffer, bufferIndex,
bufferFlags, bufferPresentationTimeUs, shouldSkip);
}
@Override
protected void renderOutputBuffer(MediaCodec codec, int index, long presentationTimeUs) {
skipToPositionBeforeRenderingFirstFrame = false;
super.renderOutputBuffer(codec, index, presentationTimeUs);
}
@TargetApi(21)
@Override
protected void renderOutputBufferV21(MediaCodec codec, int index, long presentationTimeUs,
long releaseTimeNs) {
skipToPositionBeforeRenderingFirstFrame = false;
super.renderOutputBufferV21(codec, index, presentationTimeUs, releaseTimeNs);
}
@Override
protected void onProcessedOutputBuffer(long presentationTimeUs) { protected void onProcessedOutputBuffer(long presentationTimeUs) {
super.onProcessedOutputBuffer(presentationTimeUs); super.onProcessedOutputBuffer(presentationTimeUs);
bufferCount++; bufferCount++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment