mirror of
https://github.com/androidx/media.git
synced 2025-05-09 08:30:43 +08:00
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
This commit is contained in:
parent
a3be937650
commit
55f696e11d
@ -17,6 +17,8 @@ package com.google.android.exoplayer2.testutil;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import android.os.Handler;
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
@ -25,9 +27,12 @@ import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
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.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
|
||||
import com.google.android.exoplayer2.video.VideoRendererEventListener;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@ -66,6 +71,7 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
|
||||
private int queueSize;
|
||||
private int bufferCount;
|
||||
private int minimumInsertIndex;
|
||||
private boolean skipToPositionBeforeRenderingFirstFrame;
|
||||
|
||||
public DebugMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
|
||||
long allowedJoiningTimeMs, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
|
||||
@ -75,10 +81,23 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
|
||||
eventHandler, eventListener, maxDroppedFrameCountToNotify);
|
||||
}
|
||||
|
||||
@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() {
|
||||
super.releaseCodec();
|
||||
clearTimestamps();
|
||||
skipToPositionBeforeRenderingFirstFrame = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -102,6 +121,34 @@ public class DebugRenderersFactory extends DefaultRenderersFactory {
|
||||
maybeShiftTimestampsList();
|
||||
}
|
||||
|
||||
@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) {
|
||||
super.onProcessedOutputBuffer(presentationTimeUs);
|
||||
|
Loading…
x
Reference in New Issue
Block a user