【问题标题】:How to implement oncompletionlistener to detect end of media file in Exoplayer如何实现 oncompletionlistener 来检测 Exoplayer 中媒体文件的结尾
【发布时间】:2015-02-05 17:48:26
【问题描述】:

我正在尝试一个接一个地以播放列表的形式播放视频。我正在使用 android Exoplayer 播放我的文件,但 mediaplayer 中没有侦听器来收听媒体文件的结尾。有没有办法使用 exoplayer 收听媒体文件的结尾。

【问题讨论】:

    标签: android exoplayer


    【解决方案1】:

    我知道这是旧的,但只是为了扩展已接受的答案:

    exoPlayer.addListener(this);
    
    .....
    
    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int state) {
    
        if (state == ExoPlayer.STATE_ENDED){
            //player back ended
        }
    }
    

    【讨论】:

    • onPositionDiscontinuity() 在我的情况下被调用然后如何处理?
    【解决方案2】:

    Exoplayer 提供媒体播放器不提供的高级实现。

    在 Android 的 Exoplayer 的高级示例中,在 FullPlayerActivity.java 中,他们实现了 onStateChanged,它提供了 STATE_ENDED

    您可以在 RELATED SAMPLES

    项下从this page 右侧部分下载示例

    【讨论】:

    • 他们已经更新了sdk和samples,稍微搜索一下就会有结果。顺便说一句,我已经更新了断开的链接。
    • 小细节是onPlayerStateChanged。可能他们更新了它。
    • MediaSource 为 LoopingMediaSource 时,不会触发 STATE_ENDED 事件。
    【解决方案3】:

    Google 已弃用 ExoPlayer.STATE_ENDED 并已替换为 Player.STATE_ENDED

    由于这篇文章已经有一段时间了,我将在下面写一个Kotlin版本的监听器。

    this.simpleExoPlayer?.addListener(object : Player.DefaultEventListener() {
        override fun onPlayerStateChanged(playWhenReady: Boolean,playbackState: Int) {
            when (playbackState) {
                Player.STATE_IDLE -> {}
                Player.STATE_BUFFERING -> {}
                Player.STATE_READY -> {}
                Player.STATE_ENDED -> {}
            }
        }
    })
    

    更新:05-2020 由于DefaultEventListeneronPlayerStateChanged() 已被弃用。

    player.addListener(object : Player.EventListener {
         override fun onPlaybackStateChanged(state: Int) {
               if (state == Player.STATE_ENDED) {
                  // your code
               }
         }
    })
    

    【讨论】:

    • DefaultEventListener() 已弃用,而是使用 this.player?.addListener(object :Player.EventListener{ override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) { when (playbackState) { Player.STATE_IDLE - > { progressBar.visibility=View.VISIBLE} Player.STATE_BUFFERING -> { progressBar.visibility=View.VISIBLE } Player.STATE_READY -> { progressBar.visibility=View.GONE} Player.STATE_ENDED -> { progressBar.visibility=View.离开} } } })
    • 好像EventListener现在也被弃用了,现在似乎只需要Player.Listener
    【解决方案4】:

    您可以这样做:

    playerExo.addListener(new ExoPlayer.Listener() {
    
                @Override
                public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
    
                    switch(playbackState) {
                        case ExoPlayer.STATE_BUFFERING:
                            break;
                        case ExoPlayer.STATE_ENDED:
                            //do what you want
                            break;
                        case ExoPlayer.STATE_IDLE:
                            break;
                        case ExoPlayer.STATE_PREPARING:
                            break;
                        case ExoPlayer.STATE_READY:
                            break;
                        default:
                            break;
                    }
                }
    
                @Override
                public void onPlayWhenReadyCommitted() {
    
                }
    
                @Override
                public void onPlayerError(ExoPlaybackException error) {
    
                }
            });
            playerExo.seekTo(0);
            playerExo.setPlayWhenReady(true);
    

    但是@Murtaza Khursheed Hussain 的回答是正确的!有一个愉快的代码日!如果您还需要其他东西,请告诉我!

    【讨论】:

    • STATE_ENDED 被调用两次
    • 检查是否播放视频或不使用 player.getPlayWhenReady()
    • 您可以使用Player.DefaultEventListener(),其中所有接口方法都被存根。因此,您可以删除不需要的方法,例如 onPlayWhenReadyCommittedonPlayWhenReadyCommitted
    【解决方案5】:

    您必须实现接口 Player.EventLister 并添加到您的 exoPlayer。

    只需在 onPlayerStateChanged 方法上编写代码即可。查看代码。

    exoPlayer.addListener( new Player.EventListener() {
                @Override
                public void onTimelineChanged(Timeline timeline, @Nullable Object manifest, int reason) {
    
                }
    
                @Override
                public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
    
                }
    
                @Override
                public void onLoadingChanged(boolean isLoading) {
    
                }
    
                @Override
                public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
    
                    switch(playbackState) {
                        case Player.STATE_BUFFERING:
                            break;
                        case Player.STATE_ENDED:
                            //Here you do what you want
                            break;
                        case Player.STATE_IDLE:
                            break;
                        case Player.STATE_READY:
                            break;
                        default:
                            break;
                    }
                }
    
                @Override
                public void onRepeatModeChanged(int repeatMode) {
    
                }
    
                @Override
                public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
    
                }
    
                @Override
                public void onPlayerError(ExoPlaybackException error) {
    
                }
    
                @Override
                public void onPositionDiscontinuity(int reason) {
    
                }
    
                @Override
                public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
    
                }
    
                @Override
                public void onSeekProcessed() {
    
                }
    
    
            });
    

    【讨论】:

      【解决方案6】:

      对于未连接的 MediaSource(代表您要播放的任何单个媒体),当该媒体完成播放时,您将收到 STATE_ENDED

      对于 ConcatenatingMediaSource,它会在整个串联播放完毕时发生(即您已经播放到串联中最后一个项目的末尾)。因此,当整个 MediaSource 播放完毕时会发生 STATE_ENDED。

      对于 ConcatenatingMediaSource,检测当前媒体结束和下一个媒体播放开始的最佳回调是“onPositionDiscontinuity” 您应该使用 onPositionDiscontinuity() 来确定何时发生转换。请注意,在其他一些情况下也会调用 onPositionDiscontinuity,但您可以调用 getCurrentWindowIndex() 并将其与您认为您所在的窗口进行比较以确定是否发生了转换。您可以执行以下操作:

      public void onPositionDiscontinuity() {
        int newIndex = player.getCurrentWindowIndex();
        if (newIndex != currentIndex) {
          // The index has changed ==> last media has ended and next media playback is started.
          currentIndex = newIndex;
        }
      }
      

      请注意: onPositionDiscontinuity() 不会为播放列表中的第一项调用,除非我们明确调用 player.seekTo(position,0)。因此,要处理您为播放列表中的所有媒体播放所做的任何事情,您必须单独处理播放列表中的第一项。

      【讨论】:

      • onPositionDiscontinuity() 在轨道改变时被调用,但是如果我想在它改变之前做一些事情呢?
      • 嗨@SamChen, onPositionDiscontinuity 显然是在“下一个视频”的第一帧已经渲染之后调度的。但我认为在“下一个视频”的第一帧被渲染之前,没有任何可用的事件可以触发。但是您可以在视频渲染器中添加一个 VideoFrameMetadataListener,该渲染器在每次将要释放一帧时调用渲染线程上的方法link
      • @SamChen 找到了一个可能有帮助的讨论 [链接] (github.com/google/ExoPlayer/issues/6576)
      • 谢谢,但我的意思不是“下一个视频”,是当前视频的结尾。我还为此创建了帖子:stackoverflow.com/questions/66889341/….
      • @SamChen,我发布了一些选项,您可以在帖子中尝试。我希望这会有所帮助。祝你好运!!
      【解决方案7】:

      Google 已弃用 ExoPlayer.STATE_ENDED。请改用 Player.STATE_ENDED。请参阅下面的代码。

      player.addListener(new Player.EventListener() {
          @Override
          public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
      
      
          }
      
          @Override
          public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
      
          }
      
          @Override
          public void onLoadingChanged(boolean isLoading) {
      
          }
      
          @Override
          public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
      
              if (playWhenReady && playbackState == Player.STATE_READY) {
                  // Active playback.
              } else if (playbackState == Player.STATE_ENDED) {
                  //The player finished playing all media
      
                 //Add your code here
      
              } else if (playWhenReady) {
                  // Not playing because playback ended, the player is buffering, stopped or
                  // failed. Check playbackState and player.getPlaybackError for details.
              } else {
                  // Paused by app.
              }
      
          }
      
          @Override
          public void onRepeatModeChanged(int repeatMode) {
      
          }
      
          @Override
          public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
      
          }
      
          @Override
          public void onPlayerError(ExoPlaybackException error) {
      
          }
      
          @Override
          public void onPositionDiscontinuity(int reason) {
              //THIS METHOD GETS CALLED FOR EVERY NEW SOURCE THAT IS PLAYED
            //  int latestWindowIndex = player.getCurrentWindowIndex();
      
      
          }
      
          @Override
          public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
      
          }
      
          @Override
          public void onSeekProcessed() {
      
          }
      });
      

      您可以查看ExoPlayer Developer page了解更多信息。

      【讨论】:

        【解决方案8】:

        ExoPlayer.STATE_ENDED 已贬值。请改用 Player.STATE_ENDED。 示例:

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            if(playbackState == Player.STATE_ENDED){
                // your brain put here
            }
        }
        

        【讨论】:

          【解决方案9】:

          我正在使用带有 exoplayer 的播放列表,我想在媒体播放完成后停止播放。

          对我来说,Player.STATE_ENDED 在播放列表结束时被调用

          所以为了实现我的用例,我首先在 exoplayer 中设置了这个

           simpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
          

          因此,我没有使用 EventListener,而是使用了 AnalyticsListener,它提供了 onPositionDiscontinuity 来覆盖 eventTime 参数并添加一个简单的代码了解媒体是否已重新启动。

             @Override
             public void onPositionDiscontinuity(EventTime eventTime, int reason) {
                  if (eventTime.currentPlaybackPositionMs / 1000 < 1) {
                      exoPlayer.setPlayWhenReady(false);
                      tvReplay.setVisibility(View.VISIBLE);
                  }
              }
          

          希望这对您的用例有所帮助

          【讨论】:

          • onPositionDiscontinuity() 是在轨道改变之后还是在改变之前调用?因为您的公式currentPlaybackPositionMs / 1000 &lt; 1 看起来像是曲目的开头,应该是下一首曲目。
          • 因为我设置了REPEAT_MODE_ONE,轨道会循环回到它的初始状态。所以一开始的轨道是一样的
          • 我明白了,但是有没有办法让它在当前曲目的结尾暂停?
          • 在这种情况下,您可以将当前正在播放的媒体的时间戳存储在此函数“onPositionDiscontinuity”中。并重置并运行计数器,直到总媒体长度结束。将重复模式保持为 REPEAT_MODE_NONE。因此,每次轨道更改或被寻找时,都会调用 onPositionDiscontinuity 方法,并且您的计数器将被重置并运行到媒体结束。当它结束时,您可以暂停您的媒体。
          【解决方案10】:

          由于 DefaultEventListeneronPlayerStateChanged() 已被弃用。

          使用Player.EventListeneronPlaybackStateChanged()

          Kotlin 代码

           player!!.addListener(object : Player.EventListener {
                      override fun onPlaybackStateChanged(state: Int) {
                          if (state == Player.STATE_ENDED) {
                              // your code here
                          }
                      }
                  })
          

          【讨论】:

            【解决方案11】:

            使用这个

                  exoPlayer.addListener(new Player.EventListener() {
                        @Override
                        public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
            
                        }
            
                        @Override
                        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
            
                        }
            
                        @Override
                        public void onLoadingChanged(boolean isLoading) {
            
                        }
            
                        @Override
                        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                            if (playbackState == Player.STATE_ENDED) {
            
                              
                            }
                        }
            
                        @Override
                        public void onRepeatModeChanged(int repeatMode) {
            
                        }
            
                        @Override
                        public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
            
                        }
            
                        @Override
                        public void onPlayerError(ExoPlaybackException error) {
            
                        }
            
                        @Override
                        public void onPositionDiscontinuity(int reason) {
            
                        }
            
                        @Override
                        public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
            
                        }
            
                        @Override
                        public void onSeekProcessed() {
            
                        }
                    });
            

            【讨论】:

              猜你喜欢
              • 2013-07-12
              • 1970-01-01
              • 2021-01-07
              • 1970-01-01
              • 2020-08-02
              • 2017-02-04
              • 1970-01-01
              • 2010-09-07
              • 1970-01-01
              相关资源
              最近更新 更多