MediaPlayer.getDuration() returning wrong duration

2019-05-14 00:17发布

问题:

The MediaPlayer's getDuration() method is giving me an incorrect value for some audio files. I think the common trait for all these files is that they were manipulated using Audacity or some other audio editing tool. This is a problem when trying to tie MediaPlayer progress to a Progress Bar.

I went ahead and logged it:

while(mPlayer.isPlaying())
    Log.i("progress/total", 
            mPlayer.getCurrentPosition() + 
            "/" + mPlayer.getDuration());

and found this:

I/progress/total(643): 14615/14620
I/progress/total(643): 14647/14620

This is only two log line of thousands, but the point is after the progress passes what getDuration() believes to be the total duration of the song, it just keeps going. Because the MediaPlayer can in fact give the correct total for duration, is there a way to use this to get a proper maximum for my ProgressBar?

回答1:

I had similar problem when MediaPlayer.getDuration() returned 542434 ms for mp3 file (HTC Desire C with ICS 4.0.3). File itself was around 89 seconds, difference is too big. I checked mp3 file content and saw some strange xml like:

<?xpacket begin="п»ї" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.351735, 2008/07/22-18:04:26        ">

After saving this file as new one that xml was dropped and getDuration() returned correct value. I know that it will not help those who need playing files you can't modify, but for those who can - it should help.



回答2:

I was trying to play demo player a few while ago ,when i tested in Android emulator ,its behavior was the same as like you mentioned in your question but when i tried in some real device it gave me accurate value of media duration.

If your intention is only play media syncing with seekbar then you can do something like below ,

if (!mediaPlayer.isPlaying())
mediaPlayer.start();

handler.post(new SeekbarRefresh(seekbar));

//Class to update progress of seekbar according to music player 
private class SeekbarRefresh implements Runnable {
    SeekBar seekBar;

    public SeekbarRefresh(SeekBar seekBar, ImageView imageView) {
        this.seekBar = seekBar;
    }

    @Override
    public void run() {

        if (mediaPlayer != null) {
            if (mediaPlayer.getDuration() > 0) {
                int currentDuration = mediaPlayer.getCurrentPosition();
                seekBar.setProgress(currentDuration);
                if (mediaPlayer.isPlaying()){
                    handler.post(this);
                    isAudioPlaying = true;
                     }
                else {
                    handler.removeCallbacks(this);
                    isAudioPlaying = false;
                }
            }
        }
    }
}

    seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                boolean fromUser) {

            mediaPlayer.seekTo(progress);
        }
    });


回答3:

I have encountered a similar situation. In my case the time difference between mPlayer.getDuration() to mPlayer.getCurrentPosition() was around 80 seconds.

After reading few posts on the subject, I used third party software to convert the mp3's sample rate from 22,000 kHz to 44,100 kHz. Once converted, the result of getDuration() and getCurrentPosition() are the almost the same (0.0012s constant error).

Here is the test used:

dur = mp.getDuration();
Log.d("dur", dur + " <- getDuration");
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    public void onCompletion(MediaPlayer mp) {
        // finish current activity
       Log.d("dur", mp.getCurrentPosition() + " <- getCurrentPostion");

    }
});