as

Settings
Sign out
Notifications
Alexa
Amazonアプリストア
AWS
ドキュメント
Support
Contact Us
My Cases
開発
設計と開発
公開
リファレンス
サポート

Hls.jsプレーヤーを使用したアダプティブコンテンツの再生

Hls.jsプレーヤーを使用したアダプティブコンテンツの再生

次の手順では、Hls.jsプレーヤーをMSEモードで使用して、アダプティブストリーミングコンテンツを再生する方法を示しています。

Amazonから提供されるHls.jsプレーヤーパッチは特定のバージョンのプレーヤーを対象としていますが、任意のバージョンのHls.jsプレーヤーに移植することができます。Amazonでは、特定のバージョンのHls.jsプレーヤーを使用するように要求する規定は設けていません。開発者は、独自の要件に合わせて最適なHls.jsプレーヤーのバージョンを決定できます。Hls.jsプレーヤーによるコンテンツの処理に関する問題については、オープンソースコミュニティに問い合わせてください。

Hls.jsプレーヤーとサポートされるさまざまな構成の詳細については、Hls.jsプレーヤーに関するページ(英語のみ)を参照してください。

前提条件

Hls.jsプレーヤーでアダプティブコンテンツを再生できるようにコードを変更する前に、次の前提条件を満たしていることを確認し、アプリとプレーヤーを設定します。

Vega向けHls.jsプレイヤーの構成

  1. 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.4 - HLSパーサーのパフォーマンスが向上しました。

  • v1.5.11-r1.3

  1. 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

  1. /hls-rel/scriptsディレクトリに移動します。
  2. 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プレーヤーを手動で統合する方法

  1. https://github.com/video-dev/hls.jsからHls.jsパッケージのクローンを作成します。

    クリップボードにコピーしました。

    cd <ルートディレクトリ>
    git clone https://github.com/video-dev/hls.js.git
    
  2. v1.5.11ベースのgitブランチを、v1.5.11-keplerという名前のローカルブランチにチェックアウトします。

    クリップボードにコピーしました。

     cd hls.js
     git checkout -b amz_1.5.11 v1.5.11
    
  3. Vega Hls.jsプレーヤーパッケージを、ファイルの展開先となる既知の場所にダウンロードします。
  4. ファイルを展開します。

    クリップボードにコピーしました。

    tar -xzf hls-rel-v[x.y.z]-r[x.y].tar.gz
    
  5. Hls.jsパッチを適用します。

    クリップボードにコピーしました。

    git apply hls-rel/hls-patch/*.patch -3
    
  6. npm installを実行してHls.jsの依存関係をインストールします。

    クリップボードにコピーしました。

    npm install
    
  7. npm run buildを実行してHls.jsプレーヤーをビルドします。

    クリップボードにコピーしました。

     npm run build  
    

注: ビルドでbase-64およびxmldomノードモジュールを解決できないというエラーが発生した場合は、次のコマンドを実行してこれらのモジュールをインストールします。

クリップボードにコピーしました。

npm install --save base-64   
npm install --save xmldom

Last updated: 2025年9月30日