ExoPlayer は、複数のコンテナ形式の HLS をサポートしています。含まれる音声と動画のサンプル フォーマットもサポートされている必要があります(詳しくは、サンプル フォーマットのセクションをご覧ください)。こちらのブログ投稿で説明されているように、HLS コンテンツの制作者は高品質の HLS ストリームを生成することを強くおすすめします。
機能 | サポート対象 | コメント |
---|---|---|
コンテナ | ||
MPEG-TS | ○ | |
FMP4/CMAF | ○ | |
ADTS(AAC) | ○ | |
MP3 | ○ | |
字幕 / クローズド キャプション | ||
CEA-608 | ○ | |
CEA-708 | ○ | |
WebVTT | ○ | |
メタデータ | ||
ID3 | ○ | |
SCTE-35 | いいえ | |
コンテンツの保護 | ||
AES-128 | ○ | |
AES-128 のサンプル | いいえ | |
Widevine | ○ | API 19 以降(「cenc」スキーム)および 25 以降(「cbcs」スキーム) |
PlayReady SL2000 | ○ | Android TV のみ |
サーバー制御 | ||
差分更新 | ○ | |
再生リストの再読み込みをブロック | ○ | |
プリロード ヒントの読み込みをブロック | ○ | 長さが未定義の byterange を除く |
広告挿入 | ||
サーバーガイド付き広告挿入 (インタースティシャル) | 部分的 | X-ASSET-URI の VOD のみ。ライブ配信と X-ASSET-LIST は後日追加されます。 |
IMA サーバーサイド広告とクライアントサイド広告 | ○ | 広告挿入ガイド |
ライブ再生 | ||
通常のライブ再生 | ○ | |
低遅延 HLS(Apple) | ○ | |
低レイテンシ HLS(コミュニティ) | いいえ | |
共通メディア クライアント データ CMCD | ○ | CMCD 統合ガイド |
MediaItem の使用
HLS ストリームを再生するには、HLS モジュールに依存する必要があります。
Kotlin
implementation("androidx.media3:media3-exoplayer-hls:1.7.1")
Groovy
implementation "androidx.media3:media3-exoplayer-hls:1.7.1"
次に、HLS 再生リスト URI の MediaItem
を作成して、プレーヤーに渡すことができます。
Kotlin
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri))
// Prepare the player.
player.prepare()
Java
// Create a player instance.
ExoPlayer player = new ExoPlayer.Builder(context).build();
// Set the media item to be played.
player.setMediaItem(MediaItem.fromUri(hlsUri));
// Prepare the player.
player.prepare();
URI が .m3u8
で終わらない場合は、MediaItem.Builder
の setMimeType
に MimeTypes.APPLICATION_M3U8
を渡して、コンテンツのタイプを明示的に示すことができます。
メディア アイテムの URI は、メディア プレイリストまたはマルチバリアント プレイリストのいずれかを指す場合があります。URI が複数の #EXT-X-STREAM-INF
タグを宣言するマルチバリアント プレイリストを指している場合、ExoPlayer は利用可能な帯域幅とデバイスの機能の両方を考慮して、バリアント間で自動的に適応します。
HlsMediaSource を使用する
カスタマイズ オプションをさらに追加するには、HlsMediaSource
を作成して、MediaItem
の代わりにプレーヤーに直接渡します。
Kotlin
// Create a data source factory.
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
// Create a HLS media source pointing to a playlist uri.
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri))
// Create a player instance.
val player = ExoPlayer.Builder(context).build()
// Set the HLS media source as the playlist with a single media item.
player.setMediaSource(hlsMediaSource)
// Prepare the player.
player.prepare()
Java
// Create a data source factory.
DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory();
// Create a HLS media source pointing to a playlist uri.
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri));
// Create a player instance.
ExoPlayer player = new ExoPlayer.Builder(context).build();
// Set the HLS media source as the playlist with a single media item.
player.setMediaSource(hlsMediaSource);
// Prepare the player.
player.prepare();
マニフェストへのアクセス
現在のマニフェストを取得するには、Player.getCurrentManifest
を呼び出します。HLS の場合は、返されたオブジェクトを HlsManifest
にキャストする必要があります。また、マニフェストが読み込まれるたびに、Player.Listener
の onTimelineChanged
コールバックも呼び出されます。オンデマンド コンテンツの場合は 1 回、ライブ コンテンツの場合は複数回発生する可能性があります。次のコード スニペットは、マニフェストが読み込まれるたびにアプリが何らかの処理を行う方法を示しています。
Kotlin
player.addListener(
object : Player.Listener {
override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) {
val manifest = player.currentManifest
if (manifest is HlsManifest) {
// Do something with the manifest.
}
}
}
)
Java
player.addListener(
new Player.Listener() {
@Override
public void onTimelineChanged(
Timeline timeline, @Player.TimelineChangeReason int reason) {
Object manifest = player.getCurrentManifest();
if (manifest != null) {
HlsManifest hlsManifest = (HlsManifest) manifest;
// Do something with the manifest.
}
}
});
インタースティシャルを含む HLS ストリームを再生する
HLS 仕様では、メディア再生リストにインタースティシャル情報を含めるために使用できる HLS インタースティシャルが定義されています。ExoPlayer はデフォルトでこれらのインタースティシャルを無視します。サポートは HlsInterstitialsAdsLoader
を使用して追加できます。仕様のすべての機能が最初からサポートされるわけではありません。ストリームのサポートが不足している場合は、GitHub で問題を報告し、ストリーム URI をお送りください。ストリームのサポートを追加いたします。
プレイリスト API で MediaItem
を使用する
インタースティシャルを含む HLS ストリームを再生する最も便利な方法は、HlsInterstitialsAdsLoader.AdsMediaSourceFactory
を使用して ExoPlayer インスタンスをビルドすることです。これにより、Player
インターフェースの MediaItem
ベースのプレイリスト API を使用して HLS インタースティシャルを再生できます。
プレーヤー インスタンスのビルド時に、ExoPlayer
の MediaSource.Factory
をビルダーに挿入できます。
Kotlin
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
var hlsMediaSourceFactory =
HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader,
playerView,
DefaultMediaSourceFactory(context),
)
// Build player with interstitials media source factory
player =
ExoPlayer.Builder(context)
.setMediaSourceFactory(hlsMediaSourceFactory)
.build()
// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player)
playerView.setPlayer(player)
Java
hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Create a MediaSource.Factory for HLS streams with interstitials.
MediaSource.Factory hlsMediaSourceFactory =
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader, playerView, new DefaultMediaSourceFactory(context));
// Build player with interstitials media source factory
player =
new ExoPlayer.Builder(context)
.setMediaSourceFactory(hlsMediaSourceFactory)
.build();
// Set the player on the ads loader.
hlsInterstitialsAdsLoader.setPlayer(player);
playerView.setPlayer(player);
このようなプレーヤーの設定では、HLS インタースティシャルを再生するには、プレーヤーで AdsConfiguration
を使用してメディア アイテムを設定するだけです。
Kotlin
player.setMediaItem(
MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0") // must be unique within playlist
.build())
.build())
player.prepare();
player.play();
Java
player.setMediaItem(
new MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
new AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0") // must be unique within playlist
.build())
.build());
player.prepare();
player.play();
メディアソース ベースの API を使用する
または、デフォルトのメディアソース ファクトリをオーバーライドせずに ExoPlayer インスタンスをビルドすることもできます。インタースティシャルをサポートするために、アプリは HlsInterstitialsAdsLoader.AdsMediaSourceFactory
を直接使用して MediaSource
を作成し、メディアソース ベースのプレイリスト API を使用して ExoPlayer に提供できます。
Kotlin
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context)
// Create a MediaSource.Factory for HLS streams with interstitials.
var hlsMediaSourceFactory =
HlsInterstitialsAdsLoader.AdsMediaSourceFactory(hlsInterstitialsAdsLoader, playerView, context)
// Build player with default media source factory.
player = new ExoPlayer.Builder(context).build();
// Create an media source from an HLS media item with ads configuration.
val mediaSource =
hlsMediaSourceFactory.createMediaSource(
MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0")
.build()
)
.build()
)
// Set the media source on the player.
player.setMediaSource(mediaSource)
player.prepare()
player.play()
Java
HlsInterstitialsAdsLoader hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Create a MediaSource.Factory for HLS streams with interstitials.
MediaSource.Factory hlsMediaSourceFactory =
new HlsInterstitialsAdsLoader.AdsMediaSourceFactory(
hlsInterstitialsAdsLoader, playerView, context);
// Build player with default media source factory.
player = new ExoPlayer.Builder(context).build();
// Create an media source from an HLS media item with ads configuration.
MediaSource mediaSource =
hlsMediaSourceFactory.createMediaSource(
new MediaItem.Builder()
.setUri("https://www.example.com/media.m3u8")
.setAdsConfiguration(
new MediaItem.AdsConfiguration.Builder(Uri.parse("hls://interstitials"))
.setAdsId("ad-tag-0")
.build())
.build());
// Set the media source on the player.
exoPlayer.setMediaSource(mediaSource);
exoPlayer.prepare();
exoPlayer.play();
広告イベントをリッスンする
Listener
を HlsInterstitialsAdsLoader
に追加して、HLS インタースティシャル再生に関するステータス変更のイベントをモニタリングできます。これにより、アプリや SDK は、再生された広告、読み込まれているアセット リスト、準備中の広告メディア ソースをトラッキングしたり、アセット リストの読み込みエラーや広告の準備エラーを検出したりできます。また、広告メディア ソースから出力されたメタデータを受信して、広告再生のきめ細かい検証や広告再生の進行状況のトラッキングを行うことができます。
Kotlin
class AdsLoaderListener : HlsInterstitialsAdsLoader.Listener {
override fun onStart(mediaItem: MediaItem, adsId: Any, adViewProvider: AdViewProvider) {
// Do something when HLS media item with interstitials is started.
}
override fun onMetadata(
mediaItem: MediaItem,
adsId: Any,
adGroupIndex: Int,
adIndexInAdGroup: Int,
metadata: Metadata,
) {
// Do something with metadata that is emitted by the ad media source of the given ad.
}
override fun onAdCompleted(
mediaItem: MediaItem,
adsId: Any,
adGroupIndex: Int,
adIndexInAdGroup: Int,
) {
// Do something when ad completed playback.
}
// ... See JavaDoc for further callbacks of HlsInterstitialsAdsLoader.Listener.
override fun onStop(mediaItem: MediaItem, adsId: Any, adPlaybackState: AdPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
Java
private class AdsLoaderListener
implements HlsInterstitialsAdsLoader.Listener {
// implement HlsInterstitialsAdsLoader.Listener
@Override
public void onStart(MediaItem mediaItem, Object adsId, AdViewProvider adViewProvider) {
// Do something when HLS media item with interstitials is started.
}
@Override
public void onMetadata(
MediaItem mediaItem,
Object adsId,
int adGroupIndex,
int adIndexInAdGroup,
Metadata metadata) {
// Do something with metadata that is emitted by the ad media source of the given ad.
}
@Override
public void onAdCompleted(
MediaItem mediaItem, Object adsId, int adGroupIndex, int adIndexInAdGroup) {
// Do something when ad completed playback.
}
// ... See JavaDoc for further callbacks
@Override
public void onStop(MediaItem mediaItem, Object adsId, AdPlaybackState adPlaybackState) {
// Do something with the resulting ad playback state when stopped.
}
}
使用可能なすべてのコールバックの詳細なドキュメントについては、HlsInterstitialsAdsLoader.Listener
の JavaDoc をご覧ください。
リスナーを広告ローダーに追加できます。
Kotlin
var listener = AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
Java
AdsLoaderListener listener = new AdsLoaderListener();
// Add the listener to the ads loader to receive ad loader events.
hlsInterstitialsAdsLoader.addListener(listener);
HlsInterstitialsAdsLoader
ライフサイクル
HlsInterstitialsAdsLoader
または HlsInterstitialsAdsLoader.AdsMediaSourceFactory
のインスタンスは、広告を読み込む必要がある複数のメディアソースを作成する複数のプレーヤー インスタンスで再利用できます。
たとえば、Activity
の onCreate
メソッドでインスタンスを作成し、複数のプレーヤー インスタンスで再利用できます。これは、同時に 1 つのプレーヤー インスタンスで使用されている場合に機能します。これは、アプリがバックグラウンドに移行し、プレーヤー インスタンスが破棄されてから、アプリが再びフォアグラウンドに移行したときに新しいインスタンスが作成されるという一般的なユースケースで役立ちます。
Kotlin
// Create the ads loader instance (for example onCreate).
hlsInterstitialsAdsLoader = HlsInterstitialsAdsLoader(context);
// Build a player and set it on the ads loader (for example onStart).
player = ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Build another player and set it on the ads loader (for example onStart).
player = ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Release the ads loader when not used anymore (for example onDestroy).
hlsInterstitialsAdsLoader.release();
Java
// Create the ads loader instance (for example onCreate).
hlsInterstitialsAdsLoader = new HlsInterstitialsAdsLoader(context);
// Build a player and set it on the ads loader (for example onStart).
player = new ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Build another player and set it on the ads loader (for example onStart).
player = new ExoPlayer.Builder(context).build();
hlsInterstitialsAdsLoader.setPlayer(player);
// Release the player and unset it on the ads loader (for example onStop).
player.release();
hlsInterstitialsAdsLoader.setPlayer(null);
// Release the ads loader when not used anymore (for example onDestroy).
hlsInterstitialsAdsLoader.release();
一般に、広告ローダに次のプレーヤー インスタンスを設定する前に、古いプレーヤー インスタンスを解放してください。広告ローダー自体がリリースされると、広告ローダーは使用できなくなります。
再生をカスタマイズする
ExoPlayer には、アプリのニーズに合わせて再生エクスペリエンスを調整するための複数の方法が用意されています。例については、カスタマイズ ページをご覧ください。
チャンクレス準備を無効にする
デフォルトでは、ExoPlayer はチャンクレス準備を使用します。つまり、ExoPlayer はマルチバリアント プレイリストの情報のみを使用してストリームを準備します。これは、#EXT-X-STREAM-INF
タグに CODECS
属性が含まれている場合に機能します。
メディア セグメントに、#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS
タグを使用してマルチバリアント プレイリストで宣言されていない多重化されたクローズド キャプション トラックが含まれている場合は、この機能を無効にする必要があります。そうしないと、これらの字幕トラックは検出されず、再生されません。次のスニペットに示すように、HlsMediaSource.Factory
でチャンクなしの準備を無効にできます。ExoPlayer はこれらの追加トラックを検出するためにメディア セグメントをダウンロードする必要があるため、起動時間が長くなります。そのため、代わりに多変量プレイリストでクローズド キャプション トラックを宣言することをおすすめします。
Kotlin
val hlsMediaSource =
HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri))
Java
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(false)
.createMediaSource(MediaItem.fromUri(hlsUri));
高品質の HLS コンテンツを作成する
ExoPlayer を最大限に活用するために、HLS コンテンツを改善するためのガイドラインがあります。詳細については、ExoPlayer での HLS 再生に関する Medium の投稿をご覧ください。主なポイントは次のとおりです。
- 正確なセグメントの長さを使用します。
- 連続したメディア ストリームを使用します。セグメント間でメディア構造が変化しないようにします。
#EXT-X-INDEPENDENT-SEGMENTS
タグを使用します。- 動画と音声の両方を含むファイルではなく、デマルチプレックスされたストリームを優先します。
- マルチバリアント再生リストに、可能な限りすべての情報を含めます。
ライブ ストリームには、次のガイドラインが適用されます。
#EXT-X-PROGRAM-DATE-TIME
タグを使用します。#EXT-X-DISCONTINUITY-SEQUENCE
タグを使用します。- ライブ ウィンドウを長くします。1 分以上が理想的です。