Skip to content

Commit

Permalink
优化ExoPlayer
Browse files Browse the repository at this point in the history
  • Loading branch information
Doikki committed May 4, 2018
1 parent 4851a85 commit 22d5e96
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 1,088 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public class SwitchPlayerActivity extends AppCompatActivity implements View.OnCl

private IjkVideoView ijkVideoView;
private StandardVideoController mController;
private static final String URL = "http://gslb.miaopai.com/stream/FQXM04zrW1dcXGiPdJ6Q3KAq2Fpv4TLV.mp4";
// private static final String URL = "http://vfile.hshan.com/2018/1524/9156/4430/152491564430.ssm/152491564430.m3u8";
// private static final String URL = "http://gslb.miaopai.com/stream/FQXM04zrW1dcXGiPdJ6Q3KAq2Fpv4TLV.mp4";
private static final String URL = "http://vfile.hshan.com/2018/1524/9156/4430/152491564430.ssm/152491564430.m3u8";
// private static final String URL = "rtmp://live.hkstv.hk.lxdns.com/live/hks";

@Override
Expand Down
241 changes: 84 additions & 157 deletions app/src/main/java/com/dueeeke/dkplayer/player/ExoMediaPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,22 @@

import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.view.Surface;
import android.view.SurfaceHolder;

import com.dueeeke.dkplayer.util.Repeater;
import com.dueeeke.videoplayer.player.AbstractPlayer;
import com.dueeeke.videoplayer.util.L;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
Expand All @@ -30,7 +26,6 @@
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
Expand All @@ -40,120 +35,91 @@

import tv.danmaku.ijk.media.player.IMediaPlayer;

public class ExoMediaPlayer extends AbstractPlayer implements Player.EventListener,
VideoRendererEventListener {
public class ExoMediaPlayer extends AbstractPlayer implements VideoRendererEventListener {

private static final int BUFFER_REPEAT_DELAY = 1_000;

private Context mAppContext;
private SimpleExoPlayer mInternalPlayer;
private MediaSource mMediaSource;
private String mDataSource;
private Surface mSurface;
private Handler mainHandler;
private PlaybackParameters mSpeedPlaybackParameters;
private int lastReportedPlaybackState;
private boolean lastReportedPlayWhenReady;
private boolean mIsPrepareing = true;
private boolean mIsBuffering = false;
private DataSource.Factory mediaDataSourceFactory;
@NonNull
private Repeater bufferRepeater = new Repeater();

private static final int TYPE_RTMP = 4;

public ExoMediaPlayer(Context context) {
mAppContext = context.getApplicationContext();
Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper();
mainHandler = new Handler(eventLooper);
lastReportedPlaybackState = Player.STATE_IDLE;
bufferRepeater.setRepeaterDelay(BUFFER_REPEAT_DELAY);
bufferRepeater.setRepeatListener(new BufferRepeatListener());
}

@Override
public void start() {
if (mInternalPlayer == null)
return;
mInternalPlayer.setPlayWhenReady(true);
mediaDataSourceFactory = getDataSourceFactory(true);
}

@Override
public void initPlayer() {
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(new DefaultBandwidthMeter());
DefaultTrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

// mEventLogger = new EventLogger(mTrackSelector);

// boolean preferExtensionDecoders = true;
// boolean useExtensionRenderers = true;//是否开启扩展
@DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode = DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER;

DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(mAppContext, null, extensionRendererMode);
DefaultLoadControl loadControl = new DefaultLoadControl();
mInternalPlayer = new SimpleExoPlayer(renderersFactory, trackSelector, loadControl);
mInternalPlayer.addListener(this);
mInternalPlayer.setVideoDebugListener(this);
mInternalPlayer = ExoPlayerFactory.newSimpleInstance(mAppContext, trackSelector);
mInternalPlayer.addListener(mDefaultEventListener);
mInternalPlayer.addVideoDebugListener(this);
}

@Override
public void setDataSource(String path) {
mDataSource = Uri.parse(path).toString();
mDataSource = path;
mMediaSource = getMediaSource();
}

private MediaSource getMediaSource() {
Uri contentUri = Uri.parse(mDataSource);
int contentType = inferContentType(mDataSource);
int contentType = Util.inferContentType(mDataSource);
switch (contentType) {
case C.TYPE_DASH:
return new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(getDataSourceFactory(false)),
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
getDataSourceFactory(false))
.createMediaSource(contentUri, mainHandler, null);
.createMediaSource(contentUri);
case C.TYPE_SS:
return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(getDataSourceFactory(false)),
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
getDataSourceFactory(false))
.createMediaSource(contentUri, mainHandler, null);
.createMediaSource(contentUri);
case C.TYPE_HLS:
return new HlsMediaSource.Factory(getDataSourceFactory(false))
.createMediaSource(contentUri, mainHandler, null);
return new HlsMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(contentUri);
// case TYPE_RTMP:
// RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory(null);
// return new ExtractorMediaSource.Factory(rtmpDataSourceFactory)
// .createMediaSource(contentUri, mainHandler, null);
default:
case C.TYPE_OTHER:
return new ExtractorMediaSource.Factory(getDataSourceFactory(false))
.createMediaSource(contentUri, mainHandler, null);
return new ExtractorMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(contentUri);
}
}

/**
* Makes a best guess to infer the type from a file name.
*
* @param fileName Name of the file. It can include the path of the file.
* @return The content type.
*/
@C.ContentType
private int inferContentType(String fileName) {
fileName = Util.toLowerInvariant(fileName);
if (fileName.startsWith("rtmp:")) {
return TYPE_RTMP;
} else {
return Util.inferContentType(fileName);
}
}

private DataSource.Factory getHttpDataSourceFactory(boolean preview) {
private DataSource.Factory getHttpDataSourceFactory(boolean useBandwidthMeter) {
return new DefaultHttpDataSourceFactory(Util.getUserAgent(mAppContext,
mAppContext.getApplicationInfo().name), preview ? null : new DefaultBandwidthMeter());
mAppContext.getApplicationInfo().name), useBandwidthMeter ? null : new DefaultBandwidthMeter());
}

private DataSource.Factory getDataSourceFactory(boolean useBandwidthMeter) {
return new DefaultDataSourceFactory(mAppContext, useBandwidthMeter ? null : new DefaultBandwidthMeter(),
getHttpDataSourceFactory(useBandwidthMeter));
}

private DataSource.Factory getDataSourceFactory(boolean preview) {
return new DefaultDataSourceFactory(mAppContext, preview ? null : new DefaultBandwidthMeter(),
getHttpDataSourceFactory(preview));
@Override
public void start() {
if (mInternalPlayer == null)
return;
mInternalPlayer.setPlayWhenReady(true);
}

@Override
Expand Down Expand Up @@ -215,7 +181,8 @@ public void seekTo(long time) {
public void release() {
if (mInternalPlayer != null) {
mInternalPlayer.release();
mInternalPlayer.removeListener(this);
mInternalPlayer.removeListener(mDefaultEventListener);
mInternalPlayer.removeVideoDebugListener(this);
mInternalPlayer = null;
}

Expand Down Expand Up @@ -314,125 +281,84 @@ private int getBufferedPercentage() {
return mInternalPlayer == null ? 0 : mInternalPlayer.getBufferedPercentage();
}

@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {

}

@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

}

@Override
public void onLoadingChanged(boolean isLoading) {

}
private Player.DefaultEventListener mDefaultEventListener = new Player.DefaultEventListener() {
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
super.onPlayerStateChanged(playWhenReady, playbackState);
//重新播放状态顺序为:STATE_IDLE -》STATE_BUFFERING -》STATE_READY
//缓冲时顺序为:STATE_BUFFERING -》STATE_READY
// L.e("onPlayerStateChanged: playWhenReady = " + playWhenReady + ", playbackState = " + playbackState);
if (lastReportedPlayWhenReady != playWhenReady || lastReportedPlaybackState != playbackState) {
if (mIsBuffering) {
switch (playbackState) {
case Player.STATE_ENDED:
case Player.STATE_READY:
if (mPlayerEventListener != null) {
mPlayerEventListener.onInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_END, mInternalPlayer.getBufferedPercentage());
}
mIsBuffering = false;
break;
}
}

@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (mIsPrepareing) {
switch (playbackState) {
case Player.STATE_READY:
if (mPlayerEventListener != null) {
mPlayerEventListener.onPrepared();
setBufferRepeaterStarted(true);
}
mIsPrepareing = false;
break;
}
}

//重新播放状态顺序为:STATE_IDLE -》STATE_BUFFERING -》STATE_READY
//缓冲时顺序为:STATE_BUFFERING -》STATE_READY
L.e("onPlayerStateChanged: playWhenReady = " + playWhenReady + ", playbackState = " + playbackState);
if (lastReportedPlayWhenReady != playWhenReady || lastReportedPlaybackState != playbackState) {
if (mIsBuffering) {
switch (playbackState) {
case Player.STATE_ENDED:
case Player.STATE_READY:
case Player.STATE_BUFFERING:
if (mPlayerEventListener != null) {
mPlayerEventListener.onInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_END, mInternalPlayer.getBufferedPercentage());
mPlayerEventListener.onInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_START, mInternalPlayer.getBufferedPercentage());
}
mIsBuffering = false;
mIsBuffering = true;
break;
}
}

if (mIsPrepareing) {
switch (playbackState) {
case Player.STATE_READY:
break;
case Player.STATE_ENDED:
if (mPlayerEventListener != null) {
mPlayerEventListener.onPrepared();
mPlayerEventListener.onInfo(IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START, 0);
mPlayerEventListener.onCompletion();
}
setBufferRepeaterStarted(true);
mIsPrepareing = false;
break;
default:
break;
}
}

switch (playbackState) {
case Player.STATE_BUFFERING:
if (mPlayerEventListener != null) {
mPlayerEventListener.onInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_START, mInternalPlayer.getBufferedPercentage());
}
mIsBuffering = true;
break;
case Player.STATE_READY:
break;
case Player.STATE_ENDED:
if (mPlayerEventListener != null) {
mPlayerEventListener.onCompletion();
}
break;
default:
break;
}
lastReportedPlayWhenReady = playWhenReady;
lastReportedPlaybackState = playbackState;
}
lastReportedPlayWhenReady = playWhenReady;
lastReportedPlaybackState = playbackState;
}

@Override
public void onRepeatModeChanged(int repeatMode) {

}

@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

}

@Override
public void onPlayerError(ExoPlaybackException error) {
if (mPlayerEventListener != null) {
mPlayerEventListener.onError();
@Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
if (mPlayerEventListener != null) {
mPlayerEventListener.onError();
}
}
}

@Override
public void onPositionDiscontinuity(int reason) {

}

@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

}

@Override
public void onSeekProcessed() {

}
};

//------------------ Start VideoRendererEventListener ---------------------//
@Override
public void onVideoEnabled(DecoderCounters counters) {

}

@Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {

}

@Override
public void onVideoInputFormatChanged(Format format) {

}

@Override
public void onDroppedFrames(int count, long elapsedMs) {

}

@Override
Expand All @@ -447,11 +373,12 @@ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegre

@Override
public void onRenderedFirstFrame(Surface surface) {

if (mPlayerEventListener != null && mIsPrepareing)
mPlayerEventListener.onInfo(IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START, 0);
}

@Override
public void onVideoDisabled(DecoderCounters counters) {

}
//------------------ End VideoRendererEventListener ---------------------//
}
Loading

0 comments on commit 22d5e96

Please sign in to comment.