ExoPlayer開發指南(官方文檔翻譯)

注意解決目前http直接發送請求失敗的問題:
(Cleartext HTTP traffic to xxx not permitted)
https://blog.csdn.net/qq_32534441/article/details/103529449

相關教程網站:
https://google.github.io/ExoPlayer/guide.html

前言

播放視頻和音樂是Android開發中很常見的需求。 Android框架提供了MediaPlayer這個類,能夠用最少代碼實現多媒體播放。同時,Android還提供偏底層的多媒體API,比如MediaCodec、AudioTrack和MediaDrm,可用於構建自定義媒體播放器解決方案。

ExoPlayer是google開源的應用級媒體播放器項目,構建在Android的底層多媒體API之上。該開源項目包含ExoPlayer庫和演示demo,github地址:https://github.com/google/ExoPlayer

優缺點

與Android內置的MediaPlayer相比,ExoPlayer具有許多優點:

  • 支持通過HTTP(DASH)和SmoothStreaming進行動態自適應流,這兩種都不受MediaPlayer的支持。還支持許多其他格式。有關詳細信息,請參閱支持的格式頁

  • 能夠自定義和擴展播放器,以適應各種不同需求。 ExoPlayer專門設計了這一點,大部分組件都可以自己替換

  • 官網說了很多,其實說到底最主要的就是各個組件可以自定義,還可以接入ffmpeg組件,基本能滿足99.9%的需求

缺點:

  • 缺點就是這個開源庫是基於Android4.1種的MediaCodec組件、Android4.4種的Widevine組件,所以最低支持版本是4.4

Library概述

ExoPlayer庫的核心是ExoPlayer接口,ExoPlayer公開了傳統的高級媒體播放器功能,例如緩衝媒體,播放,暫停和seek等功能。在具體實現方面,該開源庫對播放的媒體類型、存儲方式、位置、渲染方式等進行了最少的實現,旨在讓開發者自定義各種特性。ExoPlayer實現不是直接實現加載和呈現媒體,而是將這項工作委託給各種組件。 所有ExoPlayer共同的組件有:

  • MediaSource:定義多媒體數據源,這個類的功能就是從Uri中讀取多媒體文件的二進制數據。 MediaSource在播放開始時通過ExoPlayer.prepare注入

  • TrackSelector:軌道提取器,從MediaSource中提取各個軌道的二進制數據,交給Renderer渲染。創建播放器時初注入

  • Renderer:對多媒體中的各個軌道(音軌、視頻軌、字幕軌等)數據進行渲染,渲染就是“播放”,把二進制文件渲染成聲音、畫面。 創建播放器時注入

  • LoadControl:對MediaSource進行控制,比如什麼時候開始緩衝、緩衝多少等等。創建播放器時注入

該庫爲提供了這些組件的默認實現,能夠滿足大部分需求,如果有特殊需求,可以通過自定義組件來實現。 比如,可以自定義LoadControl來更改播放器的緩衝策略,或自定義Renderer來渲染Android本身不支持的編解碼器。

整個庫中都存在注入組件的概念,許多子組件都能單獨替換成自定義組件,而不會影響整個流程。 例如,默認的MediaSource實現需要通過其構造函數注入一個或多個DataSource工廠, 通過提供自定義Factory,可以從非標準源或不同的網絡堆棧加載數據。

入門

實現一個最簡單的播放器,需要如下流程:

  1. 添加ExoPlayer庫作爲依賴
  2. 創建一個SimpleExoPlayer實例
  3. 將播放器連接到UI,用於視頻輸出和用戶輸入(也就是放在某個Activity中)
  4. 準備播放器,傳入MediaSource作爲多媒體源
  5. 播放完成後釋放

這些步驟在下面更詳細地概述。完整的示例可以參考demo(github地址:https://github.com/google/ExoPlayer)中的PlayerActivity。

添加ExoPlayer作爲依賴

第一步是確保項目根目錄中的build.gradle文件中包含jcenter倉庫:

repositories {
    jcenter()
    google()
}

然後在應用app模塊的build.gradle文件中添加ExoPlayer庫的依賴:

    implementation 'com.google.android.exoplayer:exoplayer:2.6.0'
    implementation 'com.google.android.exoplayer:exoplayer-core:2.6.0'
    //(這裏解釋一下DASH(Dynamic Adaptive Streaming over HTTP)即自適應流媒體傳輸,什麼意思呢,簡單概括來說,就是在服務器端提前存好同一內容的不同碼率、不同分辨率的多個分片以及相應的描述文件MPD,客戶端在播放時即可以根據自身性能以及網絡環境選擇最適宜的版本)
    implementation 'com.google.android.exoplayer:exoplayer-dash:2.6.0'
    implementation 'com.google.android.exoplayer:exoplayer-ui:2.6.0'

不要忘記在AndroidManifest中添加網絡權限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

創建播放器

使用ExoPlayerFactory創建一個ExoPlayer實例, 該Factory提供了一系列方法來創建各種定製ExoPlayer實例。 大部分情況下,使用ExoPlayerFactory.newSimpleInstance方法之一即可, 這些方法返回SimpleExoPlayer,它實現了ExoPlayer以添加額外的高級別播放器功能。 下面是創建SimpleExoPlayer的示例:

// step1. 創建一個默認的TrackSelector
Handler mainHandler = new Handler();

// 創建帶寬
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();

// 創建軌道選擇工廠
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);

// 創建軌道選擇器實例
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

//step2. 創建播放器
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

使用SimpleExoPlayer的setVideoSurfaceView、setVideoTextureView、setVideoSurfaceHolder和setVideoSurface方法設置播放器的目標SurfaceView、TextureView、SurfaceHolder或Surface。

準備播放器

在ExoPlayer中,每一個多媒體文件均由MediaSource表示,要播放一個多媒體,您必須先創建一個相應的MediaSource實例,然後將此實例傳遞給ExoPlayer.prepare。 ExoPlayer庫爲DASH(DashMediaSource),SmoothStreaming(SsMediaSource),HLS(HlsMediaSource)和常規媒體文件(ExtractorMediaSource)提供了默認MediaSource實現,這些實現將在本指南的後面更詳細地描述。 下面的代碼演示如何播放一個mp4文件:

// 測量播放帶寬,如果不需要可以傳null
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();

// 創建加載數據的工廠
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
    Util.getUserAgent(context, "yourApplicationName"), bandwidthMeter);

// 創建解析數據的工廠
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

// 傳入Uri、加載數據的工廠、解析數據的工廠,就能創建出MediaSource
MediaSource videoSource = new ExtractorMediaSource(mp4VideoUri,
    dataSourceFactory, extractorsFactory, null, null);

// Prepare
player.prepare(videoSource);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

播放器準備好後,可以通過各種方法來控制播放。 例如,setPlayWhenReady啓動和暫停播放,seekTo方法控制進度。

退出時通過ExoPlayer.release釋放播放器,釋放硬件資源。

MediaSource

在ExoPlayer中,每個多媒體均由MediaSource表示, ExoPlayer庫爲DASH(DashMediaSource)、SmoothStreaming(SsMediaSource)、HLS(HlsMediaSource)和常規媒體文件(ExtractorMediaSource)提供了默認實現。 github上的demo中,可以在PlayerActivity中找到實例化所有四個示例。

除了上述的MediaSource之外,ExoPlayer庫還提供了MergingMediaSource、LoopingMediaSource和ConcatenatingMediaSource。 這些MediaSource通過組合實現更復雜的播放功能。 一些常見的用例如下所述。 注意,示例描述的是視頻播放,但它們同樣適用於僅音頻播放,實際上也適用於任何支持的媒體類型的播放。

加載字幕文件

給出一個視頻文件和一個單獨的字幕文件,MergingMediaSource可以用於將它們合併到單個源中進行播放:

// 創建視頻源
MediaSource videoSource = new ExtractorMediaSource(videoUri, ...);
// 創建字幕源
MediaSource subtitleSource = new SingleSampleMediaSource(subtitleUri, ...);
// 把視頻和字幕合併
MergingMediaSource mergedSource = new MergingMediaSource(videoSource, subtitleSource);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

循環播放單個視頻

使用LoopingMediaSource可以使視頻無縫循環播放多次。 以下示例播放視頻5次:

MediaSource source = new ExtractorMediaSource(videoUri, ...);
// 播放5次
LoopingMediaSource loopingSource = new LoopingMediaSource(source, 5);
  • 1
  • 2
  • 3

循環播放視頻列表

ConcatenatingMediaSource可以連續播放兩個或多個單獨的MediaSource。 以下示例依次播放兩個視頻。 源之間的轉換是無縫的,每個視頻源可以是不同格式(例如,可以將480p H264的視頻文件與720p VP9的視頻文件連接在一起),可以是不同的類型(例如,將視頻與僅音頻流連接):

MediaSource firstSource = new ExtractorMediaSource(firstVideoUri, ...);
MediaSource secondSource = new ExtractorMediaSource(secondVideoUri, ...);
// 連接多媒體source
ConcatenatingMediaSource concatenatedSource =
    new ConcatenatingMediaSource(firstSource, secondSource);
  • 1
  • 2
  • 3
  • 4
  • 5

進一步組合MediaSource

可以進一步將複雜的MediaSources組合在一起。比如,給定兩個視頻A和B,以下示例顯示瞭如何一起使用LoopingMediaSource和ConcatenatingMediaSource來播放序列(A,A,B):

MediaSource firstSource = new ExtractorMediaSource(firstVideoUri, ...);
MediaSource secondSource = new ExtractorMediaSource(secondVideoUri, ...);
// 第一個source播放兩次
LoopingMediaSource firstSourceTwice = new LoopingMediaSource(firstSource, 2);
// 把第一個source和firstSourceTwice連接起來
ConcatenatingMediaSource concatenatedSource =
    new ConcatenatingMediaSource(firstSourceTwice, secondSource);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

下面的示例也可以得到相同的結果:

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);
  • 1
  • 2
  • 3
  • 4
  • 5


事件監聽

播放期間,可以監聽由ExoPlayer生成的事件,指示播放器的整體狀態。 這些事件可用作更新用戶界面(如播放控件)的觸發器。 許多ExoPlayer組件還報告自己的組件特定的底層事件,可以用來監聽性能。

上層事件

ExoPlayer通過addListener/removeListener方法添加/刪除ExoPlayer.EventListener的實例, 監聽者能夠監聽到播放狀態的變化,以及播放失敗的事件。

使用SimpleExoPlayer時,可以在播放器上設置其他偵聽器。 比如,setVideoListener允許應用程序接收與視頻渲染有關的事件,這些事件可能對於調整UI(例如,一個特定寬高比的視頻被渲染到surface上了)有用。 可以在SimpleExoPlayer上設置其他偵聽器來接收調試信息,例如調用setVideoDebugListener和setAudioDebugListener。

底層事件

除了上層監聽外,ExoPlayer庫提供的許多單獨的組件允許自己的事件監聽器。 通常需要將Handler對象傳遞給這些組件,這些Handler決定偵聽器方法將在哪個線程調用,所以在大多數情況下,應該使用主線程的Handler。

向組件發送消息

一些組件允許在播放過程中更改配置。 一般來說,可以通過sendMessages或blockingSendMessages方法將消息通過ExoPlayer傳遞到組件來進行更改。 這種方法確保了線程安全,更改配置的操作與ExoPlayer上的其它事件一樣,需要按順序執行。

自定義

ExoPlayer與MediaPlayer的主要優點之一是可以自定義和擴展播放器,以更好地適應開發人員使用。 ExoPlayer庫專門設計了這一點,定義了一些接口和抽象基類,使應用程序開發人員可以輕鬆地替換庫提供的默認實現。 以下是構建自定義組件的一些case:

  • Renderer:可以自定義Renderer來處理默認實現不支持的多媒體格式

  • TrackSelector:自定義TrackSelector可以更改從MediaSource中提取軌道的方式

  • LoadControl:自定義LoadControl可以更改播放器的緩衝策略

  • Extractor:如果需要支持默認庫不支持的容器格式,可以自定義Extractor類,然後可以將其與ExtractorMediaSource一起使用,以播放容器格式的多媒體

  • MediaSource:如果希望獲取媒體樣本以自定義方式提供給渲染器,或者希望實現自定義MediaSource合成行爲,則實現自定義MediaSource類可能是適當的

  • DataSource:ExoPlayer庫已經包含了許多不同情況的DataSource實現。您可能希望實現自己的DataSource類,以其他方式加載數據,比如通過自定義協議,使用自定義HTTP堆棧或從自定義持久緩存加載數據。

自定義指南

如果自定義組件需要將事件報告迴應用程序,我們建議您使用與現有ExoPlayer組件相同的模型,其中將事件偵聽器與Handler一起傳遞到組件的構造函數。

我們建議自定義組件使用與現有ExoPlayer組件相同的模型,以便在播放過程中可以方便地重新配置,請參考上面“向組件發送消息”章節。 爲此,您應該實現一個ExoPlayerComponent並在其handleMessage方法中接收配置更改消息。 您的應用程序應通過調用ExoPlayer的sendMessages和blockingSendMessages方法來傳遞配置更改。



以下轉自:
ExoPlayer基本使用和關鍵類流程

public class MainActivity extends AppCompatActivity {

    private final String testUrl="http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4";
    SimpleExoPlayer mPlayer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initExoPlayer();
    }

    private void initExoPlayer() {
        RenderersFactory renderersFactory=new DefaultRenderersFactory(this);
        DefaultTrackSelector trackSelector=new DefaultTrackSelector();
        LoadControl loadControl=new DefaultLoadControl();
        mPlayer= ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector,loadControl);

        SimpleExoPlayerView playerView=new SimpleExoPlayerView(this);
        playerView.setPlayer(mPlayer);
        setContentView(playerView);

        Uri mp4Uri=Uri.parse(testUrl);
        DefaultDataSourceFactory dataSourceFactory=new DefaultDataSourceFactory(
                this, Util.getUserAgent(this,"exoPlayerTest"));
        ExtractorsFactory extractorsFactory=new DefaultExtractorsFactory();
        MediaSource mediaSource=new ExtractorMediaSource(
                mp4Uri,dataSourceFactory,extractorsFactory,null,null);
        mPlayer.prepare(mediaSource);
    }


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

#關鍵類流程圖

如果對播放器原理完全不理解的同學可以看下此文章: https://www.jianshu.com/p/82e778eb618b

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章