【问题标题】:Detect if a VideoVIew is buffering检测 VideoVIew 是否正在缓冲
【发布时间】:2011-10-23 15:53:42
【问题描述】:

有谁知道是否可以检测到 VideoView 何时缓冲?

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

到目前为止,我尝试使用 OnPreparedListener,但这仅在首次加载视频时有效。如果视频正在播放并且用户将拖拽栏移动到不同的点,则视频仍处于“准备就绪”状态,即使它正在缓冲。

我也尝试过(我知道这很糟糕)一个忙于等待 isPlaying() 的 AsyncThread:

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 实例。

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

【问题讨论】:

  • 你的问题解决了吗?

标签: android media-player android-videoview


【解决方案1】:

由于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);

【讨论】:

  • 我们不应该在缓冲结束时隐藏进度吗?
【解决方案2】:

为了不实现自定义 VideoView,我使用了以下 hack。这个想法是每 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,其文本“Buffering...”位于我的 VideoView 的中心。

【讨论】:

  • 这看起来像一段递归的指数内存消耗代码。不是吗?
【解决方案3】:

以下代码将在每次 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;
        }
    });

【讨论】:

    【解决方案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!请不要把你的源代码扔在这里。试着给你的答案一个好的描述。见:How do I write a good answer?
    【解决方案5】:

    我正在研究类似的东西,但想不出一个很好的解决方案。 here 发布了一些有趣的解决方案,如果您还没有看到,请查看它们。

    无论如何,我想出了上面线程中暗示的以下技巧,并且现在可以正常工作。

    @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 中使用。
    • 所以将它与从 VideoView.setOnPreparedListener 获得的 MediaPlayer 一起使用
    【解决方案6】:

    这对我有用

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-26
      • 2016-12-16
      • 2011-06-29
      • 2014-06-18
      • 1970-01-01
      • 2014-08-13
      • 2011-08-02
      相关资源
      最近更新 更多