如何在ExoPlayer android中跳过部分视频
我想实现的功能,如跳过介绍,跳过我的视频播放器的信用。我使用的是Exoplayer,假设我有一个长度为00:15:21(hh:mm:ss)的视频,我知道视频的实际内容从00:00:18开始,到00:14:12结束。我想显示一个“跳过介绍”和“下一集”按钮,就像在NetFlix中一样。我怎样才能做到这一点 关于Github的Exoplayer页面的问题: 从中,您可以使用如何在ExoPlayer android中跳过部分视频,android,exoplayer,Android,Exoplayer,我想实现的功能,如跳过介绍,跳过我的视频播放器的信用。我使用的是Exoplayer,假设我有一个长度为00:15:21(hh:mm:ss)的视频,我知道视频的实际内容从00:00:18开始,到00:14:12结束。我想显示一个“跳过介绍”和“下一集”按钮,就像在NetFlix中一样。我怎样才能做到这一点 关于Github的Exoplayer页面的问题: 从中,您可以使用ClippingMediaSourceAPI来完成任务 ClippingMediaSource可用于剪辑媒体源,以便仅播放部分媒
ClippingMediaSource
API来完成任务
ClippingMediaSource可用于剪辑媒体源,以便仅播放部分媒体源
从00:00:18开始播放视频到结束(跳过简介)
从00:14:12开始播放视频到结束(下一集)
或者从00:00:18到00:14:12播放视频
MediaSource videoSource =
new ExtractorMediaSource.Factory(...).createMediaSource(videoUri);
// Clip to start at from 00:00:18 to 00:14:12.
ClippingMediaSource clippingSource =
new ClippingMediaSource(
videoSource,
/* startPositionUs= */ 18_000_000,
/* endPositionUs= */ 852_000_000);
您可以找到有关API的更多信息。好的,在ExoPlayer开发人员的帮助下,我找到了一个解决方案。详情见我在问题中添加的参考链接。总结如下: 如果我们知道跳过的持续时间,我们可以创建并向Exoplayer发送消息,在回调中,我们可以实现我们的业务逻辑,如使按钮可见、按钮的onClickListners等
private class PlayerEventListener extends Player.DefaultEventListener {
@Override
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
prepareSkipToNextEpisode();
if(reason == DISCONTINUITY_REASON_PERIOD_TRANSITION){ //when a video naturally ends it course and starts playing next video.
prepareSkipIntro();
}
}
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
String stateString;
switch (playbackState) {
case Player.STATE_IDLE: // The player does not have any media to play.
stateString = "Player.STATE_IDLE";
mProgressBar.setVisibility(View.VISIBLE);
playerView.setKeepScreenOn(false);
//mPlayerView.hideController();
mediaControlsLayout.setVisibility(View.GONE);
break;
case Player.STATE_BUFFERING: // The player needs to load media before playing.
stateString = "Player.STATE_BUFFERING";
mProgressBar.setVisibility(View.VISIBLE);
mediaControlsLayout.setVisibility(View.GONE);
playerView.setKeepScreenOn(true);
break;
case Player.STATE_READY: // The player is able to immediately play from its current position.
stateString = "Player.STATE_READY";
mProgressBar.setVisibility(View.GONE);
mediaControlsLayout.setVisibility(View.VISIBLE);
playerView.setKeepScreenOn(true);
prepareSkipToNextEpisode();
if((player.getContentPosition() < 5000)) {
prepareSkipIntro();
}
//prepareSkipToNextEpisode();
break;
case Player.STATE_ENDED: // The player has finished playing the media.
stateString = "Player.STATE_ENDED";
playerView.setKeepScreenOn(false);
break;
default:
stateString = "UNKNOWN_STATE";
break;
}
}
}
private void prepareSkipIntro(){
if(episodeStartTimes[player.getCurrentWindowIndex()] > 0) {
inttoBeginsHandler = new Handler();
long introDurationMs = 3 * 1000;
player.createMessage((messageType, payload) -> hideSkipIntro())
.setPosition(introDurationMs).setHandler(inttoBeginsHandler).send();
}
}
private void hideSkipIntro(){
if(player.getCurrentPosition()>2500) {
skipIntroBtn.setVisibility(View.VISIBLE);
skipIntroBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (player != null) {
player.seekTo(episodeStartTimes[player.getCurrentWindowIndex()]);
prepareSkipToNextEpisode();
skipIntroBtn.setVisibility(View.GONE);
}
}
});
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
skipIntroBtn.setVisibility(View.GONE);
}
}, 5000);
}
}
private void prepareSkipToNextEpisode(){
if(episodeEndTimes[player.getCurrentWindowIndex()] > 0) {
if (player.getCurrentPosition() < 1000) {
remainingTime = episodeDummyEndtimes[player.getCurrentWindowIndex()];
} else {
remainingTime = episodeDummyEndtimes[player.getCurrentWindowIndex()] - player.getCurrentPosition();
}
creditsBeginssHandler = null;
creditsBeginssHandler = new Handler();
player.createMessage((messageType, payload) -> endEpisode())
.setPosition(remainingTime).setHandler(creditsBeginssHandler).send();
}
}
private void endEpisode(){
if(player.getCurrentPosition()>= episodeDummyEndtimes[player.getCurrentWindowIndex()]) {
if (player.getCurrentWindowIndex() < (episodeEndTimes.length-1)) { // no need of skip credits for the final episode
skipCreditsBtn.setVisibility(View.VISIBLE);
skipCreditsBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
player.seekTo(player.getNextWindowIndex(), 0);
skipCreditsBtn.setVisibility(View.GONE);
}
});
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
skipCreditsBtn.setVisibility(View.GONE);
}
}, 5000);
}else{
skipCreditsBtn.setVisibility(View.GONE);
}
}
}
私有类PlayerEventListener扩展了Player.DefaultEventListener{
@凌驾
位置不连续的公共无效(@Player.intercontinuctyreason int-reason){
制备kiptonexteposide();
如果(原因==不连续性\u原因\u周期\u过渡){//当一个视频自然结束它的过程并开始播放下一个视频时。
制备kipintro();
}
}
}
@凌驾
公共无效onTracksChanged(TrackGroupArray轨迹组、TrackSelectionArray轨迹选择){
super.onTracksChanged(轨迹组、轨迹选择);
}
@凌驾
PlayerStateChanged上的公共无效(布尔playWhenReady,int playbackState){
字符串stateString;
交换机(播放后台状态){
case Player.STATE_IDLE://播放器没有任何媒体可播放。
stateString=“Player.STATE\u IDLE”;
mProgressBar.setVisibility(View.VISIBLE);
playerView.setKeepScreenOn(false);
//mPlayerView.hideControl();
mediaControlsLayout.setVisibility(View.GONE);
打破
case Player.STATE_BUFFERING://播放器需要在播放前加载媒体。
stateString=“Player.STATE\u BUFFERING”;
mProgressBar.setVisibility(View.VISIBLE);
mediaControlsLayout.setVisibility(View.GONE);
playerView.setKeepScreenOn(真);
打破
case Player.STATE_READY://玩家可以立即从当前位置开始游戏。
stateString=“Player.STATE\u READY”;
mProgressBar.setVisibility(View.GONE);
mediaControlsLayout.setVisibility(View.VISIBLE);
playerView.setKeepScreenOn(真);
制备kiptonexteposide();
if((player.getContentPosition()<5000)){
制备kipintro();
}
//制备kiptonexteposide();
打破
case Player.STATE_end://播放机已完成媒体播放。
stateString=“Player.STATE\u已结束”;
playerView.setKeepScreenOn(false);
打破
违约:
stateString=“未知状态”;
打破
}
}
}
私人作废准备Kipintro(){
如果(EpiodeStartTimes[player.getCurrentWindowIndex()]>0){
intToBeginHandler=新处理程序();
长引子MS=3*1000;
createMessage((messageType,payload)->hideSkipIntro())
.setPosition(introductionMS).setHandler(intToBeginHandler).send();
}
}
私有void hideSkipIntro(){
如果(player.getCurrentPosition()>2500){
skipIntroBtn.setVisibility(View.VISIBLE);
skipIntroBtn.setOnClickListener(新视图.OnClickListener()中){
@凌驾
公共void onClick(视图v){
如果(玩家!=null){
seekTo(eposodestarttimes[player.getCurrentWindowIndex()]);
制备kiptonexteposide();
skipIntroBtn.setVisibility(View.GONE);
}
}
});
最终处理程序=新处理程序();
handler.postDelayed(新的Runnable(){
@凌驾
公开募捐{
skipIntroBtn.setVisibility(View.GONE);
}
}, 5000);
}
}
私有无效制备kiptonextepisode(){
if(eposodeEndTimes[player.getCurrentWindowIndex()]>0){
如果(player.getCurrentPosition()<1000){
remainingTime=eposodedummeyendtimes[player.getCurrentWindowIndex()];
}否则{
remainingTime=eposodedummeyendtimes[player.getCurrentWindowIndex()]-player.getCurrentPosition();
}
creditsBeginssHandler=null;
creditsBeginssHandler=新处理程序();
createMessage((messageType,payload)->endEpisode())
.setPosition(remainingTime).setHandler(creditsBeginssHandler.send();
}
}
私有void endEpisode(){
如果(player.getCurrentPosition()>=eposodedMyEndTimes[player.getCurrentWindowIndex()){
如果(player.getCurrentWindowIndex()<(eposodeEndTimes.length-1)){//
MediaSource videoSource =
new ExtractorMediaSource.Factory(...).createMediaSource(videoUri);
// Clip to start at from 00:00:18 to 00:14:12.
ClippingMediaSource clippingSource =
new ClippingMediaSource(
videoSource,
/* startPositionUs= */ 18_000_000,
/* endPositionUs= */ 852_000_000);
private class PlayerEventListener extends Player.DefaultEventListener {
@Override
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
prepareSkipToNextEpisode();
if(reason == DISCONTINUITY_REASON_PERIOD_TRANSITION){ //when a video naturally ends it course and starts playing next video.
prepareSkipIntro();
}
}
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
String stateString;
switch (playbackState) {
case Player.STATE_IDLE: // The player does not have any media to play.
stateString = "Player.STATE_IDLE";
mProgressBar.setVisibility(View.VISIBLE);
playerView.setKeepScreenOn(false);
//mPlayerView.hideController();
mediaControlsLayout.setVisibility(View.GONE);
break;
case Player.STATE_BUFFERING: // The player needs to load media before playing.
stateString = "Player.STATE_BUFFERING";
mProgressBar.setVisibility(View.VISIBLE);
mediaControlsLayout.setVisibility(View.GONE);
playerView.setKeepScreenOn(true);
break;
case Player.STATE_READY: // The player is able to immediately play from its current position.
stateString = "Player.STATE_READY";
mProgressBar.setVisibility(View.GONE);
mediaControlsLayout.setVisibility(View.VISIBLE);
playerView.setKeepScreenOn(true);
prepareSkipToNextEpisode();
if((player.getContentPosition() < 5000)) {
prepareSkipIntro();
}
//prepareSkipToNextEpisode();
break;
case Player.STATE_ENDED: // The player has finished playing the media.
stateString = "Player.STATE_ENDED";
playerView.setKeepScreenOn(false);
break;
default:
stateString = "UNKNOWN_STATE";
break;
}
}
}
private void prepareSkipIntro(){
if(episodeStartTimes[player.getCurrentWindowIndex()] > 0) {
inttoBeginsHandler = new Handler();
long introDurationMs = 3 * 1000;
player.createMessage((messageType, payload) -> hideSkipIntro())
.setPosition(introDurationMs).setHandler(inttoBeginsHandler).send();
}
}
private void hideSkipIntro(){
if(player.getCurrentPosition()>2500) {
skipIntroBtn.setVisibility(View.VISIBLE);
skipIntroBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (player != null) {
player.seekTo(episodeStartTimes[player.getCurrentWindowIndex()]);
prepareSkipToNextEpisode();
skipIntroBtn.setVisibility(View.GONE);
}
}
});
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
skipIntroBtn.setVisibility(View.GONE);
}
}, 5000);
}
}
private void prepareSkipToNextEpisode(){
if(episodeEndTimes[player.getCurrentWindowIndex()] > 0) {
if (player.getCurrentPosition() < 1000) {
remainingTime = episodeDummyEndtimes[player.getCurrentWindowIndex()];
} else {
remainingTime = episodeDummyEndtimes[player.getCurrentWindowIndex()] - player.getCurrentPosition();
}
creditsBeginssHandler = null;
creditsBeginssHandler = new Handler();
player.createMessage((messageType, payload) -> endEpisode())
.setPosition(remainingTime).setHandler(creditsBeginssHandler).send();
}
}
private void endEpisode(){
if(player.getCurrentPosition()>= episodeDummyEndtimes[player.getCurrentWindowIndex()]) {
if (player.getCurrentWindowIndex() < (episodeEndTimes.length-1)) { // no need of skip credits for the final episode
skipCreditsBtn.setVisibility(View.VISIBLE);
skipCreditsBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
player.seekTo(player.getNextWindowIndex(), 0);
skipCreditsBtn.setVisibility(View.GONE);
}
});
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
skipCreditsBtn.setVisibility(View.GONE);
}
}, 5000);
}else{
skipCreditsBtn.setVisibility(View.GONE);
}
}
}
DefaultHttpDataSourceFactory dataSourceFactory = getSettedHeadersDataFactory();
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(qualities.get(currentQuality).getQualityUrl()));
ClippingMediaSource clippingSource =
new ClippingMediaSource(
hlsMediaSource,
/* startPositionUs= */ 13_000_000,
/* endPositionUs= */ C.TIME_END_OF_SOURCE);
player.prepare(clippingSource);