as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

媒体播放器播放列表播放

媒体播放器播放列表播放

本主题提供了示例,说明如何在onEnded属性上实现JavaScript逻辑以在第一个视频完成后自动开始播放第二个视频。

先决条件

将您的应用设置成使用WC3媒体播放器。有关更多信息,请参阅媒体播放器设置

整合播放列表

在App.tsx中,按照代码示例所示进行修改。它将内容转换为内容数组并添加另一个媒体项目条目。然后,它会注册onEnded属性,卸载当前内容,并在触发onEnded事件时开始播放下一个内容。以下重点介绍的步骤与播放内容播放列表有关

代码示例

以下代码示例显示了两种播放非自适应内容的方法:

VideoPlayer API

打开您的src/App.tsx并将其内容替换为以下代码块。

使用Vega SDK来构建应用,在设备或模拟器上运行它并收集日志。有关在模拟器上构建和运行应用的更多详细信息,请参阅创建Vega应用Vega虚拟设备

已复制到剪贴板。


/*
 * 版权所有 (c) 2024 Amazon.com, Inc.或其关联公司。 保留所有权利。
 *
 * 专有/机密信息。 相关使用受许可条款的约束。
 */

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 {ShakaPlayer, ShakaPlayerSettings} from './shakaplayer/ShakaPlayer';

// 如果应用需要手动在视频上调用播放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/angel-one/dash.mpd',
    drm_scheme: '', // com.microsoft.playready, com.widevine.alpha
    drm_license_uri: '', // DRM许可证获取服务器URL:仅当内容受DRM保护时才需要
  },
];

export const App = () => {
  const currShakaPlayerSettings = useRef<ShakaPlayerSettings>({
    secure: false, // 通过安全或非安全模式进行播放
    abrEnabled: true, // 启用自适应比特率 (ABR) 切换
    abrMaxWidth: DEFAULT_ABR_WIDTH, // 对ABR允许的最大宽度
    abrMaxHeight: DEFAULT_ABR_HEIGHT, // 对ABR允许的最大高度
  });

  const player = useRef<any>(null);
  const videoPlayer = useRef<VideoPlayer | null>(null);
  const timeoutHandler = useRef<ReturnType<typeof setTimeout> | null>(null);
  const [playerSettings, setPlayerSettings] = useState<ShakaPlayerSettings>(
    currShakaPlayerSettings.current,
  );
  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;
    initializeShaka();
  };

  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 initializeShaka = () => {
    console.log('app: in initializePlayer() index = ', nextContent.index);
    if (videoPlayer.current !== null) {
      player.current = new ShakaPlayer(videoPlayer.current, playerSettings);
    }
    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}> 按下播放视频 </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,
  }
});

Video组件

打开您的src/App.tsx并将其内容替换为以下代码块。

使用Vega SDK来构建应用,在设备或模拟器上运行它并收集日志。有关在模拟器上构建和运行应用的更多详细信息,请参阅创建Vega应用Vega虚拟设备

已复制到剪贴板。


/*
 * 版权所有 (c) 2024 Amazon.com, Inc.或其关联公司。 保留所有权利。
 *
 * 专有/机密信息。 相关使用受许可条款的约束。
 */

import * as React from "react";
import { useRef } from "react";
import { useWindowDimensions, View, StyleSheet } from "react-native";

import { Video } from "@amazon-devices/react-native-w3cmedia";

// 如果应用需要手动在视频上调用播放API,则设置为false
const AUTOPLAY = true;

const content = {
  uri: "https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd",
};

export const App = () => {
  const video = useRef<Video | null>(null);
  // 以全屏分辨率呈现
  const { width: deviceWidth, height: deviceHeight } = useWindowDimensions();

  console.log("AppNonAdaptiveVidoe v1.0");

  return (
    <View style={styles.videoContainer}>
      <Video
        autoplay={AUTOPLAY}
        src={content.uri}
        width={deviceWidth}
        height={deviceHeight}
        controls={true}
        ref={(ref) => {
          video.current = ref;
        }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  videoContainer: {
    backgroundColor: "white",
    alignItems: "stretch",
  },
});

另请参阅

媒体播放器API


Last updated: 2025年9月30日