Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ExoPlayer.setVideoEffects seek stucked Occasionally #1535

Open
1 task
captain81 opened this issue Jul 9, 2024 · 7 comments
Open
1 task

ExoPlayer.setVideoEffects seek stucked Occasionally #1535

captain81 opened this issue Jul 9, 2024 · 7 comments
Assignees

Comments

@captain81
Copy link

Version

Media3 main branch

More version details

When using ExoPlayer.setVideoEffects 。Normal codec.releaseOutputBuffer, the codec will send the frame buffer to the surface, and then the surfacetexture will have an onFrameAvaliable callback, indicating that the current frame drawing is completed.After seeking several times, codec will flush, codec.releaseOutputBuffer 5 times, but not receive any surfacetexture onFrameAvaliable callback. Why surfacetexture onFrameAvaliable callback not invoke?

Devices that reproduce the issue

Android14

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

1.use ExoPlayer.setVideoEffects
2. seek many times

Expected result

seek anytimes play normal

Actual result

seek many times, play stuck

Media

NA

Bug Report

@captain81
Copy link
Author

captain81 commented Jul 9, 2024

I have added this patch bef3d51. Seek stucked Occasionally.codec.releaseOutputBuffer 5 times, but not receive any surfacetexture onFrameAvaliable callback

@claincly
Copy link
Contributor

claincly commented Jul 9, 2024

This is curious, can you check a few things, given that you've already looked at ExternalTextureManager? We have trouble reproducing it

  • Do you see Interrupted when waiting for MediaCodec frames to arrive being logged?
  • Can you check the method releaseAllFramesFromMediaCodec() being called a few times?
  • Can you check that availableFrameCount and pendingFrames are updated as expected?

I think by your description, it sounded like registerInputFrame() is called 5 times, after you seek, but SurfaceTexture.OnFrameAvailableListener is not called?

@captain81
Copy link
Author

captain81 commented Jul 10, 2024

I have resolved this issue. As seek invoke flush, codec.releaseOutputBuffer queueBuffer to BufferQueue, but the consumer surfaceTexture.setOnFrameAvailableListener.OnFrameAvailable is interrupted by flush, so the queued Buffer can't consumed, codec.releaseOutputBuffer queueBuffer again surfaceTexture OnFrameAvailable can't be invoked forever. so we should invoke surfaceTexture.updateTexImage() to consumer the queued buffer here.

private void maybeQueueFrameToExternalShaderProgram() {
    if (externalShaderProgramInputCapacity.get() == 0
        || availableFrameCount == 0
        || currentFrame != null) {
      **_surfaceTexture.updateTexImage();_**
      return;
    }

Is this fix OK?

@claincly
Copy link
Contributor

Thanks for the investigation, I think the find is valid. As for the fix I'm not sure it's safe to call surfaceTexture.updateTexImage() when the available count is zero.

We should address the issue from the point that the runnable (surfaceTexture.setOnFrameAvailableListener.OnFrameAvailable) is not cancelled during flushing.

OTOH, I wonder how do you manage to reliably trigger this case when testing?

@captain81
Copy link
Author

Use ExoPlayer.setVideoEffects,just seek many times, when flush is between codec.releaseOutputBuffer and surfaceTexture.OnFrameAvailable , surfaceTexture.OnFrameAvailable will not invoke. If flush is after codec.releaseOutputBuffer and surfaceTexture.OnFrameAvailable, this issue cannot be reproduced. As OnFrameAvailable should use acquireBuffer, or OnFrameAvailable will not be invoked later. You can run seek or fastseek automatic

@captain81
Copy link
Author

captain81 commented Jul 11, 2024

DefaultVideoFrameProcessor.flush() videoFrameProcessingTaskExecutor.flush(); will remove ExternalTextureManager's videoFrameProcessingTaskExecutor, so surfaceTexture.OnFrameAvailable can't invoke surfaceTexture.updateTexImage(). I Just move videoFrameProcessingTaskExecutor.flush() after textureManager.releaseAllRegisteredFrames(), as textureManager.releaseAllRegisteredFrames() has invoked surfaceTexture.updateTexImage()

      CountDownLatch latch = new CountDownLatch(1);
      TextureManager textureManager = inputSwitcher.activeTextureManager();
      textureManager.releaseAllRegisteredFrames();
      videoFrameProcessingTaskExecutor.flush();(move to here)

is this fix OK?

@claincly
Copy link
Contributor

No not really - that's because when flushing, we want to stop VideoFrameProcessing doing any further work, including presenting newly processed frames, and flushing the task executor (sort of) guarantees that.

I think a proper fix would be making the task we post in surfaceTexture.OnFrameAvailable non-canceallable. I'll try push a fix

Thanks for providing the repro hint!

copybara-service bot pushed a commit that referenced this issue Sep 5, 2024
Seeking was causing the player to hang in the following scenario:
1. The surfaceTexture's onFrameAvailableListener is called in
   ExternalTextureManager to notify that a new frame is available.
2. This call submits a task on the GL thread.
3. A seek is performed and DefaultVideoFrameProcessor.flush() is called
   before the task submitted in 2 is executed.
4. DefaultVideoFrameProcessor.flush() flushes the task executor, so that
   the task submitted in 2 never gets executed.
5. Once the seek is over, the first frame is registered and rendered on
   the surface texture.
6. Playback hangs because the onFrameAvailableListener is never called
   for this new frame. This is because surfaceTexture.updateTexImage()
   was never called on the frame that became available in 1.

This fix is making sure that the task submitted in 2 always gets executed.

Issue: #1535
PiperOrigin-RevId: 671389215
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants