Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android mediaplyer seekTo inside onPrepared

my problem seems to happen only on android 4.2.2

I go this way idle state -> initialized state -> prepareAsync() -> and in onPrepared the seekTo is called, but on this android version the mediaplayer returns

"Attempt to seek to past end of file: request = {int>0}, durationMs = 0"

and start to play from beginning, as there is no point where I could catch this, nor any listener, it just write this message to the log, I cannot really react on that.

What is even stranger is that if I call mediaPlayer.getDuration() in onPrepared() it returns proper value and not 0.

Do you think it is a mediaplayer bug or is there a better place where to call seekTo ? or maybe a way how to know the seekTo failed ? I would like to avoid periodically check current position if it is smaller than desired position and try to call seek to as this approach has a lot of different problems.

it is a smooth streaming video content

like image 235
Lukas Hanacek Avatar asked Apr 09 '13 09:04

Lukas Hanacek


2 Answers

I'm currently trying to find a solution to the same problem. The best I've come up with so far is as follows.

On 4.2 I've noticed that the following call backs are received:

1) onVideoSizeChanged() - where height and width = 0
2) onPrepared()
3) onVideoSizeChanged() - proper heights and widths

You can't call seekTo in (1) as the player is not yet prepared.

As you noted, if you call seekTo in (2) the media player generates the warning "Attempt to seek to past end of file"

You only receive (3) if MediaPlayer.start() has been called, but at this point you can call seekTo() successfully.

MediaPlayer mMediaPlayer = new MediaPlayer(); // + some initialisation code
boolean mVideoSizeIsSet = false;
boolean mMediaPlayerIsPrepared = false;

public void onPrepared(MediaPlayer mediaplayer) {
    Log.d(TAG, "onPrepared called");
    mMediaPlayerIsPrepared = true;

    if (mVideoSizeIsSet) {
        mMediaPlayer.seekTo();
    }

    mMediaPlayer.start()
}


public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
    Log.d(TAG, "onVideoSizeChanged called");

    if (width == 0 || height == 0) {
        Log.d(TAG, "invalid video width(" + width + ") or height(" + height + ")");
    } else {

        mVideoSizeIsSet = true;

        if (mMediaPlayerIsPrepared) {
            mMediaPlayer.seekTo();
        }
    }
}

(I personally don't like the use of the boolean guards, but if you look at the media player sample provided with the sdk, it does something similar).

Testing across a range of devices/OS versions, this provides a generic solution. However, there is a bug with 4.2. The call to mMediaPlayer.start() seems to cause the first few frames of the video start playing before the seekTo() occurs, this is barely visible for my situation, but may be more visible for you. I'm currently looking into hiding my surface view in some way until I receive the onSeekComplete() event, but this isn't ideal.

If anyone has a better solution that works across all OS versions I'd love to hear it.

like image 94
Simon Avatar answered Sep 27 '22 18:09

Simon


This is a problem with NuPlayer implementation. NuPlayer does not have a proper preparing state implementation, unlike local playback with AwesomePlayer. The network connection is established only when start() is called, after which the duration is known. The problem can be solved by bypassing the duration check if duration is 0, I have tried it before.

like image 41
Surajit Podder Avatar answered Sep 27 '22 17:09

Surajit Podder