Android ExoPlayer 集成使用以及源码分析

一、简要介绍ExoPlayer

  • Android框架本身提供了MediaPlayer来实现媒体播放。还提供了其他媒体api框架,如MediaCodec、AudioTrack和MediaDrm,可用于构建自定义媒体播放器解决方案。
  • ExoPlayer是一款开源的应用级媒体播放器,可以参考官网Git
  • ExoPlayer是Android的应用程序级媒体播放器。 它提供了Android的MediaPlayer API的替代品,用于在本地和互联网上播放音频和视频。 ExoPlayer支持Android MediaPlayer API目前不支持的功能,包括DASH和SmoothStreaming自适应回放。 与MediaPlayer API不同,ExoPlayer易于定制和扩展,并可通过Play Store应用程序更新进行更新。
    在这里插入图片描述

二、项目开发集成和使用ExoPlayer

1 、入门使用:

  • 将ExoPlayer添加为项目的依赖项。
    确保build.gradle的项目根目录中的文件中包含Google和JCenter存储库
repositories {
    google()
    jcenter()
}
添加ExoPlayer模块:

在build.gradle您的应用模块的文件中添加一个依赖项。以下内容将对完整的ExoPlayer库添加依赖项:
这里我们选择最新的:
在这里插入图片描述

implementation 'com.google.android.exoplayer:exoplayer:2.11.7'

作为完整库的替代方法,可以仅依赖实际需要的库模块。例如,以下内容将添加对Core,DASH和UI

库模块的依赖关系,这可能是播放DASH内容的应用程序所必需的:

implementation 'com.google.android.exoplayer:exoplayer-core:2.11.7'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.11.7'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.2.11.7'

在这里插入图片描述

可用的库模块在下面列出。向完整的ExoPlayer库添加依赖项等效于分别为所有库模块添加依赖项。

库名称主要功能
exoplayer-cor核心功能
exoplayer-dash支持DASH内容
exoplayer-hlsr支持HLS内容
exoplayer-smoothstreamingr支持SmoothStreaming内容
exoplayer-uir与ExoPlayer一起使用的UI组件和资源

除了库模块之外,ExoPlayer还具有多个扩展模块,这些扩展模块依赖于外部库来提供附加功能。浏览 扩展目录及其各自的自述文件以了解详细信息。
在这里插入图片描述

  • 创建一个MyExoPlayerDemo工程。
    在这里插入图片描述
需要开启JAVA8
compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}

在这里插入图片描述

在这里插入图片描述

有兴趣的可以自己复写源码,增加定制功能;

创建播放器

可以使用SimpleExoPlayer.Builder或 创建实例ExoPlayer.Builder。这些构建器提供了一系列用于创建ExoPlayer实例的定制选项。对于绝大多数用例, SimpleExoPlayer.Builder都应使用。此构建器返回 SimpleExoPlayer,它扩展ExoPlayer为添加其他高级播放器功能。以下代码是创建的示例SimpleExoPlayer。

SimpleExoPlayer mPlayer = new SimpleExoPlayer.Builder(mContext).build();

在这里插入图片描述

  • 将播放器连接到视图(用于视频输出和用户输入)。
  • 准备播放器MediaSource以播放。
  • 完成后释放播放器。

可以参考个人Exoplayer Demo Git:

https://github.com/xiaxiaxa/ExoPlayerDemo.git

package com.mgtv.exodemo.activity;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.util.Log;

import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;

import com.mgtv.exodemo.MyApplication;
import com.mgtv.exodemo.R;


public class ExoPlayerActivity extends BaseActivity {

    private Context mContext;
    private PlayerView mPlayerView = null;
    private SimpleExoPlayer mPlayer;
    private DataSource.Factory mediaDataSourceFactory;
    private MediaSource mediaSourceHls;
    //    private UdpDataSource udpDataSourceRtp;
    private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
    private String videoUrlRtp = "rtp://239.76.245.115:1234";
    private String videoUrlHls = "http://10.255.30.137:8082/EDS/RedirectPlay/000000000000/vod/f95e41c67ca2410c89b335ee5f5eecb8/3cc6fae6d07740aa8d57934e26cc2632?UserToken=123456789&UserName=6830018";


    private void initExoPlayer() {
        mPlayer = new SimpleExoPlayer.Builder(mContext).build();
        mPlayerView.setPlayer(mPlayer);
        Uri playHlsUri = Uri.parse(videoUrlHls);
//        Uri playRtpUri = Uri.parse(videoUrlRtp);
        /**使用dash的解析库*/
/*        dashMediaSource = new DashMediaSource(playHlsUri,mediaDataSourceFactory,
                new DefaultDashChunkSource.Factory(mediaDataSourceFactory
        ),null,null);*/

        /**====解析hls===begin*/
        mediaSourceHls = new HlsMediaSource.Factory(mediaDataSourceFactory)
                .createMediaSource(playHlsUri, null, null);
        Log.d("exo", "Mr.xw==mediaSource==" + mediaSourceHls);
        mPlayer.prepare(mediaSourceHls);
        mPlayerView.setPlayer(mPlayer);
        mPlayer.setPlayWhenReady(true);
        /**====解析hls===end*/

        /**====解析rtp===begin 这块需要复写udp方法,暂未实现*/

/*        mediaSourceHls = new UdpDataSource(mediaDataSourceFactory)
                .createMediaSource(playHlsUri, null, null);
        Log.d("exo", "Mr.xw==mediaSource==" + mediaSourceHls);
        mPlayerView.setPlayer(mPlayer);
        mPlayer.setPlayWhenReady(true);*/
        /**====解析rtp===end*/
        

    }


    @Override
    public int getLayoutRes() {
        getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        return R.layout.exoplayer;
    }

    @Override
    public void init() {
        mContext = this;
        mPlayerView = findViewById(R.id.exo_vr);
        mediaDataSourceFactory = buildDataSourceFactory(true);
        initExoPlayer();
    }

    private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) {
        return ((MyApplication) getApplication())
                .buildDataSourceFactory(useBandwidthMeter ? null : null);
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }

    @Override
    protected void onStop() {
        super.onStop();

    }


    @Override
    protected void onPause() {
        super.onPause();
        releaseData();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseData();
    }

    private void releaseData() {
        if (isFinishing()) {
            if (mPlayer != null) {
                mPlayer.stop();
                mPlayer.release();
                mPlayer = null;
            }
            if (mPlayerView!=null){
                mPlayerView.destroyDrawingCache();
                mPlayerView = null;
            }
        }
    }
}

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "30.0.0"
    defaultConfig {
        applicationId "com.mgtv.exodemo"
        minSdkVersion 19
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation 'com.google.android.exoplayer:exoplayer:2.11.7'
    implementation 'com.google.android.exoplayer:exoplayer-core:2.11.7'
    implementation 'com.google.android.exoplayer:exoplayer-dash:2.11.7'
    implementation 'com.google.android.exoplayer:exoplayer-hls:2.11.7'
    implementation 'com.google.android.exoplayer:exoplayer-ui:2.11.7'
    implementation 'com.google.android.exoplayer:extension-rtmp:2.11.7'
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation files('libs/xutils.jar')
    implementation 'androidx.appcompat:appcompat:1.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

ExoPlayer库的核心是ExoPlayer接口。Exoplayer把播放类型、存储位置和渲染方式等任务委派给不同的部件,然后在创建播放器或后台播放的时候把这些部件注入。这些部件包括:

  • MediaSource - 负责装载 media,装载到MediaSource 的 media 可以被读取,MediaSource 在调用
    ExoPlayer.prepare 方法时被注入。
  • Render S - 用于渲染 media 的部件,在创建播放器时被注入。
  • TrackSelector - 从MediaSource 中选出 media 提供给可用的 Render S
    来渲染,在创建播放器时被注入。
  • LoadControl - 控制 MediaSource 缓存更多的 media,有多少 media 被缓冲。在创建播放器时被注入。

如果标准实现不能满足需求,也可以使用自定义实现。例如,自定义LoadControl 可以改变播放器的缓冲策略,或自定义Renderer 可实现 Android 本身不支持的视频编解码器。

ExoPlayer提供默认的音频和视频渲染器,利用了Android框架中的MediaCodec和AudioTrack类。这两个都需要一个SampleSource对象中注入,用来实现媒体示例的播放。

组件的注入在当前ExoPlayer库中是普遍存在的。下图展示了使用一个ExoPlayer来配置和播放MP4媒体流的高级对象模型。默认的音频和视频渲染器已经被注解到ExoPlayer中。ExtractorSampleSource类的实现被注解到渲染器中用于提供简单的媒体播放功能。DataSource和Extractor示例被注解到ExtractorSampleSource来支持加载媒体流和在被加载的数据中提取样板。在这个示例中DefaultUriDataSource和Mp4Extractor被用于播放从URIs中导入的MP4流。

可以参考官网文档:

[developer guide]:

https://google.github.io/ExoPlayer/guide.html

[class reference]:

https://google.github.io/ExoPlayer/doc/reference

[release notes]:

 https://github.com/google/ExoPlayer/blob/release-v2/RELEASENOTES.md

[developer blog]:

 https://medium.com/google-exoplayer

2.MediaSource

我们重点看下MediaSource的使用;

在ExoPlayer中,每个media都由 MediaSource 表示。 ExoPlayer库为DASH(DashMediaSource),SmoothStreaming(SsMediaSource),HLS(HlsMediaSource)和常规媒体文件(ExtractorMediaSource)提供了MediaSource实现。 在 main demo app 的PlayerActivity中可以找到如何实例化所有四个示例。

需要注意:MediaSource实例不适用于重新使用的情况。 如果您想用相同的media多次准备播放器,请每次使用新的实例。

除了上述的MediaSource实现外,ExoPlayer库还提供了MergingMediaSource,LoopingMediaSource,ConcatenatingMediaSource和DynamicConcatenatingMediaSource。这些MediaSource实现可以通过组合来实现更复杂的播放功能。下面描述了一些常见的用例。请注意,尽管在视频播放的上下文中描述了以下示例,但它们同样适用于仅播放音频,以及任何支持的媒体类型的播放的情况。

序号主要功能
1从侧面加载字幕文件
2循环播放视频
3播放一系列视频
4高级组合
(1)从侧面加载字幕文件
// Build the video MediaSource.
MediaSource videoSource =
    new ExtractorMediaSource.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);
(2)循环播放视频

无限循环,通常最好使用 ExoPlayer.setRepeatMode 而不是 LoopingMediaSource。

MediaSource source =
    new ExtractorMediaSource.Factory(...).createMediaSource(videoUri);
// Plays the video twice.
LoopingMediaSource loopingSource = new LoopingMediaSource(source, 2);
(3)播放一系列视频

ConcatenatingMediaSource 可以连续播放两个或多个单独的MediaSource。 比如按顺序播放了两个视频的例子。 数据源之间的转换是无缝的。对连接的源具有相同的格式这一点不做强制要求,您可以把两个不同格式的数据源连接起来。

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

DynamicConcatenatingMediaSource 类似于 ConcatenatingMediaSource,不同之处在于它允许在播放前和播放期间动态添加,删除和移动MediaSource。 DynamicConcatenatingMediaSource非常适合于播放列表的使用场景,即用户可以在播放期间修改播放列表。

MediaSource 实例不应该多次添加到 DynamicConcatenatingMediaSource中,或者在之前被删除的情况下重新添加。 推荐创建新的实例去操作。

(4)高级组合

有可能进一步将复合MediaSources组合起来,用于更多不常见的用法。 给定两个视频A和B,以下示例显示LoopingMediaSource和ConcatenatingMediaSource如何一起使用来播放序列(A,A,B)。

ediaSource firstSource =
    new ExtractorMediaSource.Factory(...).createMediaSource(firstVideoUri);
MediaSource secondSource = 
    new ExtractorMediaSource.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 ExtractorMediaSource.Builder(firstVideoUri, ...).build();
MediaSource secondSource = new ExtractorMediaSource.Builder(secondVideoUri, ...).build();
// Plays the first video twice, then the second video.
ConcatenatingMediaSource concatenatedSource =
     new ConcatenatingMediaSource(firstSource, firstSource, secondSource);

除非文档明确允许,否则避免在组合中多次使用相同的MediaSource实例很重要。 上面的示例中使用firstSource两次就是这种情况,因为用于ConcatenatingMediaSource的Javadoc明确指出允许重复条目。 然而,一般来说,由构造组成的对象的图形应该是树形结构(这个地方不好翻译,英文不好见谅)。 在组合中使用多个等效的MediaSource实例是允许的。

最后

个人觉得使用ExoPlayer的一个特别之处是ExoPlayer支持数字版权管理(DRM)保护回放;

ExoPlayer库提供了一个DrmSessionManager的默认实现,名为DefaultDrmSessionManager,它使用MediaDrm。会话管理器支持在设备上存在模块DRM组件的任何DRM方案。所有的Android设备都需要支持Widevine模块DRM(使用L3安全性,尽管许多设备也支持L1)。某些设备可能支持其他方案,例如PlayReady。所有的Android TV 设备都支持PlayReady。

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ExoPlayer是一个开源的Android音视频播放器,由Google开发和维护。它支持多种音视频格式、网络协议和多种数据源,可以满足各种应用场景的需求。下面是使用ExoPlayer进行音视频播放的基本步骤: 1. 添加ExoPlayer库依赖 在项目的build.gradle中添加以下依赖库: ``` implementation 'com.google.android.exoplayer:exoplayer-core:2.14.0' implementation 'com.google.android.exoplayer:exoplayer-dash:2.14.0' // 适用于DASH格式视频 implementation 'com.google.android.exoplayer:exoplayer-ui:2.14.0' // 可选依赖,提供了默认的播放器UI组件 ``` 2. 创建ExoPlayer实例 在需要播放视频的Activity或Fragment中创建ExoPlayer实例: ``` SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build(); ``` 3. 准备媒体资源 准备需要播放的媒体资源,可以是本地文件或网络地址。如果是网络资源,需要使用ExtractorMediaSource或DashMediaSource进行数据源的构建: ``` MediaItem mediaItem = MediaItem.fromUri(uri); // uri为需要播放的资源地址 player.setMediaItem(mediaItem); player.prepare(); ``` 4. 开始播放 调用ExoPlayer的start方法即可开始播放: ``` player.play(); ``` 5. 暂停和停止播放 可以通过pause和stop方法实现暂停和停止播放: ``` player.pause(); player.stop(); ``` 6. 释放资源 在Activity或Fragment的生命周期中,需要在onDestroy或onDestroyView方法中释放ExoPlayer资源: ``` player.release(); ``` 以上就是使用ExoPlayer进行音视频播放的基本步骤。需要注意的是,ExoPlayer在播放过程中可能会抛出各种异常,需要在代码中进行处理。同时,ExoPlayer还提供了丰富的参数配置和事件监听接口,可以根据具体需求进行配置和使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值