androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.72k stars 413 forks source link

Player moves to next item in playlist before completing previous item. #1904

Open akshdeep-singh opened 2 days ago

akshdeep-singh commented 2 days ago

Version

Media3 1.4.1

More version details

No response

Devices that reproduce the issue

Pixel 8 running Android 15 Emulator Pixel 5 Android 14

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Not tested

Reproduction steps

  1. Play the issue causing mp3 file
  2. Wait until reached 1:40 (1 min 40 sec) position

Expected result

The media plays successfully

Actual result

Either the player starts playing next item in the playlist, or the sound stops but position is increasing. No Error shown by player. Following warnings are there:

6038-6103  CCodecConfig            I  query failed after returning 7 values (BAD_INDEX)
6038-6076  MediaCodec              D  keep callback message for reclaim
6038-6103  Codec2Client            W  query -- param skipped: index = 1342179345.
6038-6103  Codec2Client            W  query -- param skipped: index = 2415921170.

I am observing this issue with more mp3 files also but at different positions. The issue is not observed by other softwares, such as Windows Media Player, Chrome Browser Player.

Media

MP3 file link

Bug Report

icbaker commented 4 hours ago

This is happening because the file has a VBRI header where the table of contents (ToC) only covers 2255081 bytes, while the file on disk is 13605001 bytes long.

When I play this file in ExoPlayer I see a warning logged about this:

VbriSeeker              androidx.media3.demo.main            W  VBRI data size mismatch: 13605001, 2255081

The result of this that we indicate the frame just before byte 2255081 is the last sample, and so playback stops at that point. With some extra logging I see dataEndPosition=2255081, extractorInput.getPeekPosition()=2255491 at these lines:

https://github.com/androidx/media/blob/827966b7a46b48cd17fe27b7b82d01fd9cd4a045/libraries/extractor/src/main/java/androidx/media3/extractor/mp3/Mp3Extractor.java#L322-L324

https://github.com/androidx/media/blob/827966b7a46b48cd17fe27b7b82d01fd9cd4a045/libraries/extractor/src/main/java/androidx/media3/extractor/mp3/Mp3Extractor.java#L455-L460


We are currently assuming that the ToC in the VBRI frame covers the whole file. This is perhaps an unreasonable assumption.

The VBRI frame also has a bytes field to indicate the amount of MP3 data in the file (which we don't use atm). This should be the number of MP3 bytes, not including the VBRI frame itself.

In your file, the VBRI frame has bytes=13603849, so based on that we'd expect the end of the MP3 data to be at:

  vbriFrameStart + vbriFrameSize + bytes
= 1024 + 522 + 13603849
= 13605395

This seems incorrect, because the file on disk is only 13605001 bytes long!

With a bit of guesswork, and noting that the VBRI frame also has a frameSize=128 field (which is meant to be the average frame size of the rest of the file), we can re-run the calculation assuming whatever populated the bytes field incorrectly assumed the VBRI frame itself was 128 bytes long:

  vbriFrameStart + avgFrameSize + bytes
= 1024 + 128 + 13603849
= 13605001

And this now exactly matches the file on disk.

Aside: We can also derive the MP3 data length from the VBRI frame size & count values: numFrames * frameSize = 2882048. This is clearly also incorrect in this file (but roughly consistent with the ToC).

Summary:

This file has a strange VBRI frame, with a ToC that only covers the first ~1:40 of the file, an incorrect average frameSize value, and an incorrect bytes value which assumes the VBRI frame itself is 128 bytes long (when it's actually 522 bytes long) - meaning it's wrong by 394 bytes.


If we switch to using the bytes field from the VBRI header then other parts of ExoPlayer's MP3 machinery handle the 394 length error fairly gracefully and playback continues for the whole duration of the file. I'll send a change for this.

icbaker commented 3 hours ago

This file has a strange VBRI frame, with a ToC that only covers the first ~1:40 of the file

This also results in seeking being broken/nonsensical for this file, because the VBRI ToC assumes that each of the N entries covers an Nth of the file. The result of this is that (with the bytes fix applied), when I play your file and seek near the end, playback continues well past the 9:48 'duration' - because the "seek near the end" actually resulted in us seeking near the end of the first 2255081 bytes, so there's lots more MP3 data left to consume.