Building a video player app in Android(Part1 - 2)を読んだメモ

本当に読んだときの自分のメモ書きなので、英語読める方はそちらのほうが良いと思います。
https://medium.com/google-developers/building-a-video-player-app-in-android-part-1-5-d95770ef762d
本当はPart5まで見たかったのですが、時間切れしました。もしかしたら追加するかもです。
`Listening to player events for UX`が良かったです。もう少し深く見ていきたいです。



# ExoPlayer introduction(Part 1)
https://medium.com/google-developers/building-a-video-player-app-in-android-part-1-5-d95770ef762d

## Overview of using ExoPlayer
`SimpleExoPlayer`と`MediaSource`がビデオファイルを再生するのに必要になる。
`SimpleExoPlayer`を作成するには`track selector`(どのファイルやどの言語でどの音声で再生するか決める)がいる。
`MediaSource`クラスを使うことでmp4とかmp3とかのUriを読み込める。(HLSを再生できる`HlsMediaSource`とかもある。)player.playWhenReadyをtrueにするとデータが有ると再生する。

そして`PlayerView`にプレーヤーをアタッチしてあげる必要がある。`PlayerView`はUIコントロールも提供する。動画のソースを提供する前にUIを用意する方が良い。なぜなら再生されている間にアタッチされるようなことがあり得るため。
またplayerの準備が必要でロードのスタートを知らせる。(バッファリングに時間がかかる可能性があるため。)
playerのplayWhenReadyにtrueをセットするとデータが読み込まれた時に再生を行う。
Proguardをかけてサイズを減らそう。

## Create the ExoPlayer instance

このコードはplayerをデフォルトのオプションで作っている。そして`PlayerView`にアタッチしている。
https://gist.github.com/nazmulidris/6a40763185ed0653320d8efae66256bc#file-create-ep-instance-kt

## Loading files locally from APK using ExoPlayer
`DefaultDataSource`は以下のUriのロードに対応している。

```
file:///
asset:///
content:///
rtmp
data
http(s)
```

以下のようにローカルファイルをロードできる(assetフォルダーにネストした形でフォルダを作れる)

```
Uri.parse(“file:///android_asset/video/video.mp4”)
Uri.parse(“asset:///video/video.mp4”)
```

RawResourceDataSourceを使うとres/rawのなかに置いてアクセスできる
`RawResourceDataSource.buildRawResourceUri(R.raw.my_media_file) `

## Release ExoPlayer resources
コーデックやネットワークやメモリを利用しているので再生が完了したときplayerを終了させる必要がある。システムコーデックはシステム内でシェアされていて、OSや端末によって限られているため、それを開放することは重要である。以下のコードで同じExoPlayerを再利用できる。
https://gist.github.com/nazmulidris/6bb12dcf8e0b67e43f4d47ae0f18176b#file-ep-release-kt
これはplayerにより確保されている全てのリソースを開放している(コーデックやメディアソースなど)。もう一度playerを利用するときは`prepare(MediaSource)`を呼び、そして`playWhenReady`をセットする。
`ExoPlayer.release()`は1つを除いてstop()と同じ動きをします。再生スレッドを停止し、ExpPlayerのインスタンスの再利用を防ぐ。ReleaseはActivity.onDestroyやService.onDestroyなどplayerがもう使われない時に呼び出すべき。

## Activity Lifecycle Integration
作成して、利用し、リリースするためにActivityのライフサイクルを利用する必要がある。
シンプルな例が以下になる。
https://gist.github.com/nazmulidris/8e1e8b3cf67ae9b563e4dbe699847d01#file-ep-video-activity-kt

## Saving player state between onStart() and onStop()
PlayerStateデータクラスはplayerが最初に読み込まれる前に、playerの状態を読み込むために利用される。Playerがリリースされた時Playerの状態はこのクラスのオブジェクトに保存される。新しいPlayerを作成した時にこのシンプルな状態オブジェクトを利用して前回やめた位置から再開する。
https://gist.github.com/nazmulidris/62f45c3eaa9c77bb7a8cb8d77369261f#file-player-state-kt

UIの観点からはこれはアプリの実行中何かを再生していて、ホームボタンを押し、playerリソースがリリースされ、アプリに戻ってきた時にplayerが再度初期化され、前回の状態がリストアされ、やめたところから再開できる。
どのようにその保存と復元をやるかは以下のコードで行っている。
https://gist.github.com/nazmulidris/6d02ac7e4f64ad86c61a2d081c18ca49#file-playerholder-release-kt

## A little more control over player creation
playerをカスタマイズするためにExoPlayerFactor.newSimpleInstanceの別のシグネチャを利用できる。例えば`DefaultLoadControl`クラスを使うことでExoPlayerのbuffering policyを変更することが出来る。
https://gist.github.com/nazmulidris/f1d66dd5f5962aa187909fec9eaaf687#file-ep-creation-extra-kt
もっと複雑なユースケースでは`ExoPlayerFactory.newSimpleInstance(…)`ファクトリーメソッドの全ての引数に、自分の実装を渡すことが出来る。これによりExoPlayerで大きく拡張性を得ることが出来る。

# ExoPlayer playlists, UI customization, and events(Part 2)
https://medium.com/google-developers/building-a-video-player-app-in-android-part-2-5-e5a5392879fa
## Creating playlists
一つのExtractorMediaSource(buildMediaSource(Uri)を使う方法)を使う代わりに、DynamicConcatenatingMediaSourceを使うことが出来る。MediaSourceオブジェクトをつなげて利用することが出来る。これがサンプルになる。
https://gist.github.com/nazmulidris/82cebffca8fbd159382fb2c0d89caf69#file-ep-playlist-kt

`DynamicConcatenatingMediaSource`は動的にプレイリストを作る。もし静的なプレイリストを作りたければ、`ContactenatingMediaSource`を使うことが出来る。どちらもシームレスにメディアをつなげ、プレイリスト全体のバッファリングを処理する。`MediaSource`の構成の詳細を知るためには[この記事](https://medium.com/google-exoplayer/dynamic-playlists-with-exoplayer-6f53e54a56c0)を読むと良い。


## Customizing the UI
ExoPlayerインスタンスをPlayerViewにアタッチ出来る。PlayerViewのレイアウトの例を示す。
ビデオの早送りや巻き戻しそして他のもっと多くの事ができる。[ExoPlayerのJavaDoc](http://google.github.io/ExoPlayer/doc/reference/index.html?com/google/android/exoplayer2/ui/SimpleExoPlayerView.html)で全てをみることができる。
https://gist.github.com/nazmulidris/f4a1fc64aa52d01e2844ee4218ca890c#file-ep-custom-layout-xml
コントローラーを使わない場合は`app:use_controller=”false” `を利用する。`PlayerView`は自動的にmedia controller UIを表示する。これらはユーザーに再生、一時停止、スキップなどを提供する。`show_timeout`を使うことで、このコントローラーがどのぐらいの間表示されるかを設定できる。
コントローラーのUIをカスタマイズするために、`controller_layout_id`を使うことが出来る。これがサンプルとなる。
https://gist.github.com/nazmulidris/d9c92c56bc6d7fb5c83759537575257a#file-ep-controller-ui-xml
PlayerView自身の前に覆って表示される。再生、一時停止、スキップなどを追加したり、削除したりすることができる。ExoPlayerによって提供されているIDを利用することで、ExoPlayerが知ることが出来る。PlayerViewのカスタマイズに関しては[この記事](https://medium.com/google-exoplayer/customizing-exoplayers-ui-components-728cf55ee07a)を読んで欲しい。

## Listening to player events for UX
`ExoPlayer.EventListener`インターフェースを介して、たくさんの価値のある情報を提供する。これをインターフェースを実装するかサブクラスの`Player.DefaultEventListener`を実装することで、Playerの状態が変わった時に受け取ることが出来る。また、`VideoRendererEventListener`と`AudioRendererEventListener`を実装することができ、これにより`audio`や`video`のレンダリングの詳細を取得することが出来る。
それぞれを利用することで、アプリのユーザーにとってquality of experience (QoE)がどのように影響を受けているか知ることができる。

これらを利用するサンプル

* `STATE_BUFFERING`とともに`ExoPlayer.EventListener.OnPlaybackStateChanged()`が呼ばれた時に、もし再生開始時や、ユーザーがまだ再生可能でない場所を指定した場合でなければ、QoEにとって有害であると考えられる。
* ユーザーによって、再生が開始されてから、`ExoPlayer.VideListener.onFirstFrameRendered`が呼ばれるまでにかかった時間は、再生の最初の時間となる。良いQoEのためには少ないほうが望ましい。
* `VideoRendererEventListener.onDroppedFrames`はframe落ちに関しての情報を提供する。とても多くのこのイベントはQoEに悪い影響をもたらす。

この記事では詳細をカバーしない。ExoPlayerのイベントとQoEシグナルをもっと知るためには[ExoPlayer codelab](https://codelabs.developers.google.com/codelabs/exoplayer-intro/#5)のMeasure QoE sectionを必ず行ってください。Playerの再生、バッファリング、一時停止中を深く理解するためには[このStackOverflow](https://stackoverflow.com/questions/47731779/detect-pause-resume-in-exoplayer/48067205#48067205)を参照してください。

## Adaptive streaming
ExoPlayerはAPKやネットワークからメディアファイルを読み込むだけでなく、adaptive streamingを広範囲にサポートしている。adaptive streamingはビデオと音声を所定の期間の小さいチャンクにカットする。ExoPlayerはそれを再生のためにつなげる。それぞれのチャンクは異なる品質(サイズまたはビットレート)が利用できる。プレーヤーはデバイスの性能やネットワークの帯域によってその品質を選択する。プレーヤーは低画質から再生を開始し、帯域が利用可能になれば良い画質に切り替える(例えば遅いモバイルネットワークからWiFiに切り替えるなど)

HLS(HTTP Live Streaming)やMPEG-DASH (Dynamic Adaptive Streaming over HTTP)やSmoothStreamingについて[MDN記事](https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Setting_up_adaptive_streaming_media_sources)で学ぶことが出来る。DASH and HLSの違いについて学ぶには[このExoplayerブログ](https://medium.com/google-exoplayer/test-8b62d50362ef)を確認してほしい。これらの記事ではadaptive streamingにExoPlayerを利用することはないが、もっと学びたい場合は、[ExoPlayer codelab](https://codelabs.developers.google.com/codelabs/exoplayer-intro/#4)を確認して欲しい。