google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.7k stars 6.02k forks source link

Inclusion of Info tag with TOC in a CBR MP3 file makes seeking less precise #10325

Closed ThibautRf closed 2 years ago

ThibautRf commented 2 years ago

Hello, I am part of the development team for the player library use to manage media in Radio France applications

We actually use ExoPlayer 2.16.1

As we didn't know if it's a bug or not, we decide to post it here first

Some applications users have reported problem on certain podcast (mp3) and after researching on the subject, we have identified media, where we can reproduce the problem

Reproduction : 1 - launch the media 2 - seek close to the end 3 - let run the media till the end

Observed behavior : The media continue to play few seconds after the progress bar indicate that the media is finished

Wanted behavior : The media stay in sync and end when the progress bar reach the end

Ex : We start playing a 54 min media, seek to 53:30, wait until the end of the media. 90% of the time, the progress bar reach 54:00. But the media still play few seconds before ending

After investigation, it don't come from our code and we can reproduce the behavior in the ExoPlayer Demo (with ExoPlayer 2.17.1) Here are Three media with which we can reproduce it

Extract from the modified "media.exolist.json" file from ExoPlayer Demo, used when reproducing in ExoPlayer Demo, to make things smoother

,{ "name": "Radio France", "samples": [ { "name": "En Namibie, chez les Himbas avec Solenn Bardet", "uri": "https://media.radiofrance-podcast.net/podcast09/13019-26.03.2022-ITEMA_22975320-2022F20970S0085-21.mp3" },{ "name": "40 jours sous terre, hors du temps", "uri": "https://media.radiofrance-podcast.net/podcast09/13019-07.05.2022-ITEMA_23018636-2022F20970S0127-21.mp3" },{ "name": "Enquête chez les manchots royaux, sur une île sauvage des mers australes", "uri": "https://media.radiofrance-podcast.net/podcast09/13019-23.04.2022-ITEMA_23004339-2022F20970S0113-21.mp3" }

We investigate the mp3 encoding and compared it to podcast (mp3) as the encoding is made by an other team To do so, we used Mp3tag and mp3checker-0.21 All our mp3 are CBR, so seeking with ExoPlayer shouldn't be the issue. The only difference we could observe is that the media where the behavior is occuring have a ID3v2.3 (ID3v2.3) tag, and all other mp3, which don't have the problem have ID3v2.3 (ID3v1 ID3v2.3) tag

Searching on the subject of tags, ID3 metadata norm, and if we understand well, the faulty mp3 only contains the ID3v2.3 tag, where the mp3 with no problem contain both ID3 v1 and v2.3 tags

As we tested those faulty mp3 in VLC and Windows player without having the problem. And having check ExoPlayer format support documentation located here -> https://exoplayer.dev/supported-formats.html We read and know that ExoPlayer support "ID3 metadata" but there is no detail about version support

As explained, the only difference we observe is the tags

Question 1: So, is ExoPlayer interpreting ID3v2.3 tags? and if it's the case, do you have an idea on why our CBR mp3 with only the ID3v2.3 tag seems to have an unprecise seeking issue


Question 2 : (Not related to the main subject) As we encounter some issues on the playback of our media since some time We just want to be sure about the playback behavior of ExoPlayer when an error is raised and send into the Player.Listener function onPlayerError

Can you confirm or refute the fact that if an Exception is raised by ExoPlayer and send to Player.Listener, onPlayerError function, the playback is stopped? (We assume it stop the playback at this point, as the Exception is passed to our code, but it's just to be 100% sure)


Question 3 : (Not related to the main subject) Sorry for the dumb question here, but we encountered the Exception -> com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker$PlaylistResetException

Reading it's documentation here -> https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.PlaylistResetException.html

It says "Thrown when the media sequence of a new snapshot indicates the server has reset.", does it mean that ExoPlayer indicates us a server side issue? Because the server didn't reset when we saw the exception

ojw28 commented 2 years ago

Looking at the first file, it seems the problem is caused by the Info header at the start of the file. It's a bit hard to find definitive documentation, but there's a description of it here in Section 2.3.1 (which describes the Xing header, but it's basically the same thing).

The Info header in this particular file includes the optional table of contents (TOC), which is essentially a time-to-byte mapping for the file that can be used by the player for seeking. Unfortunately, the way the TOC is represented in Xing/Info headers is quite imprecise. As a result, it cannot actually represent a time-to-byte mapping that perfectly describes a constant bitrate (aside: I think it is possible to get slightly closer than the TOC in this file, but this wouldn't fully solve the problem).

When ExoPlayer finds a Xing/Info header that includes a TOC, it uses the TOC for seeking. Since it's not precise, this introduces some impreciseness into the seeking, and it's this impreciseness that causes the problem you ultimately end up seeing. When an MP3 is VBR use of the TOC is going to be much better than nothing, but when the file is CBR it actually makes things worse.

A couple of possible solutions:

  1. When generating these MP3s, you could stop including the TOC in the Info header. If the file is CBR then I don't see what value it adds. It seems likely that the files you have that don't reproduce the issue either don't include an Info header at all, or omit the TOC from them.
  2. We could change ExoPlayer to ignore the TOC in Info headers based on an assumption that Info headers are only used in CBR files (and that Xing headers are always used instead for VBR content). I managed to find some references online indicating that this is (possibly?) supposed to be the case, but it's super hard to find any definitive documentation around these headers. What MP3 encoders actually do may also be different to what any documentation we find says. So I'd be somewhat hesitant to do that unless someone who knows more about MP3 than I do can provide some definitive information here!
ThibautRf commented 2 years ago

Hello, Thank you for the super clear answer and pointing out "MPEG Audio Frame Header". If you have answer for the other question, i am a taker! Best regards!

ojw28 commented 2 years ago

Can you confirm or refute the fact that if an Exception is raised by ExoPlayer and send to Player.Listener, onPlayerError function, the playback is stopped?

Correct

It says "Thrown when the media sequence of a new snapshot indicates the server has reset.", does it mean that ExoPlayer indicates us a server side issue? Because the server didn't reset when we saw the exception

Correct that this indicates a server-side issue. The HLS media playlist has somehow jumped backward in time, which is not allowed. A typical cause of this might be the server having to restart HLS streaming from scratch for some reason (e.g., because the process responsible for doing it crashed). But it could also be caused by other bugs in the server-side HLS implementation too.

ThibautRf commented 2 years ago

All my thanks for the super quick reaction and clear answers again!

ojw28 commented 2 years ago

No worries. Do you want us to keep this issue open to consider:

We could change ExoPlayer to ignore the TOC in Info headers based on an assumption that Info headers are only used in CBR files

There's no guarantee that we'd decide to do anything. I'm just wondering whether you'd like us to look at this further, or whether you're planning a fix on your side anyway. Thanks!

google-oss-bot commented 2 years ago

Hey @ThibautRf. We need more information to resolve this issue but there hasn't been an update in 14 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

google-oss-bot commented 2 years ago

Since there haven't been any recent updates here, I am going to close this issue.

@ThibautRf if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.