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_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
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
decoder_av1.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
Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMis available.Actual result
Player crash:
Media
In
processOutputBuffer(long positionUs, long elapsedRealtimeUs), theoutputFormatis resolved as follows:media/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java
Lines 868 to 876 in 0b20baa
However, if
onPositionResetinmedia/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java
Lines 294 to 312 in 0b20baa
processOutputBufferis not called sooutputFormatis nullformatQueue.clear()is calledinputFormatmay remain unchangedonInputFormatChanged(FormatHolder formatHolder)is not triggeredAs a result:
formatQueueremains emptypollFloor()andpollFirst()return nulloutputFormatis never setcheckNotNull(outputFormat)causes a crashSuggested 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
onPositionResetto include:Bug Report
adb bugreportto android-media-github@google.com after filing this issue.