Skip to content

Setting video surface after the player is ready causes a rebuffer #1973

Closed

Description

@sgosantos

Version

Media3 1.5.0

More version details

No response

Devices that reproduce the issue

  • Pixel 7 running Android 15
  • Android Emulator Pixel 7 API 33
  • Android Emulator Pixel 7 API 30

(there are the ones I tried to reproduce. I believe this happens in other devices also)

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

The issue happens when I prepare the player with an initialPosition, playWhenReady=false and with no surface. Later, after the player is READY, I set the surface and playWhenReady=true, then the player state changes back to BUFFERING and READY again.

Detailed steps:

  1. Set playWhenReady=false
  2. Set an initial playback position (for example, seekTo=3_000L)
  3. Prepare the player
  4. The player moves to BUFFERING state
  5. The player moves to READY state
  6. Wait some time before setting the surface (for example, 2_000L)
  7. Set the surface in the player
  8. Set playWhenReady=true

Reproducing in the ExoPlayer demo app.

  • Apply the following patch in the Media3 git repo.
    buffering-bug.patch
  • Run the ExoPlayer demo APP and select a video to play
  • I could reproduce it 99%* of the times when:
    • I play the Clear DASH UHD (MP4, H264) on the Pixel 7
    • I play the Clear DASH UHD (MP4, H264) and HD (MP4, H264) on the Android Emulator Pixel 7 API 30
    • I play the Clear DASH UHD (MP4, H264) and HD (MP4, H264) on the Android Emulator Pixel 7 API 33
      *in the emulator it seems it didn't happen in the first playback, but it happened 100% of the times in the following attempts.

Other info

  • I can only see the issue happening if I start the playback with an initialPosition != 0.
  • I could also reproduce the issue when I clip the media.

Expected result

The player starts playing and no new BUFFERING event is trigged, since the player is already in the READY state

Actual result

The player goes to BUFFERING state again , although it was already on the READY state.

Media

  • Clear DASH UHD (MP4, H264) and HD (MP4, H264)
  • Also reproduced with the HLS 16x9 basic stream (TS)

It probably happens with other media types, but these are the ones I played with the most.

Bug Report

Activity

  1. changed the title [-]Setting video surface after the player is ready causes causes a rebuffer e[/-] [+]Setting video surface after the player is ready causes a rebuffer[/+] on Dec 13, 2024
  2. sgosantos commented on Jan 27, 2025

    @sgosantos
    Author

    @marcbaechinger Hello! Do you have any update on this issue?
    I've also tested it on 1.3.x and 1.4.x and could reproduce in both of them.

  3. tonihei commented on Feb 3, 2025

    @tonihei
    Collaborator

    I found the underlying problem. The playback is actually not yet ready at the time of attaching the surface and calling setPlayWhenReady(true), so going into the buffering state is working as intended. You can see this by extending the delay to something like 30 seconds, where the additional buffering doesn't happen anymore.

    So the real question is: why does the player need 20+ seconds to decode 2 seconds of video to get ready for playback? It turns out that this is caused by a low-power mode that only executes new actions every second. This mode is entered because the video renderer is apparently ready (because it's rendering to a placeholder surface) and the player is paused, so nothing needs to be done from the player's perspective. We'll have a look to find a solution to this issue.

  4. sgosantos commented on Feb 3, 2025

    @sgosantos
    Author

    @tonihei thanks for having a look!
    you can't think of any work around yet while we don't have a proper fix, right?

  5. tonihei commented on Feb 3, 2025

    @tonihei
    Collaborator

    If you never want to play without a surface, you can do the following as a workaround:

    new ExoPlayer.Builder(context)
       .setRenderersFactory(
          new DefaultRenderersFactory(context) {
             @Override
             protected void buildVideoRenderers(...) {
               // copy base class logic, or just add default renderer:
               out.add(new MediaCodecVideoRenderer(...) {
                  @Override
                  public boolean isReady() {
                    if (getSurface() == null) {
                      // Ensure ExoPlayer thinks there is work to be done while we haven't attached a surface.
                      return false;
                    }
                    return super.isReady();
                  }
               });
             }
          }
    

    Note that this also means the player never becomes READY until the surface is attached.

  6. sgosantos commented on Feb 19, 2025

    @sgosantos
    Author

    @tonihei thanks for the workaround, I realized I did not reply to it.
    Several times we want to play with and without a surface, so maybe this would help only in certain scenarios 🤔

    Do you have any idea when this bug will be prioritized?

  7. tonihei commented on Feb 19, 2025

    @tonihei
    Collaborator

    We already have a pending change for it to fix it properly (still in review, because there was some discussion around naming and the exact approach we take). Hoping to get the bug fix it into Media3 1.6.0-rc01 unless there are further discussion needed.

  8. sgosantos commented on Feb 19, 2025

    @sgosantos
    Author

    @tonihei cool, great to know!
    Is there a PR already I could track?

    Thanks for taking a look at it!

  9. tonihei commented on Feb 19, 2025

    @tonihei
    Collaborator

    We use internal Google tooling for all changes and reviews, so there is unfortunately no way to see pending progress until it's fully submitted and uploaded to the main branch on GitHub. PRs are only used for external contributions.

  10. tonihei commented on Mar 18, 2025

    @tonihei
    Collaborator

    This issue is now fixed on the main branch. Sorry for the additional delay as it required some internal refactor before we could safely apply the fix.

  11. sgosantos commented on Mar 18, 2025

    @sgosantos
    Author

    Cool! Thanks a lot for fixing it!

  12. locked and limited conversation to collaborators on May 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions