Hls.jsプレーヤーを使用したアダプティブコンテンツの再生
次の手順では、Hls.jsプレーヤーをMSEモードで使用して、アダプティブストリーミングコンテンツを再生する方法を示しています。
Amazonから提供されるHls.jsプレーヤーパッチは特定のバージョンのプレーヤーを対象としていますが、任意のバージョンのHls.jsプレーヤーに移植することができます。Amazonでは、特定のバージョンのHls.jsプレーヤーを使用するように要求する規定は設けていません。開発者は、独自の要件に合わせて最適なHls.jsプレーヤーのバージョンを決定できます。Hls.jsプレーヤーによるコンテンツの処理に関する問題については、オープンソースコミュニティに問い合わせてください。
Hls.jsプレーヤーとサポートされるさまざまな構成の詳細については、Hls.jsプレーヤーに関するページ(英語のみ)を参照してください。
前提条件
Hls.jsプレーヤーでアダプティブコンテンツを再生できるようにコードを変更する前に、次の前提条件を満たしていることを確認し、アプリとプレーヤーを設定します。
- W3Cメディアプレーヤーを使用するようにアプリを設定します。詳細については、メディアプレーヤーのセットアップを参照してください。
Vega向けHls.jsプレイヤーの構成
-
Vega向けHls.js Playerを既知の場所にダウンロードします。
Vegaは以下のHls.jsバージョンをサポートしています。
- v1.5.11-r1.5 - ヘッドレスJS再生をサポートするようにポリフィルを更新しました。インポートを
@amazon-devices/react-native-w3cmediaから@amazon-devices/react-native-w3cmedia/dist/headlessに変更しました。
- v1.5.11-r1.5 - ヘッドレスJS再生をサポートするようにポリフィルを更新しました。インポートを
-
Hls.jsプレーヤーパッケージを展開します。
tar -xzf hls-rel-v<x.y.z>-r<a.b>.tar.gz次に例を示します。
tar -xzf hls-rel-v1.5.11-r1.5.tar.gz - /hls-rel/scriptsディレクトリに移動します。
- setup.shヘルパースクリプトを実行します。
./setup.shsetup.shスクリプトはhls.jsという名前のディレクトリを生成するビルドを実行します。- 生成されたhls.jsディレクトリから、hls-rel/src/*ディレクトリの内容を<アプリのルート>/src/*にコピーします。
- 生成されたhls.jsディレクトリから、distディレクトリを<アプリのルート>/src/hlsjsplayer/distにコピーします。
アダプティブコンテンツの再生
ビデオコンポーネントがマウントされたら、次の手順を実行してHls.jsプレーヤーを読み込みます。
Hls.jsプレーヤーでアダプティブコンテンツを再生する方法
-
src/App.tsxを開き、コンテンツを以下のコードに置き換えます。
/* * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All rights reserved. * * 専有/機密情報。 使用にあたってはライセンス条項が適用されます。 */ import * as React from 'react'; import {useRef, useState, useEffect} from 'react'; import { Platform, useWindowDimensions, View, StyleSheet, TouchableOpacity, Text, } from 'react-native'; import { VideoPlayer, VegaVideoSurfaceView, VegaCaptionsView, } from '@amazon-devices/react-native-w3cmedia'; import { HlsJsPlayer } from './hlsjsplayer/HlsJsPlayer'; // アプリからビデオの再生APIを手動で呼び出す場合は、falseに設定します。 const AUTOPLAY = true; const DEFAULT_ABR_WIDTH: number = Platform.isTV ? 3840 : 1919; const DEFAULT_ABR_HEIGHT: number = Platform.isTV ? 2160 : 1079; const content = [ { secure: 'false', // true: セキュアなビデオバッファーを使用します。false: 非セキュアなビデオバッファーを使用します。 uri: 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths-hls/hls.m3u8', drm_scheme: '', // com.microsoft.playready, com.widevine.alpha drm_license_uri: '', // DRMライセンス取得サーバーのURL(コンテンツがDRMで保護されている場合にのみ必要) }, ]; export const App = () => { const player = useRef<any>(null); const videoPlayer = useRef<VideoPlayer | null>(null); const timeoutHandler = useRef<ReturnType<typeof setTimeout> | null>(null); const [buttonPress, setButtonPress] = useState(false); const [nextContent, setNextContent] = useState({index: 0}); // { index: number } // 再レンダリングのnextContentの状態を追跡 const nextContentRef = useRef<number>(0); // 全画面解像度でレンダリング const {width: deviceWidth, height: deviceHeight} = useWindowDimensions(); useEffect(() => { if (nextContent.index !== nextContentRef.current) { nextContentRef.current = nextContent.index; // <Video>コンポーネントを強制的に再レンダリングします。 initializeVideoPlayer(); setNextContent((prev) => { return {...prev}; }); } }, [nextContent]); useEffect(() => { console.log('app:AppPreBuffering v13.0を開始します'); initializeVideoPlayer(); }, []); const onEnded = async () => { console.log('app:onEndedを受け取りました'); player.current.unload(); player.current = null; await videoPlayer.current?.deinitialize(); removeEventListeners(); onVideoUnMounted(); setNextContent({index: (nextContent.index + 1) % content.length}); }; const onError = () => { console.log(`app: AppPreBuffering:エラーイベントリスナーが呼び出されました`); }; const setUpEventListeners = (): void => { console.log('app:イベントリスナーをセットアップします'); videoPlayer.current?.addEventListener('ended', onEnded); videoPlayer.current?.addEventListener('error', onError); }; const removeEventListeners = (): void => { console.log('app:イベントリスナーを削除します'); videoPlayer.current?.removeEventListener('ended', onEnded); videoPlayer.current?.removeEventListener('error', onError); }; const initializeVideoPlayer = async () => { console.log('app:initializeVideoPlayerが呼び出されました'); videoPlayer.current = new VideoPlayer(); // @ts-ignore global.gmedia = videoPlayer.current; await videoPlayer.current.initialize(); setUpEventListeners(); videoPlayer.current!.autoplay = false; initializeHls(); }; const onSurfaceViewCreated = (surfaceHandle: string): void => { console.log('app:サーフェスが作成されました'); videoPlayer.current?.setSurfaceHandle(surfaceHandle); videoPlayer.current?.play(); }; const onSurfaceViewDestroyed = (surfaceHandle: string): void => { videoPlayer.current?.clearSurfaceHandle(surfaceHandle); }; const onCaptionViewCreated = (captionsHandle: string): void => { console.log('app:キャプションビューが作成されました'); videoPlayer.current?.setCaptionViewHandle(captionsHandle); }; const initializeHls = () => { console.log('app: in initializePlayer() index = ', nextContent.index); if (videoPlayer.current !== null) { player.current = new HlsJsPlayer(videoPlayer.current); } if (player.current !== null) { player.current.load(content[nextContent.index], AUTOPLAY); } }; const onVideoUnMounted = (): void => { console.log('app: in onVideoUnMounted'); // @ts-ignore global.gmedia = null; videoPlayer.current = null; }; if (!buttonPress) { return ( <View style={styles.container}> <TouchableOpacity style={styles.button} onPress={() => { setButtonPress(true); }} hasTVPreferredFocus={true} activeOpacity={1}> <Text style={styles.buttonLabel}> Press to Play Video </Text> </TouchableOpacity> </View> ); } else { return nextContent.index === nextContentRef.current ? ( <View style={styles.videoContainer}> <VegaVideoSurfaceView style={styles.surfaceView} onSurfaceViewCreated={onSurfaceViewCreated} onSurfaceViewDestroyed={onSurfaceViewDestroyed} /> <VegaCaptionsView onCaptionViewCreated={onCaptionViewCreated} style={styles.captionView} /> </View> ) : ( <View style={styles.videoContainer}></View> ); } }; const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', backgroundColor: '#283593', justifyContent: 'center', alignItems: 'center', }, button: { alignItems: 'center', backgroundColor: '#303030', borderColor: 'navy', borderRadius: 10, borderWidth: 1, paddingVertical: 12, paddingHorizontal: 32, }, buttonLabel: { color: 'white', fontSize: 22, fontFamily: 'Amazon Ember', }, videoContainer: { backgroundColor: 'white', alignItems: 'stretch', }, surfaceView: { zIndex: 0, }, captionView: { width: '100%', height: '100%', top: 0, left: 0, position: 'absolute', backgroundColor: 'transparent', flexDirection: 'column', alignItems: 'center', zIndex: 2, } }); -
Vega SDKを使用してアプリをビルドし、デバイスまたはシミュレーターで実行してログを収集します。アプリを作成してシミュレーターで実行する方法の詳細については、Vegaアプリの作成およびVega仮想デバイスを参照してください。
Hls.jsプレーヤーを手動で統合する方法
- https://github.com/video-dev/hls.jsからHls.jsパッケージのクローンを作成します。
cd <ルートディレクトリ> git clone https://github.com/video-dev/hls.js.git - v1.5.11ベースのgitブランチを、v1.5.11-keplerという名前のローカルブランチにチェックアウトします。
cd hls.js git checkout -b amz_1.5.11 v1.5.11 - Vega Hls.jsプレーヤーパッケージを、ファイルの展開先となる既知の場所にダウンロードします。
- ファイルを展開します。
tar -xzf hls-rel-v[x.y.z]-r[x.y].tar.gz - Hls.jsパッチを適用します。
git apply hls-rel/hls-patch/*.patch -3 - npm installを実行してHls.jsの依存関係をインストールします。
npm install - npm run buildを実行してHls.jsプレーヤーをビルドします。
npm run buildビルドでbase-64およびxmldomノードモジュールを解決できないというエラーが発生した場合は、次のコマンドを実行してこれらのモジュールをインストールします。
npm install --save base-64bash npm install --save xmldom
関連トピック
- W3Cメディアプレーヤーの概要
- Dash.jsプレーヤーを使用したアダプティブコンテンツの再生
- Shaka Playerを使用したアダプティブコンテンツ(HLS/DASH)の再生
- メディアプレーヤーのプレイリストの再生
Last updated: 2025年9月30日

