-
Notifications
You must be signed in to change notification settings - Fork 769
Early seek after media load may cause crash in DecoderVideoRenderer #2965
Copy link
Copy link
Closed
Labels
Description
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
- Launch the Media3 demo app.
- Start playing any video asset use video decoder Extensions such as
decoder_av1. - As soon as
Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMbecomes 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_ITEMis 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:
media/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java
Lines 868 to 876 in 0b20baa
| 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 media/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java
Lines 294 to 312 in 0b20baa
| 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(); | |
| } |
processOutputBufferis not called sooutputFormatis nullformatQueue.clear()is calledinputFormatmay remain unchangedonInputFormatChanged(FormatHolder formatHolder)is not triggered
As a result:formatQueueremains empty- Both
pollFloor()andpollFirst()return null outputFormatis 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
- You will email the zip file produced by
adb bugreportto android-media-github@google.com after filing this issue.
Reactions are currently unavailable