android mediaplayer seekTo inside onPrepared

时间:2013-04-09 09:19:35

标签: android media-player seek

我的问题似乎只发生在android 4.2.2

我这样闲置状态 - >初始化状态 - > prepareAsync() - >在onPrepared中调用seekTo,但在这个Android版本上,媒体播放器返回

“尝试寻找过去的文件结尾:request = {int> 0},durationMs = 0”

并从头开始播放,因为我无法捕捉到这一点,也没有任何监听器,它只是将此消息写入日志,我无法真正做出反应。

更奇怪的是,如果我在onPrepared()中调用mediaPlayer.getDuration(),它将返回正确的值而不是0。

您认为这是一个媒体播放器错误还是有更好的地方可以调用seekTo?或者也许是一种如何知道seekTo失败的方法?如果它小于所需位置,我想避免定期检查当前位置,并尝试调用搜索,因为这种方法有很多不同的问题。

这是一个流畅的流媒体视频内容

3 个答案:

答案 0 :(得分:5)

我目前正在尝试找到同一问题的解决方案。到目前为止我提出的最好的是如下。

在4.2上我注意到收到了以下回叫:

1)onVideoSizeChanged() - 其中height和width = 0
2)onPrepared()
3)onVideoSizeChanged() - 正确的高度和宽度

你不能在(1)中调用seekTo,因为玩家尚未准备好。

正如您所指出的,如果您在(2)中调用seekTo,则媒体播放器会生成警告“尝试寻找过去的文件末尾”

如果已调用MediaPlayer.start(),您只会收到(3),但此时您可以成功调用seekTo()。

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();
        }
    }
}

(我个人不喜欢使用布尔警卫,但是如果你看一下sdk提供的媒体播放器样本,它会做类似的事情。)

在一系列设备/操作系统版本中进行测试,这提供了一种通用解决方案。但是,4.2中存在一个错误。对mMediaPlayer.start()的调用似乎会导致视频的前几帧在seekTo()发生之前开始播放,这对我的情况几乎不可见,但对您来说可能更明显。我目前正在寻找以某种方式隐藏我的表面视图,直到我收到onSeekComplete()事件,但这并不理想。

如果有人有更好的解决方案适用于所有操作系统版本,我很乐意听到它。

答案 1 :(得分:2)

这是NuPlayer实施的问题。与使用AwesomePlayer进行本地回放不同,NuPlayer没有正确的准备状态实现。仅在调用start()时建立网络连接,之后知道持续时间。如果持续时间为0,我可以通过绕过持续时间检查来解决问题,我之前已经尝试过了。

答案 2 :(得分:0)

以下是源代码:

418 status_t MediaPlayer::seekTo_l(int msec)
419 {
420     ALOGV("seekTo %d", msec);
421     if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
422         if ( msec < 0 ) {
423             ALOGW("Attempt to seek to invalid position: %d", msec);
424             msec = 0;
425         } else if ((mDuration > 0) && (msec > mDuration)) {
426             ALOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
427             msec = mDuration;
428         }
429         // cache duration
430         mCurrentPosition = msec;
431         if (mSeekPosition < 0) {
432             getDuration_l(NULL);
433             mSeekPosition = msec;
434             return mPlayer->seekTo(msec);
435         }
436         else {
437             ALOGV("Seek in progress - queue up seekTo[%d]", msec);
438             return NO_ERROR;
439         }
440     }
441     ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
442     return INVALID_OPERATION;
443 }

我建议你先调用getDuration()让mediaplayer实例强制初始化duration字段。 否则,请尝试在seekTo()之前调用start(),或者甚至在start()之后调用seekTo()。