読者です 読者をやめる 読者になる 読者になる

ExoPlayer 2 に関するメモ

2016/9/28 に ExoPlayer r2.0.0 がリリースされました。

また、 ExoPlayer は medium に開発ブログを書くようになったようです。 r2.0.0 がリリースされたのは結構前だけど、未だに追えていなかったので medium の記事を参考にしつつ調べた内容をメモっておきます。

ちなみに ExoPlayer 1.x の話は過去に書いたものもあるので、興味がある方はそちらも参照すると良いでしょう。

Q: なぜメジャーバージョンアップしたの?

A: 後方互換性を破壊したかったから

  • ExoPlayer 2.x - Why, what and when?
    • 元々 ExoPlayer は YouTube や GooglePlay ムービーのために作っていた
    • MPEG-DASH 再生に特化していたけど、オープンソース化以後どんどん進化して様々なフォーマットが利用できるようになった
    • 出来るだけ API を安定させたが、その一方で新しいフォーマットを扱うための効率は悪くなっていた
    • これを解消するためには API 互換性を破壊してでも、作り直す必要があった

ExoPlayer 2.x で変わったクラス

ExoPlayer 2.x - New package and class names

再設計するにあたって、複雑なクラスを分解したり、リネームしたものがまとめられている。

  • 1.x と 2.x でパッケージ名変えた
    • com.google.android.exoplayer2 というパッケージ名になった
    • 二つのプレイヤーを入れて徐々に移行していくこともできる
  • 旧 TrackRenderer は Interface にして Renderer という名前で定義しなおした
    • TrackRenderer 相当のものは BaseRenderer (implements Renderer) にある
  • 旧 SampleSource は複雑だったので MediaSource, MediaPeriod, SampleStream という 3 つになった
  • util.extensionsdecoder になった
  • MediaCodecRenderer は mediacodec 配下になった
    • MediaCodecAudioRenderer は audio 配下になった
    • MediaCodecVideoRenderer は video 配下になった
  • FrameworkSampleSource は廃止された
  • MediaFormat は Format になった

MediaSource Composition

ExoPlayer 2.x - MediaSource composition

  • ExoPlayer 2 では SampleSource の代わりに MediaSource を作る必要がある
    • ExtractorMediaSrouce とか HlsMediaSource のように単一のメディアファイルを再生するクラス
    • MergingMediaSource, LoopingMediaSource, ConcatenatingMediaSource というのも出来た

MergingMediaSource

別々の MediaSource を合成して再生する。以下の場合だと、動画に別ファイルの字幕データをマージしている。

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

LoopingMediaSource

  • シームレスなループ再生ができる
  • 動画をループ再生するときに onFinished()seekTo(0)play() みたいにしなくてよくなった
    • この方法だと position = 0 の位置を再度バッファリングする場合がある
    • LoopingMediaSource を使えば、動画の終わり preload が行なわれてシームレスに再生することが出来る

ConcatenatingMediaSource

  • 複数の動画を繋げてシームレスに再生することができる
    • プレイリストみたいな感じになる
    • 異なるフォーマットでも concat できる
      • e.g.) 480p の H.264 の後に 720p の VP9 を再生するとか
  • ConcatenatingMediaSource した動画を LoopingMediaSource に設定するとかも出来る

New audio features

ExoPlayer 2.x - New audio features

  • 動画だけで無く音声も良い感じになった
    • 音楽プレイヤーを作るときにも使える
  • 簡単にギャップレス再生ができるようになった
    • mp3 や aac ファイルのメタデータを見て、次の曲を予めバッファリングしてシームレスに再生する機能
  • MediaCodec 以外のデコーダを NativeLibrary 経由で利用して音声を再生できるようになった
    • FFmpeg
    • libopus
    • libflac

Track Selection

ExoPlayer 2.x - Track selection

  • Track selector を実装できるようになった
  • 映画のような複数の音声トラックや字幕トラックが入っているメディアを切り替えができる
  • HLS のような AdaptiveStreaming の Track selection も出来る
    • アプリの要件 (モバイル回線では低画質にしておきたいとか) で個別に m3u8 ファイルを作らなくても柔軟に切り替えることができる
      • ExoPlayer2 の DemoApp では HLS の Track selection を試すことができる
  • Track selector を実装できるようになったので複雑な select ロジックを実現できるようになった
    • 端末の設定言語じゃない映像ファイルの場合は字幕を出すとか

SimpleExoPlayer/SimpleExoPlayerView

  • 簡単につかうための便利クラスができた
    • ExoPlayer 1.x はプレイヤーの下準備が多く、 DemoPlayer というクラスを参考にして利用していた
    • ちなみに VideoView ほどコードは短かくならないけど、最初から View のリサイズや、コントローラがついている
// TrackSelector, LoadControl を指定して SimpleExoPlayer を作る
Handler mainHandler = new Handler();
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
        new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
        new DefaultTrackSelector(mainHandler, videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);

// HLS の URL を指定して MediaSource を作る
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this,
        Util.getUserAgent(this, "TestApp/0.1"), bandwidthMeter);
MediaSource videoSource = new HlsMediaSource(
        Uri.parse(url),
        dataSourceFactory,
        5,
        null,
        null);

// 再生する
player.prepare(videoSource);
player.setPlayWhenReady(true);
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
    android:id="@+id/video"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:use_texture_view="true" />

所感

  • ExoPlayer 2 の大きな部分としてプレイリストを扱えるようになったと言うの大きいかなと思った
    • このお陰で LoopingMediaSource, ConcatenatingMediaSource, audio のギャップレス再生のような、シームレスに次のメディアファイルを再生するという機能が実現されているように思える
      • 実装はまだ追い掛けられていないので本当にそうなのかは不明
  • あと Track selector を実装できるようになったのは凄い
    • 画質ごとに m3u8 ファイルを用意する必要はなくなって便利