ExoPlayer是运行在YouTube app Android版本上的视频播放器。不仅功能强大,而且使用简单,可定制性强。ExoPlayer也是Google官方推荐的Android媒体播放器,可以在Android官方文档的音频和视频目录中找到。

一,优点和缺点

     优点:

       1,支持DASH和SmoothStreaming这两种数据格式的资源,而MediaPlayer对这两种数据格式都不支持。它还支持其它格式的数据资源,比如MP4, M4A, FMP4, WebM, MKV, MP3, Ogg, WAV, MPEG-TS, MPEG-PS, FLV and ADTS (AAC)等

       2,支持高级的HLS特性,比如能正确的处理#EXT-X-DISCONTINUITY标签

       3,无缝连接,合并和循环播放多媒体的能力

       4,和应用一起更新播放器(ExoPlayer),因为ExoPlayer是一个集成到应用APK里面的库,你可以决定你所想使用的ExoPlayer版本,并且可以随着应用的更新把ExoPlayer更新到一个最新的版本。

       5,较少的关于设备的特殊问题,并且在不同的Android版本和设备上很少会有不同的表现。

       6,在Android4.4(API level 19)以及更高的版本上支持Widevine通用加密

       7,为了符合你的开发需求,播放器支持自定义和扩展。其实ExoPlayer为此专门做了设计,并且允许很多组件可以被自定义的实现类替换。

       8,使用官方的扩展功能可以很快的集成一些第三方的库,比如IMA扩展功能通过使用互动媒体广告SDK可以很容易地将视频内容货币化(变现)

     缺点:

       1,在某些设备上播放音频,ExoPlayer可能会比MediaPlayer消耗更多的电量。

二,使用

1,添加依赖

implementation 'com.google.android.exoplayer:exoplayer:2.X.X'

        目前最新版本是2.10.5,最新的版本可以查看github地址。

        上面是省事的方式,依赖了整个ExoPlayer库。也可以根据自己的需求选择性添加依赖,如核心库和UI库,这两个可以满足基本上的视频播放需求:

implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X'implementation 'com.google.android.exoplayer:exoplayer-ui:2.X.X'

        整个ExoPlayer库包含5个字库,依赖5个子库和依赖整个库效果是一样的。

  • exoplayer-core:核心功能 (必要)
  • exoplayer-dash:支持DASH内容
  • exoplayer-hls:支持HLS内容
  • exoplayer-smoothstreaming:支持SmoothStreaming内容
  • exoplayer-ui:用于ExoPlayer的UI组件和相关的资源。

2,添加Java8的支持

android {    compileOptions {        sourceCompatibility JavaVersion.VERSION_1_8        targetCompatibility JavaVersion.VERSION_1_8    }}

3,布局中引入

4,activity中使用

val player = ExoPlayerFactory.newSimpleInstance(this,DefaultTrackSelector(),DefaultLoadControl())player.playWhenReady = truevideo_view.player = playerval uri = Uri.parse("https://cdn.xxxxxx.com/new-sing/66c3d05eaa177e07d57465f948f0d8b934b7a7ba.mp4")val dataSourceFactory = DefaultHttpDataSourceFactory("user-agent")val videoSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri)// 播放player.prepare(mediaSource)

        此时已经可以播放了,如下:

5,释放资源

        适当时候释放资源

player.release()

6,添加监听

        Player.EventListener中有很多监听方法,但都是default类型的,可以根据需求添加实现。

player.addListener(object:Player.EventListener{    override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {        Log.e("ExoPlayer","playWhenReady: $playWhenReady  +$playbackState")        when (playbackState){            Player.STATE_BUFFERING->                Toast.makeText([email protected],"加载中",Toast.LENGTH_LONG).show()            Player.STATE_READY->                Toast.makeText([email protected],"播放中",Toast.LENGTH_LONG).show()            Player.STATE_ENDED->                Toast.makeText([email protected],"播放完成",Toast.LENGTH_LONG).show()        }    }    override fun onPlayerError(error: ExoPlaybackException?) {        Log.e("ExoPlayer","ExoPlaybackException: $error")    }    ...})

三,其他功能

1,Clipping a video(视频裁剪)

        播放指定的范围:

MediaSource videoSource =    new ProgressiveMediaSource.Factory(...).createMediaSource(videoUri);// Clip to start at 5 seconds and end at 10 seconds.ClippingMediaSource clippingSource =    new ClippingMediaSource(        videoSource,        /* startPositionUs= */ 5_000_000,        /* endPositionUs= */ 10_000_000);

2,Side-loading a subtitle file(加载台词)

// Build the video MediaSource.MediaSource videoSource =    new ProgressiveMediaSource.Factory(...).createMediaSource(videoUri);// Build the subtitle MediaSource.Format subtitleFormat = Format.createTextSampleFormat(    id, // An identifier for the track. May be null.    MimeTypes.APPLICATION_SUBRIP, // The mime type. Must be set correctly.    selectionFlags, // Selection flags for the track.    language); // The subtitle language. May be null.MediaSource subtitleSource =    new SingleSampleMediaSource.Factory(...)        .createMediaSource(subtitleUri, subtitleFormat, C.TIME_UNSET);// Plays the video with the sideloaded subtitle.MergingMediaSource mergedSource =    new MergingMediaSource(videoSource, subtitleSource);

3,Advanced composition(视频合并)

        下面两种方式实现第一个视频播放两次,第二个播放一次

        方法一:

MediaSource firstSource =    new ProgressiveMediaSource.Factory(...).createMediaSource(firstVideoUri);MediaSource secondSource =    new ProgressiveMediaSource.Factory(...).createMediaSource(secondVideoUri);// Plays the first video twice.LoopingMediaSource firstSourceTwice = new LoopingMediaSource(firstSource, 2);// Plays the first video twice, then the second video.ConcatenatingMediaSource concatenatedSource =    new ConcatenatingMediaSource(firstSourceTwice, secondSource);

        方法二:

MediaSource firstSource =    new ProgressiveMediaSource.Factory(...).createMediaSource(firstVideoUri);MediaSource secondSource =    new ProgressiveMediaSource.Factory(...).createMediaSource(secondVideoUri);// Plays the first video twice, then the second video.ConcatenatingMediaSource concatenatedSource =    new ConcatenatingMediaSource(firstSource, firstSource, secondSource);

        还有其他功能,可以参看官方文档:https://exoplayer.dev/hello-world.html

四,自定义UI

1,简单自定义

        这种方式是通过修改ExoPlayer预留的布局文件来实现定制化,但是这种方式只能修改特定的一些UI。

在源代码中可以找到

int controllerLayoutId = R.layout.exo_player_control_view;

        也就是说ExoPlayer默认使用的是这个布局,我们可以在代码中新建一个名为:exo_player_control_view 的layout,或者在xml中添加

        指定我们的layout来实现覆盖的目的。如下:

                                                                        

        效果如下:

缺点:

        这种方式控件的id不能随便起,要与exoPlayer原来PlaybackControlView的布局控件id,名称一致,不然就人家的代码中是获取不到你的id的。

        有这些控件id可以使用:

                exo_play –>播放

                exo_pause –>暂停

                exo_rew –>后退

                exo_ffwd –>前进

                exo_prev –>上一个

                exo_next –>下一个

                exo_repeat_toggle –>重复模式开关

                exo_duration –>视频总时长

                exo_position –>当前播放位置

                exo_progress –>播放进度

2,高级自定义

        高级自定义可以实现任意的效果,如下:

1,首先需要重写: com.google.android.exoplayer2.ui.PlayerView。这里的“重写”是指新建一个类比如MyPlayerView,然后复制PlayerView中的代码到MyPlayerView。使用时引用MyPlayerView。

2,引入自定义的布局,如:senior_diy_player_control_view.xml,通过controller_layout_id属性设置布局,如下:

3,改变了布局以后需要添加自定义的事件,需要重写com.google.android.exoplayer2.ui.PlayerControlView,跟上面一样新建一个MyPlayerControlView,然后把代码复制进去,同时需要把MyPlayerView中所有的PlayerControlView的引用改为MyPlayerControlView的引用,此时MyPlayerControlView就生效了,在这里可以找到原布局中的播放、暂停、快进、快退按钮:

private final View playButton;private final View pauseButton;private final View fastForwardButton;private final View rewindButton;

        以及对应的点击事件:

playButton = findViewById(R.id.exo_play);if (playButton != null) {    playButton.setOnClickListener(componentListener);}pauseButton = findViewById(R.id.exo_pause);if (pauseButton != null) {    pauseButton.setOnClickListener(componentListener);}

        以及具体的事件方法:

@Overridepublic void onClick(View view) {    ...    if (playButton == view) {        ...    } else if (pauseButton == view) {        ...    }    ...}

        接下来怎么做就不用多说了。

4,此时还不能改变进度条的样式,进度条通过com.google.android.exoplayer2.ui.DefaultTimeBar实现的,如果要改变进度条样式就需要重写DefaultTimeBar,和上面的一样,新建一个MyTimeBar,把代码复制进去,修改MyPlayerControlView中对DefaultTimeBar的引用,DefaultTimeBar继承自View,修改样式也就是自定义View的操作,比如我这里把原来的进度改成圆头的代码:

private void drawTimeBar(Canvas canvas) {    ..    if (duration <= 0) {//      canvas.drawRect(progressBar.left, barTop, progressBar.right, barBottom, unplayedPaint);      // 改为圆角      canvas.drawRoundRect(progressBar.left, barTop, progressBar.right, barBottom, barHeight/2,barHeight/2, unplayedPaint);      return;    }    ...    if (progressLeft < progressBar.right) {//      canvas.drawRect(progressLeft, barTop, progressBar.right, barBottom, unplayedPaint);      // 改为圆角      canvas.drawRoundRect(scrubberBar.left, barTop, progressBar.right, barBottom, barHeight/2,barHeight/2,unplayedPaint);    }    ...    if (bufferedRight > bufferedLeft) {//      canvas.drawRect(bufferedLeft, barTop, bufferedRight, barBottom, bufferedPaint);      // 改为圆角      canvas.drawRoundRect(bufferedLeft, barTop, bufferedRight, barBottom, barHeight/2,barHeight/2,bufferedPaint);    }    if (scrubberBar.width() > 0) {//      canvas.drawRect(scrubberBar.left, barTop, scrubberBar.right, barBottom, playedPaint);      // 改为圆角      canvas.drawRoundRect(scrubberBar.left, barTop, scrubberBar.right, barBottom, barHeight/2,barHeight/2, playedPaint);    }    ...}

        这里就不多说了。

        代码地址:https://github.com/giswangsj/ExoPlayerDemo,感觉有用的帮忙star一下

 

 

 

 

更多相关文章

  1. Android中Toast的用法简介(转)
  2. Android(安卓)如何获取经纬度
  3. android画图——Path()的使用
  4. ubuntu下Android源代码模块编译
  5. 关于使用Android(安卓)Application的注意点
  6. Android中的线性布局(LinearLayout)
  7. Android多Module合并aar打包
  8. Android(安卓)简单计算器源码....
  9. Android学习之Adapter(适配器)源代码分析与观察者模式的运用(一)

随机推荐

  1. 100分面试题,背过面试老师说好的我们再仔
  2. 从来不相信快速会成就一件事,我只相信笨功
  3. 自学第六十一天
  4. 大部分中产阶级都只是靠工资过中产,如何增
  5. 我就是要单打独斗
  6. 我们没有退路,只有不断向前
  7. 不断持续做,未来就已经到来
  8. 全力以赴让人喜乐
  9. 保持忠贞是不容易的,需要持续付出努力
  10. 必会10大软件测试软件工具,不知道的快收藏