Skip to content

Early seek after media load may cause crash in DecoderVideoRenderer #2965

@HZ78high

Description

@HZ78high

Version

Media3 main branch

More version details

All

Devices that reproduce the issue

All

Devices that do not reproduce the issue

n/a

Reproducible in the demo app?

Yes

Reproduction steps

  1. Launch the Media3 demo app.
  2. Start playing any video asset use video decoder Extensions such as decoder_av1 .
  3. As soon as Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM becomes available (media is loading but not yet rendering output), immediately perform a seek operation inside the media.

Expected result

  • Seeking should be safe and exception-free as long as
    Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM is available.
  • Playback should continue normally after the seek when using decoder extensions.

Actual result

Player crash:

androidx.media3.exoplayer.ExoPlaybackException: Unexpected runtime error
  at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:921)
  at android.os.Handler.dispatchMessage(Handler.java:106)
  at android.os.Looper.loop(Looper.java:219)
  at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.NullPointerException
  at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:904)
  at androidx.media3.exoplayer.video.DecoderVideoRenderer.processOutputBuffer(DecoderVideoRenderer.java:882)
  at androidx.media3.exoplayer.video.DecoderVideoRenderer.drainOutputBuffer(DecoderVideoRenderer.java:832)
  at androidx.media3.exoplayer.video.DecoderVideoRenderer.render(DecoderVideoRenderer.java:221)
  at androidx.media3.exoplayer.RendererHolder.render(RendererHolder.java:392)
  at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1378)
  at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:707)
  at android.os.Handler.dispatchMessage(Handler.java:106) 
  at android.os.Looper.loop(Looper.java:219) 
  at android.os.HandlerThread.run(HandlerThread.java:67)

Media

In processOutputBuffer(long positionUs, long elapsedRealtimeUs), the outputFormat is resolved as follows:

Format format = formatQueue.pollFloor(bufferTimeUs);
if (format != null) {
outputFormat = format;
} else if (outputFormat == null) {
// After a stream change or after the initial start, there should be an input format change
// which we've not found. Check the Format queue in case the corresponding presentation
// timestamp is greater than bufferTimeUs
outputFormat = formatQueue.pollFirst();
}

However, if onPositionReset in
protected void onPositionReset(
long positionUs, boolean joining, boolean sampleStreamIsResetToKeyFrame)
throws ExoPlaybackException {
// TODO(b/440006632): Implement decode-only frame drop logic to allow skipping keyframe reset.
inputStreamEnded = false;
outputStreamEnded = false;
lowerFirstFrameState(C.FIRST_FRAME_NOT_RENDERED);
initialPositionUs = C.TIME_UNSET;
consecutiveDroppedFrameCount = 0;
if (decoder != null) {
flushDecoder();
}
if (joining) {
setJoiningDeadlineMs();
} else {
joiningDeadlineMs = C.TIME_UNSET;
}
formatQueue.clear();
}
is invoked before any output buffer is processed (for example, due to an early seek right after media load):

  • processOutputBuffer is not called so outputFormat is null
  • formatQueue.clear() is called
  • inputFormat may remain unchanged
  • onInputFormatChanged(FormatHolder formatHolder) is not triggered
    As a result:
  • formatQueue remains empty
  • Both pollFloor() and pollFirst() return null
  • outputFormat is never set
  • A subsequent checkNotNull(outputFormat) causes a crash

Suggested Fix: After onPositionReset, the next input sample must be treated as the first sample of the current Format, even if the format itself did not change.
This can be ensured by updating onPositionReset to include:

formatQueue.clear();
waitingForFirstSampleInFormat = true;

Bug Report

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions