ExoMediaPlayer.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. package com.yc.kernel.impl.exo;
  2. import android.app.Application;
  3. import android.content.Context;
  4. import android.content.res.AssetFileDescriptor;
  5. import android.os.Handler;
  6. import android.view.Surface;
  7. import android.view.SurfaceHolder;
  8. import com.google.android.exoplayer2.DefaultLoadControl;
  9. import com.google.android.exoplayer2.DefaultRenderersFactory;
  10. import com.google.android.exoplayer2.ExoPlaybackException;
  11. import com.google.android.exoplayer2.LoadControl;
  12. import com.google.android.exoplayer2.PlaybackParameters;
  13. import com.google.android.exoplayer2.Player;
  14. import com.google.android.exoplayer2.RenderersFactory;
  15. import com.google.android.exoplayer2.SimpleExoPlayer;
  16. import com.google.android.exoplayer2.analytics.AnalyticsCollector;
  17. import com.google.android.exoplayer2.source.MediaSource;
  18. import com.google.android.exoplayer2.source.MediaSourceEventListener;
  19. import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
  20. import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
  21. import com.google.android.exoplayer2.trackselection.TrackSelector;
  22. import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
  23. import com.google.android.exoplayer2.util.Clock;
  24. import com.google.android.exoplayer2.util.EventLogger;
  25. import com.google.android.exoplayer2.util.Util;
  26. import com.google.android.exoplayer2.video.VideoListener;
  27. import com.yc.kernel.inter.AbstractVideoPlayer;
  28. import com.yc.kernel.utils.PlayerConstant;
  29. import com.yc.kernel.utils.VideoLogUtils;
  30. import java.util.Map;
  31. import static com.google.android.exoplayer2.ExoPlaybackException.TYPE_SOURCE;
  32. /**
  33. * <pre>
  34. * @author yangchong
  35. * blog : https://github.com/yangchong211
  36. * time : 2018/11/9
  37. * desc : exo视频播放器实现类
  38. * revise:
  39. * </pre>
  40. */
  41. public class ExoMediaPlayer extends AbstractVideoPlayer implements VideoListener, Player.EventListener {
  42. protected Context mAppContext;
  43. protected SimpleExoPlayer mInternalPlayer;
  44. protected MediaSource mMediaSource;
  45. protected ExoMediaSourceHelper mMediaSourceHelper;
  46. private PlaybackParameters mSpeedPlaybackParameters;
  47. private int mLastReportedPlaybackState = Player.STATE_IDLE;
  48. private boolean mLastReportedPlayWhenReady = false;
  49. private boolean mIsPreparing;
  50. private boolean mIsBuffering;
  51. private LoadControl mLoadControl;
  52. private RenderersFactory mRenderersFactory;
  53. private TrackSelector mTrackSelector;
  54. public ExoMediaPlayer(Context context) {
  55. if (context instanceof Application){
  56. mAppContext = context;
  57. } else {
  58. mAppContext = context.getApplicationContext();
  59. }
  60. mMediaSourceHelper = ExoMediaSourceHelper.getInstance(context);
  61. }
  62. @Override
  63. public void initPlayer() {
  64. //创建exo播放器
  65. mInternalPlayer = new SimpleExoPlayer.Builder(
  66. mAppContext,
  67. mRenderersFactory == null ? mRenderersFactory = new DefaultRenderersFactory(mAppContext) : mRenderersFactory,
  68. mTrackSelector == null ? mTrackSelector = new DefaultTrackSelector(mAppContext) : mTrackSelector,
  69. mLoadControl == null ? mLoadControl = new DefaultLoadControl() : mLoadControl,
  70. DefaultBandwidthMeter.getSingletonInstance(mAppContext),
  71. Util.getLooper(),
  72. new AnalyticsCollector(Clock.DEFAULT),
  73. /* useLazyPreparation= */ true,
  74. Clock.DEFAULT)
  75. .build();
  76. setOptions();
  77. //播放器日志
  78. if (VideoLogUtils.isIsLog() && mTrackSelector instanceof MappingTrackSelector) {
  79. mInternalPlayer.addAnalyticsListener(new EventLogger((MappingTrackSelector) mTrackSelector, "ExoPlayer"));
  80. }
  81. initListener();
  82. }
  83. /**
  84. * exo视频播放器监听listener
  85. */
  86. private void initListener() {
  87. mInternalPlayer.addListener(this);
  88. mInternalPlayer.addVideoListener(this);
  89. }
  90. public void setTrackSelector(TrackSelector trackSelector) {
  91. mTrackSelector = trackSelector;
  92. }
  93. public void setRenderersFactory(RenderersFactory renderersFactory) {
  94. mRenderersFactory = renderersFactory;
  95. }
  96. public void setLoadControl(LoadControl loadControl) {
  97. mLoadControl = loadControl;
  98. }
  99. /**
  100. * 设置播放地址
  101. *
  102. * @param path 播放地址
  103. * @param headers 播放地址请求头
  104. */
  105. @Override
  106. public void setDataSource(String path, Map<String, String> headers) {
  107. // 设置dataSource
  108. if(path==null || path.length()==0){
  109. if (mPlayerEventListener!=null){
  110. mPlayerEventListener.onInfo(PlayerConstant.MEDIA_INFO_URL_NULL, 0);
  111. }
  112. return;
  113. }
  114. mMediaSource = mMediaSourceHelper.getMediaSource(path, headers);
  115. }
  116. @Override
  117. public void setDataSource(AssetFileDescriptor fd) {
  118. //no support
  119. }
  120. /**
  121. * 准备开始播放(异步)
  122. */
  123. @Override
  124. public void prepareAsync() {
  125. if (mInternalPlayer == null){
  126. return;
  127. }
  128. if (mMediaSource == null){
  129. return;
  130. }
  131. if (mSpeedPlaybackParameters != null) {
  132. mInternalPlayer.setPlaybackParameters(mSpeedPlaybackParameters);
  133. }
  134. mIsPreparing = true;
  135. mMediaSource.addEventListener(new Handler(), mMediaSourceEventListener);
  136. //准备播放
  137. mInternalPlayer.prepare(mMediaSource);
  138. }
  139. /**
  140. * 播放
  141. */
  142. @Override
  143. public void start() {
  144. if (mInternalPlayer == null){
  145. return;
  146. }
  147. mInternalPlayer.setPlayWhenReady(true);
  148. }
  149. /**
  150. * 暂停
  151. */
  152. @Override
  153. public void pause() {
  154. if (mInternalPlayer == null){
  155. return;
  156. }
  157. mInternalPlayer.setPlayWhenReady(false);
  158. }
  159. /**
  160. * 停止
  161. */
  162. @Override
  163. public void stop() {
  164. if (mInternalPlayer == null){
  165. return;
  166. }
  167. mInternalPlayer.stop();
  168. }
  169. private MediaSourceEventListener mMediaSourceEventListener = new MediaSourceEventListener() {
  170. @Override
  171. public void onReadingStarted(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
  172. if (mPlayerEventListener != null && mIsPreparing) {
  173. mPlayerEventListener.onPrepared();
  174. }
  175. }
  176. };
  177. /**
  178. * 重置播放器
  179. */
  180. @Override
  181. public void reset() {
  182. if (mInternalPlayer != null) {
  183. mInternalPlayer.stop(true);
  184. mInternalPlayer.setVideoSurface(null);
  185. mIsPreparing = false;
  186. mIsBuffering = false;
  187. mLastReportedPlaybackState = Player.STATE_IDLE;
  188. mLastReportedPlayWhenReady = false;
  189. }
  190. }
  191. /**
  192. * 是否正在播放
  193. */
  194. @Override
  195. public boolean isPlaying() {
  196. if (mInternalPlayer == null){
  197. return false;
  198. }
  199. int state = mInternalPlayer.getPlaybackState();
  200. switch (state) {
  201. case Player.STATE_BUFFERING:
  202. case Player.STATE_READY:
  203. return mInternalPlayer.getPlayWhenReady();
  204. case Player.STATE_IDLE:
  205. case Player.STATE_ENDED:
  206. default:
  207. return false;
  208. }
  209. }
  210. /**
  211. * 调整进度
  212. */
  213. @Override
  214. public void seekTo(long time) {
  215. if (mInternalPlayer == null){
  216. return;
  217. }
  218. mInternalPlayer.seekTo(time);
  219. }
  220. /**
  221. * 释放播放器
  222. */
  223. @Override
  224. public void release() {
  225. if (mInternalPlayer != null) {
  226. mInternalPlayer.removeListener(this);
  227. mInternalPlayer.removeVideoListener(this);
  228. final SimpleExoPlayer player = mInternalPlayer;
  229. mInternalPlayer = null;
  230. new Thread() {
  231. @Override
  232. public void run() {
  233. //异步释放,防止卡顿
  234. player.release();
  235. }
  236. }.start();
  237. }
  238. mIsPreparing = false;
  239. mIsBuffering = false;
  240. mLastReportedPlaybackState = Player.STATE_IDLE;
  241. mLastReportedPlayWhenReady = false;
  242. mSpeedPlaybackParameters = null;
  243. }
  244. /**
  245. * 获取当前播放的位置
  246. */
  247. @Override
  248. public long getCurrentPosition() {
  249. if (mInternalPlayer == null){
  250. return 0;
  251. }
  252. return mInternalPlayer.getCurrentPosition();
  253. }
  254. /**
  255. * 获取视频总时长
  256. */
  257. @Override
  258. public long getDuration() {
  259. if (mInternalPlayer == null){
  260. return 0;
  261. }
  262. return mInternalPlayer.getDuration();
  263. }
  264. /**
  265. * 获取缓冲百分比
  266. */
  267. @Override
  268. public int getBufferedPercentage() {
  269. return mInternalPlayer == null ? 0 : mInternalPlayer.getBufferedPercentage();
  270. }
  271. /**
  272. * 设置渲染视频的View,主要用于SurfaceView
  273. */
  274. @Override
  275. public void setSurface(Surface surface) {
  276. if (surface!=null){
  277. try {
  278. if (mInternalPlayer != null) {
  279. mInternalPlayer.setVideoSurface(surface);
  280. }
  281. } catch (Exception e) {
  282. mPlayerEventListener.onError(PlayerConstant.ErrorType.TYPE_UNEXPECTED,e.getMessage());
  283. }
  284. }
  285. }
  286. @Override
  287. public void setDisplay(SurfaceHolder holder) {
  288. if (holder == null){
  289. setSurface(null);
  290. } else{
  291. setSurface(holder.getSurface());
  292. }
  293. }
  294. /**
  295. * 设置音量
  296. */
  297. @Override
  298. public void setVolume(float leftVolume, float rightVolume) {
  299. if (mInternalPlayer != null){
  300. mInternalPlayer.setVolume((leftVolume + rightVolume) / 2);
  301. }
  302. }
  303. /**
  304. * 设置是否循环播放
  305. */
  306. @Override
  307. public void setLooping(boolean isLooping) {
  308. if (mInternalPlayer != null){
  309. mInternalPlayer.setRepeatMode(isLooping ? Player.REPEAT_MODE_ALL : Player.REPEAT_MODE_OFF);
  310. }
  311. }
  312. @Override
  313. public void setOptions() {
  314. //准备好就开始播放
  315. mInternalPlayer.setPlayWhenReady(true);
  316. }
  317. /**
  318. * 设置播放速度
  319. */
  320. @Override
  321. public void setSpeed(float speed) {
  322. PlaybackParameters playbackParameters = new PlaybackParameters(speed);
  323. mSpeedPlaybackParameters = playbackParameters;
  324. if (mInternalPlayer != null) {
  325. mInternalPlayer.setPlaybackParameters(playbackParameters);
  326. }
  327. }
  328. /**
  329. * 获取播放速度
  330. */
  331. @Override
  332. public float getSpeed() {
  333. if (mSpeedPlaybackParameters != null) {
  334. return mSpeedPlaybackParameters.speed;
  335. }
  336. return 1f;
  337. }
  338. /**
  339. * 获取当前缓冲的网速
  340. */
  341. @Override
  342. public long getTcpSpeed() {
  343. // no support
  344. return 0;
  345. }
  346. @Override
  347. public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
  348. if (mPlayerEventListener == null){
  349. return;
  350. }
  351. if (mIsPreparing){
  352. return;
  353. }
  354. if (mLastReportedPlayWhenReady != playWhenReady || mLastReportedPlaybackState != playbackState) {
  355. switch (playbackState) {
  356. //最开始调用的状态
  357. case Player.STATE_IDLE:
  358. break;
  359. //开始缓充
  360. case Player.STATE_BUFFERING:
  361. mPlayerEventListener.onInfo(PlayerConstant.MEDIA_INFO_BUFFERING_START, getBufferedPercentage());
  362. mIsBuffering = true;
  363. break;
  364. //开始播放
  365. case Player.STATE_READY:
  366. if (mIsBuffering) {
  367. mPlayerEventListener.onInfo(PlayerConstant.MEDIA_INFO_BUFFERING_END, getBufferedPercentage());
  368. mIsBuffering = false;
  369. }
  370. break;
  371. //播放器已经播放完了媒体
  372. case Player.STATE_ENDED:
  373. mPlayerEventListener.onCompletion();
  374. break;
  375. default:
  376. break;
  377. }
  378. mLastReportedPlaybackState = playbackState;
  379. mLastReportedPlayWhenReady = playWhenReady;
  380. }
  381. }
  382. @Override
  383. public void onPlayerError(ExoPlaybackException error) {
  384. if (mPlayerEventListener != null) {
  385. int type = error.type;
  386. if (type == TYPE_SOURCE){
  387. //错误的链接
  388. mPlayerEventListener.onError(PlayerConstant.ErrorType.TYPE_SOURCE,error.getMessage());
  389. } else if (type == ExoPlaybackException.TYPE_RENDERER
  390. || type == ExoPlaybackException.TYPE_UNEXPECTED
  391. || type == ExoPlaybackException.TYPE_REMOTE
  392. || type == ExoPlaybackException.TYPE_OUT_OF_MEMORY){
  393. mPlayerEventListener.onError(PlayerConstant.ErrorType.TYPE_UNEXPECTED,error.getMessage());
  394. }
  395. }
  396. }
  397. @Override
  398. public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
  399. if (mPlayerEventListener != null) {
  400. mPlayerEventListener.onVideoSizeChanged(width, height);
  401. if (unappliedRotationDegrees > 0) {
  402. mPlayerEventListener.onInfo(PlayerConstant.MEDIA_INFO_VIDEO_ROTATION_CHANGED, unappliedRotationDegrees);
  403. }
  404. }
  405. }
  406. @Override
  407. public void onRenderedFirstFrame() {
  408. if (mPlayerEventListener != null && mIsPreparing) {
  409. mPlayerEventListener.onInfo(PlayerConstant.MEDIA_INFO_VIDEO_RENDERING_START, 0);
  410. mIsPreparing = false;
  411. }
  412. }
  413. }