Skip to content

Commit

Permalink
Fix potential video codec stall in tunneling (#27)
Browse files Browse the repository at this point in the history
In #26 I added an error when we detect a potential stall of the video
renderer (probably caused by the codec).
It wasn't working properly in tunneling, because we never handle the
decoded buffer (that's pretty much what tunneling does). It was
triggering 100% because of that.
This PR disables the detection in tunneling. And also cleans up how it
was done.
  • Loading branch information
SylvainMorel authored and simonlary committed Oct 1, 2024
1 parent c1ca2e7 commit 0895136
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) {

// MIREGO: added the following field and 2 functions to log and debug a specific issue (rendering pipleine stall)
// MIREGO: once the issue is solved, we should get rid of that code
private boolean hasReportedRenderingStall = false;
protected boolean hasReportedRenderingStall = false;

void saveFeedInputBufferStep(int stepIndex) {
if (getTrackType() == TRACK_TYPE_AUDIO) {
Expand Down Expand Up @@ -2180,6 +2180,10 @@ private void drainAndReinitializeCodec() throws ExoPlaybackException {

int dequeuedOutputCount = 0; // MIREGO for logging

protected void detectRendererStallMirego(boolean hasDequeuedBuffer) {
// NOOP
}

/**
* @return Whether it may be possible to drain more output data.
* @throws ExoPlaybackException If an error occurs draining the output buffer.
Expand Down Expand Up @@ -2211,22 +2215,12 @@ private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs)
outputIndex = codec.dequeueOutputBufferIndex(outputBufferInfo);
}

if (outputIndex < 0) {
// MIREGO video renderer stall detection
if (getTrackType() == TRACK_TYPE_VIDEO) {
detectRendererStallMirego(outputIndex >= 0);
}

// MIREGO video renderer stall detection
if (getTrackType() == TRACK_TYPE_VIDEO) {

if (Util.currentProcessedOutputBuffers < Util.currentQueuedInputBuffers) {
// waiting for a decoded buffer to be available from the codec
long currentTimeMs = System.currentTimeMillis();
if (Util.waitingForDecodedVideoBufferTimeMs == 0) {
Util.waitingForDecodedVideoBufferTimeMs = currentTimeMs; // starting to wait for the decoded buffer
} else if (!hasReportedRenderingStall && currentTimeMs > Util.waitingForDecodedVideoBufferTimeMs + 7000) { // been waiting for an arbitrary while, send an error to the app
Log.e(TAG, new PlaybackException("Video codec may be stalled error", new RuntimeException(), PlaybackException.ERROR_CODE_VIDEO_CODEC_STALLED));
hasReportedRenderingStall = true;
}
}
}
if (outputIndex < 0) {

// MIREGO
Log.v(Log.LOG_LEVEL_VERBOSE2, TAG, "drainOutputBuffer(type:%d) Failed dequeueOutputBufferIndex res: %d (dequeuedOutputCount: %d)",
Expand All @@ -2246,11 +2240,6 @@ private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs)
return false;
}

// MIREGO video renderer stall detection
if (getTrackType() == TRACK_TYPE_VIDEO) {
Util.waitingForDecodedVideoBufferTimeMs = 0; // we got a decoded buffer, reset the wait time
}

// MIREGO START
dequeuedOutputCount++;
Log.v(Log.LOG_LEVEL_VERBOSE3, TAG, "drainOutputBuffer(type:%d) presentationTime: %d dequeuedOutputCount: %d outputIndex: %d",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package androidx.media3.exoplayer.video;

import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.media3.common.C.TRACK_TYPE_VIDEO;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
Expand Down Expand Up @@ -1656,6 +1657,31 @@ private void detectTunnelingDroppedFrames(long presentationTimeUs) {
lastRenderedTunneledBufferPresentationTimeUs = presentationTimeUs;
}

protected void detectRendererStallMirego(boolean hasDequeuedBuffer) {
if (tunneling) {
return;
}

if (hasDequeuedBuffer) {
Util.waitingForDecodedVideoBufferTimeMs = 0; // we got a decoded buffer, reset the wait time
} else {
if (Util.currentProcessedOutputBuffers < Util.currentQueuedInputBuffers) {
// waiting for a decoded buffer to be available from the codec
long currentTimeMs = System.currentTimeMillis();
if (Util.waitingForDecodedVideoBufferTimeMs == 0) {
Util.waitingForDecodedVideoBufferTimeMs = currentTimeMs; // starting to wait for the decoded buffer
} else if (!hasReportedRenderingStall && currentTimeMs
> Util.waitingForDecodedVideoBufferTimeMs
+ 7000) { // been waiting for an arbitrary while, send an error to the app
Log.e(TAG,
new PlaybackException("Video codec may be stalled error", new RuntimeException(),
PlaybackException.ERROR_CODE_VIDEO_CODEC_STALLED));
hasReportedRenderingStall = true;
}
}
}
}

/** Called when a output EOS was received in tunneling mode. */
private void onProcessedTunneledEndOfStream() {
setPendingOutputEndOfStream();
Expand Down

0 comments on commit 0895136

Please sign in to comment.