ExoPlayer浅析

ExoPlayer是一款由Google开发的开源媒体播放器,支持动态自适应流、HLS、DASH等格式。相比系统自带的MediaPlayer,ExoPlayer具有更多优点,如自适应流媒体、高级HLS特性、自定义扩展等。本文详细介绍了ExoPlayer的优缺点、使用方法、MediaSource的应用以及如何播放HLS和特殊格式文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ExoPlayer是个什么高大上的东西?怎么用?如何用?有哪些优缺点?相比IjkPlayer和Viatimo有那些区别?

ExoPlayer是什么?

ExoPlayer是一个开源媒体播放器,App等级的媒体API。

ExoPlayer的优缺点:

ExoPlayer相较于MediaPlayer有很多很多的优点:

  • 支持动态的自适应流HTTP(DASH) 和 平滑流,任何目前MediaPlayer支持的视频格式(同时它还支持HTTP直播了(HLS),MP4,MP3,WebM,M4A,MPEG-TS 和 AAC).
  • 支持高级的HLS特性,例如正确处理 EXT-X-DISCONTINUITY 标签;这个后面会举例。
  • 支持自定义和扩治你的使用场景。ExoPlayer专门为此设计;
  • 便于随着App的升级而升级。因为ExoPlayer是一个包含在你的应用中的库,对于你使用哪个版本有完全的控制权,并且你可以简单的跟随应用的升级而升级;
  • 更少的适配性问题。

值得注意的时,ExoPlayer同时有些缺点:

  • ExoPlayer的音频和视频组件依赖Android的 MediaCodec接口,该接口发布于Android4.1(API 等级16)。因此它不能工作于之前的Android版本。
  • ExoPlayer目前还不支持自动检查需要播放的媒体格式。应用需要知道他想要播放的媒体格式去构建一个ExoPlayer去播放媒体。

ExoPlayer的使用方法:

如果需要使用ExoPlayer,你需要执行以下几步:
1. 添加依赖
2. 创建player
3. 关联视图
4. 准备播放
5. 释放

1. 添加依赖到项目中:

在project的build.gradle中添加:

repositories {
    jcenter()
}

在app的build.gradle中添加最新版本的exopalyer包:

compile 'com.google.android.exoplayer:exoplayer:r2.X.X'

2. 创建player:

ExoPlayer是通过ExoPlayerFactory创建的,这个工厂类提供了一系列的方法可以创建各种个性化的player。绝大数情况下Renderer可以使用系统默认的,当然如果渲染器满足不了你的需求,你可以自定义。默认情况下可以直接使用ExoPlayerFactory.newSimpleInstance(),返回一个SimpleExoPlayer,SimpleExoPlayer是ExoPlayer的一个升级版,添加了一些强大的功能,可以直接使用。一个简单的SimpleExoPlayer的创建例子:

// 1. Create a default TrackSelector
Handler mainHandler = new Handler();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
    new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
    new DefaultTrackSelector(videoTrackSelectionFactory);

// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();

// 3. Create the player
SimpleExoPlayer player =
    ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);

3. 将播放器和视图连接起来

SimpleExoPleyerView可以写在布局文件中,可以直接在代码中使用下面代码即可实现视图的绑定://绑定视图
simpleExoPlayerView.setPlayer(player);

如果你想要更精确的对播放进行控制的话,可以使用Surface,SurfaceView,TextureView,surfaceHolder,使用SimpleExoplayer对应的方法如:我将视频播放和Surface联系起来,可以直接用setVideoSurface方法。还有setVideoSurfaceView, setVideoTextureView, setVideoSurfaceHolder方法可以选择使用。您可以使用PlaybackControlView作为一个独立的组件,或实现自己的播放控制,直接控制播放器。setTextOutput setId3Output可以用来接收标题和ID3元数据输出在回放期间。

4. 现在可以开始准备播放了。

有一点很重要,所有的资源都由MediaSource控制,所以第一步一定要创建对应的MediaSource。然后再将放入ExoPlayer,通过prepare方法来实现。
MediaSource主要有四种类型:
- ExtractorSampleSource - 用于MP3,M4A,WebM,MPEG-TS和AAC;
- HlsSampleSource - 用于HLS 播放;
- DashMediaSource - DASH的播放
- SsMeidaSource - 平滑流的播放
简单写一个如何播放MP4文件格式的代码:

// Measures bandwidth during playback. Can be null if not required.
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this,
    Util.getUserAgent(this, "yourApplicationName"), bandwidthMeter);
// Produces Extractor instances for parsing the media data.
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new ExtractorMediaSource(mp4VideoUri,
    dataSourceFactory, extractorsFactory, null, null);
// Prepare the player with the source.
player.prepare(videoSource);

一旦准备完毕,可以通过控制器来控制播放状态,比如你可以使用setPlayWhenReady来开始和暂停播放……

5. 释放player

不需要的时候一定要释放掉,释放响应的资源如:视频解码器,来供其他应用程序使用。方法:ExoPlayer.release().

MediaSource的讲解

前面提到了四种MediaSource,这四种在官方的Demo中都有详细的实现方法,这里不再赘述。这里讲一下其他三种:MergingMediaSource,LoopingMediaSource and ConcatenatingMediaSource.适合更复杂的视频播放。

1. 带有视频字幕文件的视频播放

视频文件和字幕文件是分开的,可以使用MergingMediaSource进行操作。代码如下:

MediaSource videoSource = new ExtractorMediaSource(videoUri, ...);
MediaSource subtitleSource = new SingleSampleMediaSource(subtitleUri, ...);
// Plays the video with the sideloaded subtitle.
MergingMediaSource mergedSource =
    new MergingMediaSource(videoSource, subtitleSource);

2. 实现无缝视频播放

什么叫无缝视频播放,简单来说,当这个视频文件播放完成后,切换到另一个视频文件播放,这中间没有延迟。如果要实现这个功能,我们可以使用LoopingMediaSource ;下面是一个无限循环的看一个视频的代码:代码如下:

MediaSource source = new ExtractorMediaSource(videoUri, ...);
// Loops the video indefinitely.
LoopingMediaSource loopingSource = new LoopingMediaSource(source);

3.无缝地玩一个视频序列

你可以使不同视频文件播放起来像同一文件一样,没有视频的切换和延迟,ConcatenatingMediaSource就派上作用了,它对视频的类型没有要求,如第一个视频为480p,第二个视频可以为720p,也可以为480p没有强制规定。下面是使用ConcatenatingMediaSource来完成两个视频的无缝播放。(它可以连接视频与音频流);代码如下:

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

4.高级操作

MediaSource不是单一的,是可以结合。怎么合并使用?
情景描述:给出两个视频A和B,可以一直按A.A.B的顺序循环下去,这个该怎么做?
思考:更具3和4可以使用LoopingMediaSource and ConcatenatingMediaSource
代码如下:
第一种方法:

MediaSource firstSource = new ExtractorMediaSource(firstVideoUri, ...);
MediaSource secondSource = new ExtractorMediaSource(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);
// Loops the sequence indefinitely.
LoopingMediaSource compositeSource = new LoopingMediaSource(concatenatedSource);

第二种方法:

MediaSource firstSource = new ExtractorMediaSource(firstVideoUri, ...);
MediaSource secondSource = new ExtractorMediaSource(secondVideoUri, ...);
// Plays the first video twice, then the second video.
ConcatenatingMediaSource concatenatedSource =
    new ConcatenatingMediaSource(firstSource, firstSource, secondSource);
// Loops the sequence indefinitely.
LoopingMediaSource compositeSource = new LoopingMediaSource(concatenatedSource);

特别注意:如果官方文档明确指出可以多次初始化使用,否则MediaSource只允许实例化一次,不允许出现重复。如ConcatenatingMediaSource明确指出可以允许出现重复。如上例。


播放事件处理,低级监听,高级监听,这些今后再补充,特别指出,在Android 4,4 (API19)以后,ExoPlayer支持数字版权管理。如果需要这个功能,你的应用必须使用DrmSessionManager来实例化你的播放器。具体参考官方文档

ExoPlayer播m3u8和google.redirector?

如何播放HLS格式的视频:

DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        AdaptiveVideoTrackSelection.Factory factory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
        DefaultTrackSelector selector = new DefaultTrackSelector(factory);
        DefaultLoadControl loadControl = new DefaultLoadControl();
        SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(this, selector, loadControl);
        mPlayerView.setPlayer(exoPlayer);
MediaSource mediaSource = new HlsMediaSource(Uri.parse(URL_HLS),
                new DefaultDataSourceFactory(this, "HlsPlayActivity"),
                null, null); 
exoPlayer.prepare(mediaSource);

如何播放google.redirector……格式文件:

private static final DefaultBandwidthMeter bandwidthMeter= new DefaultBandwidthMeter();
DataSource.Factory mediaDataSourceFactory = new DefaultDataSourceFactory(this, bandwidthMeter,
new DefaultHttpDataSourceFactory(Util.getUserAgent(this, "应用名"), bandwidthMeter);
 AdaptiveVideoTrackSelection.Factory factory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
        DefaultTrackSelector selector = new DefaultTrackSelector(factory);
 DefaultLoadControl loadControl = new DefaultLoadControl();
SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(this, selector, loadControl);
// SimpleExoPlayerView  mPlayerView
mPlayerView.setPlayer(exoPlayer);
MediaSource mMediaSource = new ExtractorMediaSource(Uri.parse(uri), mediaDataSourceFactory, new DefaultExtractorsFactory(),
                null, null);
exoPlayer.prepare(mMediaSource);
//设置事件处理
exoPlayer.addListener(new ExoPlayer.EventListener() {
            @Override
            public void onTimelineChanged(Timeline timeline, Object manifest) {
                Log.d(TAG, "onTimelineChanged() called with: timeline = [" + timeline + "], " +
                        "manifest = [" + manifest + "]");
            }

            @Override
            public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray
                    trackSelections) {
                pbLoaded.setVisibility(View.INVISIBLE);
                ivCover.setVisibility(View.INVISIBLE);
                Log.d(TAG, "onTracksChanged() called with: trackGroups = [" + trackGroups + "], " +
                        "trackSelections = [" + trackSelections + "]");
            }

            @Override
            public void onLoadingChanged(boolean isLoading) {
                Log.d(TAG, "onLoadingChanged: "+isLoading);
            }

            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                Log.d(TAG, "onPlayerStateChanged: "+playWhenReady);
            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {
                Log.d(TAG, "onPlayerError: ");
            }

            @Override
            public void onPositionDiscontinuity() {
                Log.d(TAG, "onPositionDiscontinuity: ");
            }
        });

总结:ExoPlayer也是最新学习的一个很好的开源框架,以前对于流媒体视频处理一直都是使用ijkPlayer,Vitamio。现在使用ijkPlayer的人也越来越多,第一免费,第二,支持的视频格式多,适配性强。当然,当时也是做快速开发,只要套上这个框架能使用就可以了,并没有做更多的深入。Exoplayer不说别的,Google开发的,你懂的。ExoPlayer相关文章会持续更新,不想再做一个浅尝辄止的IT男咯。本文是笔者学习所结,不全面之处还请见谅。有问题可以留言,看到及时回复。

参考资料:
ExoPlayerDemo下载地址
ExoPlayer官方文档
ExoPlayer开发者指导
ExoPlayer源码浅析

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值