Why is MediaPlayer.seekTo(int msec)
so inaccurate?
It's sometimes 30 seconds early (with mp3's of both variable and constant bitrates)! Is seeking with audio inherently problematic or is this method broken? Is it to do with buffering or what?
I've also noticed that the total runtime getDuration()
can be wrong (which isn't a big issue) and I've tested that getCurrentPosition()
is accurate enough (as in every n seconds of playback, it increases by n thousand). I'm on Android 2.2.
Finally, does anybody know which formats if any it actually works consistently for (preferably other than wav which presumably it does)?
EDIT:
I mainly listen to podcasts. smodcast and Thinking Allowed have been problematic several times, even after being converted/re-encoded to CBR. The files aren't corrupted.
QuickMediaConverter (Windows) seems to work ok but Sound Converter (Ubuntu) has generated some dodgy files. I'll try sticking to the former...
UPDATE: QuickMediaConverter works really well but no idea why. No problems since!
There are two ways in which a multimedia framework will perform a seek operation on a multimedia (AV) file.
Seek to Key frame - The video when encoded will usually have something called as the I frame or the Key frame, it means that this frame has lot of information and can be used to decode a frame in its entirety. To reduce the amount of space all the frames are not encoded as key frames instead they are encoded as P (Predicted) frames or predicted frames, meaning you can decode a P frame with the help from the key frame.
So during the seek operation, in this case the seeking is done to the closest key frame for a given time duration. For example if the user seeks to 40secs and the closest key frame is at 35th sec then seeking is done to the 35th sec and not to the 40th second.
Seek to Time - This is seeking to the accurate time that the user demands.
The seeking is still done at the closest key frame since otherwise you will see green patches or pixelation of the video which is highly undesirable. So instead the seeking is done to the key frame and then frames are decoded until the required time but these frames are dropped and are not shown to the user. In above example, all the decoded frames from the 35th to 40th second are discarded and only the frames beyond 40th sec are shown to the user.
In case of audio only files there can be two cases (If there is no parser or a parser that doesnot build the timestamp table then -)
CBR - Constant Bit Rate - Since the bit rate is constant we can skip necessary number of bytes to a given time (Bitrate * timeToSeek = bytes to be skipped)
VBR - Variable Bit rate - The bit rate is not constant it keeps varying. So in this case the find out the average bitrate of the file and then use the above method, in this case seeking will not be accurate.
Now coming back to your question, I can tell with confidence that it works well and is accurate for the majority of the mediafiles.
The only reason why you could be facing such issues is becuase the media file is itself corrupted. (It is just not possible to have a difference of 30seconds during seek + you are saying the duration is not returned correctly. And none of the mediaplayer API's are broken for Android 2.2)
As to which formats is supported by Android see this link
So can you try with an another mp3 file?