检测视频播放器的缓冲状态

15

有没有人知道如何检测VideoView何时正在缓冲?

我想在视频缓冲时显示一个ProgressDialog。

到目前为止,我尝试使用OnPreparedListener,但那只适用于视频第一次加载时。如果视频正在播放并且用户将滑块移动到不同的位置,则视频仍然处于“准备就绪”状态,即使它正在缓冲。

我也试过(我知道这很糟糕)使用一个AsyncThread来忙等isPlaying():

private class BufferTask extends AsyncTask<Void, Void, Void> {

  protected Void doInBackground(Void...voids) {
    final VideoView videoView = (VideoView)findViewById(R.id.video);
    while (!videoView.isPlaying()) { }
    return null;
  }

 protected void onPostExecute(Void v) {
     // Hide the dialog here...
 }
}

这无法正常工作,因为一旦调用start()方法,VideoView会被认为正在播放,即使它正在缓冲。

我能想到的唯一解决方案是构建一个自定义的VideoView类型类,这样我就可以访问它的MediaPlayer实例。

有什么想法吗?谢谢阅读。


1
你的问题解决了吗? - Pandiri Deepak
6个回答

17

自从API level 17,您现在可以从MediaPlayer访问InfoListener:

final MediaPlayer.OnInfoListener onInfoToPlayStateListener = new MediaPlayer.OnInfoListener() {

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        switch (what) {
            case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: {
                mProgressBar.setVisibility(View.GONE);
                return true;
            }
            case MediaPlayer.MEDIA_INFO_BUFFERING_START: {
                mProgressBar.setVisibility(View.VISIBLE);
                return true;
            }
            case MediaPlayer.MEDIA_INFO_BUFFERING_END: {
                mProgressBar.setVisibility(View.GONE);
                return true;
            }
        }
        return false;
    }

});

mVideoView.setOnInfoListener(onInfoToPlayStateListener);

3
我们不应该隐藏缓冲结束的进度吗? - Saeed Neamati

10

为了不实现自定义VideoView,我想到了以下的解决方法。思路是每隔1秒检查当前位置是否与1秒前相同。如果相同,则视频正在缓冲。如果不同,则视频正在真正播放。

final Handler handler = new Handler(); 
Runnable runnable = new Runnable() { 
    public void run() {
        int duration = videoView.getCurrentPosition();
        if (old_duration == duration && videoView.isPlaying()) {
            videoMessage.setVisibility(View.VISIBLE);
        } else {
            videoMessage.setVisibility(View.GONE);
        }
        old_duration = duration;

        handler.postDelayed(runnable, 1000);
    }
};
handler.postDelayed(runnable, 0);

videoMessage只是一个TextView,在我的VideoView中心放置了文本“缓冲中...”。


5
这段代码看起来像是递归的指数级内存消耗器,对吗? - Behnam

4

当缓冲时,VideoView显示进度。 下面的代码对我有用:

videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(final MediaPlayer mp) {
                mp.start();
                mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra) {
                        switch (what) {
                            case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: {
                                progressBar.setVisibility(View.GONE);
                                return true;
                            }
                            case MediaPlayer.MEDIA_INFO_BUFFERING_START: {
                                progressBar.setVisibility(View.VISIBLE);
                                return true;
                            }
                            case MediaPlayer.MEDIA_INFO_BUFFERING_END: {
                                progressBar.setVisibility(View.GONE);
                                return true;
                            }
                        }
                        return false;
                    }
                });
            }
        });

欢迎来到 Stack Overflow!请不要仅仅把您的代码丢在这里。尽量给您的答案提供一个良好的描述。参见:如何编写一个好的答案? - sɐunıɔןɐqɐp

4
每次VideoView缓冲时,以下代码将显示一个缓冲对话框。
    final ProgressDialog bufferingDialog;
    bufferingDialog = ProgressDialog.show(context,
            "Buffering", "Please wait", true, true);

    VideoView videoView;
    videoView = (VideoView) findViewById(R.id.video_view);
    videoView.setVideoPath(path);
    videoView.setMediaController(new MediaController(context));
    videoView.requestFocus();
    videoView.start();
    videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                @Override
                public boolean onInfo(MediaPlayer mp, int what, int extra) {
                    if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START)
                        bufferingDialog.show();
                    if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END)
                        bufferingDialog.dismiss();
                    return false;
                }
            });
        }
    });
    videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            bufferingDialog.dismiss();
            return false;
        }
    });

1

我正在做类似的事情,但是无法想出一个好的解决方案。如果你还没有看到的话,这里有一些有趣的解决方案可以让你参考。

无论如何,我想出了以下的hack方法,它在上面的帖子中被暗示,并且现在运行得还不错。

@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
    float temp = ((float)mp.getCurrentPosition() / (float)mp.getDuration())*100;
    if(Math.abs(percent - temp) < 1) {
        buffer_fail++;
        if(buffer_fail == 15) {
            //buffer failed
        }
    }
}

这不能在 VideoView 内使用。 - Rui
3
使用从VideoView.setOnPreparedListener获得的MediaPlayer。 - Gil SH

0

这对我有用

boolean b_start = true;
boolean b_end = true;                                                                  
 final MediaPlayer.OnInfoListener onInfoToPlayStateListener = new MediaPlayer.OnInfoListener() {

        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            switch (what) {
                case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: {
                    dialog1.setVisibility(View.GONE);
                    b_end = false;
                    b_start = false;

                }
                case MediaPlayer.MEDIA_INFO_BUFFERING_START: {
                    if (b_start){
                    dialog1.setVisibility(View.VISIBLE);
                    }
                    b_start = true;

                }
                case MediaPlayer.MEDIA_INFO_BUFFERING_END: {
                    if(b_end){
                    dialog1.setVisibility(View.VISIBLE);
                    }
                    b_end = true;
                }
            }
            return false;
        }

    };


    videoView.setOnInfoListener(onInfoToPlayStateListener);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接