You need to enable JavaScript to run this app.
文档中心
视频点播

视频点播

复制全文
下载 pdf
React Native 播放器 SDK
示例代码
复制全文
下载 pdf
示例代码

本文提供 React Native 播放器 SDK 部分功能的详细示例代码。

预渲染示例代码

以下为以 @ant-design/react-nativeCarousel 作为轮播组件容器实现预渲染的示例代码:

// index.tsx
import React, {useCallback, useState, useEffect} from 'react';
import {View, Carousel} from '@ant-design/react-native';
import {StyleSheet, SafeAreaView} from 'react-native';
import {setPreRenderCallback, enableEngineStrategy, StrategyType} from '@volcengine/react-native-vod-player';
import type {
  TTVideoEngine,
  VideoSource,
} from '@volcengine/react-native-vod-player';
import PrePlayer from './PrePlayer';

enableEngineStrategy(StrategyType.Preload, StrategyScene.SmallVideo);
enableEngineStrategy(StrategyType.PreRender, StrategyScene.SmallVideo);

const sourceDataList = [
  {
    url: 'https://demo.com/1.mp4?auth_key=18221***732f',
    vid: 'v0ddfa0***h92v9l0',
    cacheKey: 'v0dd***h92v9l0',
    poster: 'https://demo-cover.com/t***c533b04/57bd2***53fd~tplv-vod-noop.image',
  },
  {
    url: 'https://demo.com/2.mp4?auth_key=182002***598e',
    vid: 'v03dfag10*****4ar8ft0',
    cacheKey: 'v03d***4ar8ft0',
    subUrl: 'https://demo.com/e87***61e?auth_key=176075***71f5&mime_type=text_plain',
    poster: 'https://demo-cover.com/t***c53b04/158***9621c~tplv-vod-noop.image',
  },
  {
    url: 'https://demo.com/3.mp4?auth_key=18***c935',
    vid: 'v03dfag100***9s8kevs0',
    cacheKey: 'v03df***cpig9s8kevs0',
    poster: 'https://demo-cover.com/t***533b04/201***fe9a9f7~tplv-vod-noop.image',
  },
  {
    url: 'https://demo.com/4.mp4?auth_key=1820024284-***a9139',
    vid: 'v02dfag10***39jdg',
    cacheKey: 'v02dfa***imkm239jdg',
    poster: 'https://demo-cover.com/t*****c997******3b04/e12b***4d15c2~tplv-vod-noop.image',
  },
  {
    url: 'https://demo.com/5.mp4?auth_key=1820024298-90***bafc3032',
    vid: 'v03dfag10***ppj65150',
    cacheKey: 'v03df***j65150',
    poster: 'https://demo-cover.com/t***c-8a997967cc533b04/beac53***76d403dea~tplv-vod-noop.image',
  },
  {
    url: 'https://demo.com/6.mp4?auth_key=182219***afec',
    vid: 'v02dfag1***1v0vjl8jmvgg',
    cacheKey: 'v02df***vjl8jmvgg',
    poster: 'https://demo-cover.com/t***33b04/41ac***bbdb6020f~tplv-vod-noop.image',
  },
];

const styles = StyleSheet.create({
  wrapper: {
    flex: 1,
    position: 'relative',
  },
  text: {
    color: '#fff',
    fontSize: 30,
    fontWeight: 'bold',
  },
  info: {
    position: 'absolute',
    top: 40,
    left: 10,
    width: '60%',
    height: 300,
    backgroundColor: 'rgba(255, 255, 255, 0.5)',
  },
});

const PreRender = () => {
  const [currentIndex, setIndex] = useState(0);
  const [isScrollDrag, setScrollDrag] = useState(false);

  const onIndexChanged = useCallback(index => {
    setIndex(index);
  }, []);

  useEffect(() => {
    setPreRenderCallback({
      onPlayerCreated(player: TTVideoEngine, source: VideoSource) {
        const index = sourceDataList.findIndex(e => e.vid === source.vid());
        if (index < 0) {
          return;
        }
        const sourceData = sourceDataList[index];
        const {subUrl} = sourceData;
        if (subUrl) {
          // 设置预渲染播放器的字幕
          player.enableSubThread(true);
          player.enableSubtitle(true);
          player.setSubDesInfoModel({
            list: [
              {
                id: 1,
                language: 'cmn-Hans-CN',
                language_id: 1,
                url: subUrl,
                format: 'webvtt',
                sub_id: 1,
              },
            ],
          });
        }
      },
      onPlayerWillPrepare(player: TTVideoEngine) {
        console.log('player will prepare', player);
      },
      onPlayerExtraSetup(player: TTVideoEngine, source: VideoSource) {
        console.log('player extra setup', player, source);
      },
    });
  }, []);

  const onScrollBeginDrag = useCallback(() => {
    setScrollDrag(true);
  }, []);
  const onScrollEndDrag = useCallback(() => {
    setScrollDrag(false);
  }, []);

  return (
    <SafeAreaView style={styles.wrapper}>
      <Carousel
        style={{width: '100%', height: '100%'}}
        vertical
        afterChange={onIndexChanged}
        onScrollBeginDrag={onScrollBeginDrag}
        onScrollEndDrag={onScrollEndDrag}
        overScrollMode="never">
        {sourceDataList.map((item, index) => {
          return (
            <View key={item.vid}>
              <PrePlayer
                isScrollDrag={isScrollDrag}
                data={item}
                currentIndex={currentIndex}
                index={index}
              />
            </View>
          );
        })}
      </Carousel>
    </SafeAreaView>
  );
};

export default PreRender;

以下为使用 React Native 播放视图组件实现预渲染的示例代码:

// PrePlayer.tsx
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View, StyleSheet, Image} from 'react-native';
import {
  PlayerViewComponent,
  TTVideoEngine,
  VideoSource,
  createDirectUrlSource,
  getPreRenderEngine,
  setView,
  initPlayer,
  getFirstFrameEngine,
  type DirectUrlSourceInitProps,
} from '@volcengine/react-native-vod-player';

interface SwiperPlayerProps {
  currentIndex: number;
  index: number;
  data: DirectUrlSourceInitProps & {
    poster: string;
  };
  isScrollDrag: boolean;
}

const styles = StyleSheet.create({
  wrap: {
    position: 'relative',
    width: '100%',
    height: '100%',
  },
  player: {
    width: '100%',
    height: '100%',
    backgroundColor: '#000000',
  },
  img: {
    position: 'absolute',
    width: '100%',
    height: '100%',
    resizeMode: 'contain',
    top: 0,
    left: 0,
    backgroundColor: '#000000',
  },
});

const PrePlayer: React.FC<SwiperPlayerProps> = ({
  currentIndex,
  index,
  data,
  isScrollDrag,
}) => {
  const isCurrent = useMemo(
    () => index === currentIndex,
    [index, currentIndex],
  );
  const viewId = useMemo<string>(() => `pre-player-${index}`, [index]);
  const [canInit, setCanInit] = useState(false);
  // 预渲染 engine
  const playerRef = useRef<TTVideoEngine | undefined>();
  const [showPoster, setShowPoster] = useState(true);

  const handleStart = useCallback(() => {
    setCanInit(true);
  }, []);

  const setPlayer = useCallback(async () => {
    if (!playerRef.current) {
      setShowPoster(true);
      const curSource: VideoSource = createDirectUrlSource(data);
      const preRenderEngine = getPreRenderEngine(curSource);
      if (preRenderEngine && index !== 0) {
        // 命中预渲染
        await setView(preRenderEngine, viewId);
        setShowPoster(false);
        playerRef.current = preRenderEngine;
      } else {
        // 未命中预渲染
        const player = await initPlayer({viewId});
        player.setVideoSource(curSource);
        playerRef.current = player;
        playerRef.current?.setListener({
          onReadyToDisplay() {
            setShowPoster(false);
          },
        });
      }
      if (isCurrent) {
        playerRef.current?.play();
      }
    }
  }, [data, index, isCurrent, viewId]);

  useEffect(() => {
    return () => {
      playerRef.current?.close();
    };
  }, []);

  useEffect(() => {
    if (!isCurrent) {
      playerRef.current?.close();
      playerRef.current = undefined;
      setShowPoster(true);
    } else {
      if (canInit) {
        setPlayer();
      }
    }
  }, [canInit, index, isCurrent, setPlayer]);

  const whenDrag = useCallback(async () => {
    if (canInit) {
      const source: VideoSource = createDirectUrlSource(data);
      const preRenderEngine = getFirstFrameEngine(source);
      if (preRenderEngine) {
        console.log('hit prerender, set first frame');
        await setView(preRenderEngine, viewId);
      }
    }
  }, [canInit, data, viewId]);

  useEffect(() => {
    if (index === currentIndex + 1 && isScrollDrag) {
    // 对当前下一个视图使用预渲染的播放器实例设置首帧封面
      whenDrag();
    }
  }, [canInit, currentIndex, index, isCurrent, isScrollDrag, whenDrag]);

  return (
    <View style={styles.wrap}>
      <PlayerViewComponent
        style={styles.player}
        viewId={viewId}
        onLoad={handleStart}
      />
      <Image
        style={[styles.img, showPoster ? {opacity: 1} : {opacity: 0}]}
        source={{uri: data.poster}}
      />
    </View>
  );
};

export default PrePlayer;
最近更新时间:2025.04.29 19:17:05
这个页面对您有帮助吗?
有用
有用
无用
无用