【问题标题】:Android VideoView MediaPlayer OnInfoListener - events not firedAndroid VideoView MediaPlayer OnInfoListener - 未触发事件
【发布时间】:2012-10-14 13:46:33
【问题描述】:

给出以下源代码sn-p:

videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {

            mediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                @Override
                public boolean onInfo(MediaPlayer mp, int what, int extra) {
                    if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END){
                        activity.dismissDialog(DialogID.DIALOG_LOADING);
                        return true;
                    } 
                    return false;
                }
            });
        }
    });

我正在使用 Android 3.x+ 设备流式传输 HLS 流,并在缓冲完成后尝试隐藏加载对话框。 视频流有效,但永远不会触发信息事件。

有什么想法吗?

【问题讨论】:

  • 谁能为此提供一个好的解决方案?
  • 我只是想知道在onPrepared(...) 中设置OnInfoListener 在调用链中是否为时已晚。 prepareAsync() 上的文档说明如下:"(...) 对于流,您应该调用 prepareAsync(),它会立即返回,而不是阻塞直到缓冲足够的数据。 " 这听起来好像onPrepared(...) 在缓冲区被填满之前不会被击中。您已经尝试过反射的任何更改吗?这应该允许您随时设置OnInfoListener

标签: android video-streaming android-mediaplayer


【解决方案1】:

我知道为时已晚,但将其发布给仍在寻求解决方案的用户(这对我有用):

        progressDialog.show();
        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                mediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra) {
                        if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END){
                            progressDialog.dismiss();
                            return true;
                        } else if(what == MediaPlayer.MEDIA_INFO_BUFFERING_START){
                            progressDialog.show();
                        }
                        return false;
                    }
                });
                progressDialog.dismiss();
                videoView.start();
            }
        });

【讨论】:

  • setOnInfoListener 在视频开始后被触发。然后我们可以在视频的中间缓冲期间使用它来显示和隐藏进度条。
  • 在我的情况下仍然没有被解雇
【解决方案2】:

你是对的,事件永远不会被触发。这是一个已知的 HLS 错误,我认为 Google 不会修复。

这适用于 onInfo 和缓冲事件。

https://code.google.com/p/android/issues/detail?id=42767https://code.google.com/p/googletv-issues/issues/detail?id=2

对不起!

【讨论】:

    【解决方案3】:

    不完全确定 OP 的要求,但这里有一些非常不合时宜的信息。

    我不会依赖 onPrepared。我觉得不靠谱。

    我发现通过 MediaPlayer 进行 HLS 流式传输的两个最有用的信息是视频的持续时间和视频的进度位置。您可以通过收听进度更新来获得这两者。

    当持续时间大于零时,您就知道视频已真正准备好并且可以进行处理(擦洗)。当进度位置发生变化时,您就知道视频已完成缓冲并开始播放。当然,最后一项仅在视频播放时才有效。 MediaPlayer 倾向于传递不准确的信息。

    这些信息大多是准确的,通常可以依靠“相当”及时。这种及时性因设备而异。

    【讨论】:

      【解决方案4】:

      onPreparedMediaPlayer 准备开始缓冲时调用,而不是在视频完全缓冲时调用。但是,在 onPrepared 方法中关闭加载对话框是完全自然的。

      还使用MEDIA_INFO_BUFFERING_ENDMediaPlayer 在填充缓冲区后恢复播放,所以我认为它不应该用来关闭对话框。所以这应该有效:

      videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
          @Override
          public void onPrepared(MediaPlayer mediaPlayer) {
              activity.dismissDialog(DialogID.DIALOG_LOADING);
          }
      });
      

      【讨论】:

      • 这是我已经尝试过的。我正在尝试解决可能由于初始缓冲区、由于网络条件差而导致的重新缓冲或由于搜索导致的重新缓冲而导致的缓冲区欠载。您的方法不适用于任何这些情况。
      【解决方案5】:

      您可以在 videoView 上设置 OnPreparedListener,因为它是您的对象,但如果您检查 VideoView 的来源,您会发现 mMediaPlayer 是它的私有成员,因此您从外部所做的任何更改都不会应用到它。

      根据您的要求,您需要缓冲状态,以便您可以拥有线程或处理程序或其他东西,以便您可以更新 UI 以获取缓冲状态,有一种方法

      int percent = videoView.getBufferPercentage();
      
      if(percent == 100){
      // buffering done 
      } 
      

      【讨论】:

      • 阅读赏金说明,这不是他想要的:“我不想要一个解决方案 * 轮询查看播放头以检查进度 * 使用onBufferUpdate 估计(根据 SO 上的旧帖子,这是不准确的。”
      • 请检查我在第一段中所说的内容
      • @yorkw 是对的。如果您查看视频视图的 AOSP 源,getBufferPercentage 返回与 onBufferUpdate(percent) 相同的值。 onBufferUpdate 告诉您相对于整个视频缓冲了多少内容。例如 80% 意味着 80% 的视频已被缓冲
      【解决方案6】:

      您无需通过 setOnInfoListener

      通过重写 setOnPreparedListener 方法就足够了。就像在 api 节目中一样

      public void setOnPreparedListener (MediaPlayer.OnPreparedListener l)

      注册一个回调函数,在加载媒体文件时调用 准备好了。

      所以,你可以在 setOnPreparedListener 方法中关闭你的对话框就足够了

      喜欢这个

          vv.setOnPreparedListener(new OnPreparedListener() {
          @Override
          public void onPrepared(MediaPlayer mp) {
      
                  handler.post(new Runnable() {
                  @Override
              public void run() {
                      Toast.makeText(MainActivity.this, "finish11", Toast.LENGTH_LONG).show();
              }
              });
              }
          });
      

      【讨论】:

      • 我的结果和他的结果有什么不同?此外,缓冲区完成时加载。我从 Android API 复制了它。在这里查看developer.android.com/reference/android/widget/…
      • 让我重申我给@Cristian 的答案。这是我已经尝试过的。我正在尝试解决可能由于初始缓冲区、由于网络条件差而导致的重新缓冲或由于搜索导致的重新缓冲而导致的缓冲区欠载。您的方法不适用于任何这些情况。
      【解决方案7】:

      如果您想在每次缓冲时显示加载(初始时间或后续缓冲区欠载),只需确保再次显示:

      // at the beginning
      show
      
      boolean onInfo(int what, int extra) {
        switch (what) {
          case MEDIA_INFO_BUFFERING_END:
            "hide";
            break;
          case MEDIA_INFO_BUFFERING_START
            "show":
        }
      }
      

      所以这个事件序列将按照需要进行:

      - whenever you start (setVideoURI or start): show
      - onPrepared: just plug the info listener
      - onInfo BUFFERING_END   hide (it's playing)
      - onInfo BUFFERING_START show (it's buffering again)
      - onInfo BUFFERING_END   hide (it's playing)
      

      更新:

      这是假设信息事件有效。当然。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-20
        • 2012-06-26
        • 2019-05-09
        • 1970-01-01
        • 2014-09-23
        • 2016-07-30
        • 1970-01-01
        相关资源
        最近更新 更多