GameWith Developer Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

ExoPlayerを使ってAndroidアプリに動画を入れた話 #GameWith #TechWith

はじめまして、GameWithでAndroidエンジニアをしているgiです。 iOSの攻略動画に続き、Androidもv2.1.0で攻略動画を見られるようになりました。

前回kyamさんが書いたiOSの記事:

tech.gamewith.co.jp

今回はExoPlayer(v2.9.6)の使い方について話をします。

目次

簡単の紹介

公式サイト: https://google.github.io/ExoPlayer/
Source code: https://github.com/google/ExoPlayer
ExoPlayerはGoogleが開発したアプリケーションレベルのMediaPlayerです。Libraryとして扱うため、AndroidのSource codeにはありません。

メリットとデメリット

メリット

  • DASH、SmoothStreamingなどMediaPlayerがサポートされてない動画もサポートしています
  • カスタマイズは簡単
  • アプリと一緒にアップデートできます

デメリット

  • Libraryですので、アプリのサイズが増えます
  • Android 4.1からの MediaCodec API に依存しているため、4.1以前は使えません

使い方

Gradle設定

GoogleとJcenterのリポジトリが必要です

    repositories {
        google()
        jcenter()
    }

dependencies

  // core、必須のdependency、ほかのdependencyは全部オプショナルです
  implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6'
  // hlsをサポートしたいときのdependency
  implementation 'com.google.android.exoplayer:exoplayer-hls:2.9.6'
  // smoothstreamingをサポートしたいときのdependency
  implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.9.6'
  // dashをサポートしたいときのdependency
  implementation 'com.google.android.exoplayer:exoplayer-dash:2.9.6'
  // デフォルトのUIを入れたdependency、自分でUIを書くのもできますが、これがあると便利です
  implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.6'

ほかにrtmp、flacなどのextensionもあります:https://github.com/google/ExoPlayer/tree/release-v2/extensions/

Java 8の設定

compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}

ExoPlayer v2.9.0以上はJava 8の設定が必要です。

playerのインスタンスを作る

  val player = ExoPlayerFactory.newSimpleInstance(context)

newSimpleInstanceメソッドが複数あって、ContextRenderersFactoryTrackSelectorLoadControlなどいろいろなカスタマイズができます。一番簡単なのはContextだけ設定して、ほかは全部デフォルトにするこのメソッドです。

playerをViewに設置する

exoplayer-uiを使っている場合

直接中のPlayerViewを使うことができます:

  playerView.setPlayer(player)

exoplayer-uiを使ってない場合

自分が書いたViewとplayerの連携を取る必要があります。

動画Url(mp4)を使ってMediaSourceを作る

  // 1つの動画
  val dataSourceFactory = DefaultDataSourceFactory(context, Util.getUserAgent(context, context.packageName))
  val mediaSource = ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(url))

  // 1つの動画を10回ループする
  val mediaSource = ...
  val loopingMediaSource = LoopingMediaSource(mediaSource, 10)

  // 3つの動画を連続で再生する
  val mediaSource1 = ...
  val mediaSource2 = ...
  val mediaSource3 = ...
  val concatenatingMediaSource = ConcatenatingMediaSource(mediaSource1, mediaSource2, mediaSource3)

hls、smoothstreaming、dashが必要なとき、それぞれのHlsMediaSourceSsMediaSourceDashMediaSourceを使う必要があります。

MediaSourceとplayerを組み合わせて動画を再生する

  player.prepare(mediaSource)

EventListenerを使ってplayerの状態変化を取る

  player.addListener(object : Player.EventListener{
    // タイムラインが変わった、再生が始まった、再生が止まった、再生がエラーになったなどの情報はここで取れます
  })

音量の設定

  player.setVolume(audioVolume)

audioVolumeは0〜1のfloat、0は音なし、1は最大。この設定は、あくまでplayerの音量設定です。デバイスの音量をOFFにしたら、setVolumeで最大に設定しても、音が出ません。

動画のplayとpause

  // play
  player.setPlayWhenReady(true)

  // pause
  player.setPlayWhenReady(false)

動画画面を閉じるときの処理

  player.release()
  player = null

UIのカスタマイズ

exoplayer-uiを使っている場合

  • Libraryにあるexo_simple_player_view.xmlを参照して、自分のUIをカスタマイズする、exo_simple_player_view.xmlのコード:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">

  <com.google.android.exoplayer2.ui.AspectRatioFrameLayout android:id="@id/exo_content_frame"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_gravity="center">

    <!-- Video surface will be inserted as the first child of the content frame. -->

    <View android:id="@id/exo_shutter"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"/>

    <ImageView android:id="@id/exo_artwork"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"/>

    <com.google.android.exoplayer2.ui.SubtitleView android:id="@id/exo_subtitles"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <ProgressBar android:id="@id/exo_buffering"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:layout_gravity="center"/>

    <TextView android:id="@id/exo_error_message"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:gravity="center"
        android:background="@color/exo_error_message_background_color"
        android:padding="16dp"/>

  </com.google.android.exoplayer2.ui.AspectRatioFrameLayout>

  <FrameLayout android:id="@id/exo_ad_overlay"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

  <FrameLayout android:id="@id/exo_overlay"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>

  <View android:id="@id/exo_controller_placeholder"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>

</merge>

動画の場合、exo_content_frameが必須です。再生している動画を表示するTexureView/SurfaceViewがその中に入るためです。ほかのViewは全部なくっても問題ないです。別のIDが付いたViewを追加しても問題ないです。ただしその場合、そのViewを自分で制御しなければならないです。 コントローラーが欲しい場合、exo_controller_placeholderあるいはexo_controllerが必要です。

  • コントローラーをカスタマイズする場合、exo_playback_control_view.xmlを参照して、自分のUIをカタマイズする。

  • PlayerViewplayer_layout_idcontroller_layout_idを設定する

    <com.google.android.exoplayer2.ui.PlayerView
      android:id="@+id/player_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:player_layout_id="@layout/my_player_view"
      app:controller_layout_id="my_controller_view"
      />

exoplayer-uiを使ってない場合

すべてのUIを自分で作るため、特別な設定は必要ないです。

まとめ

以上がExoPlayerの簡単な使い方です。あまり複雑なものが必要ないなら、結構使いやすいLibraryです。また、Github上のdemoにはいろいろな複雑な機能を実装しています。とても勉強になります。

終わりに

GameWithアプリチームでは一緒にアプリをよくしていく仲間を募集中です! 興味がありましたら以下からご連絡をいただけるとありがたいです。

www.wantedly.com