React使用西瓜播放器

韶硕
2023-12-01

西瓜播放器 | 快速上手

概述

西瓜播放器是一个Web视频播放器类库,它本着一切都是组件化的原则设计了独立可拆卸的 UI 组件。更重要的是它不只是在 UI 层有灵活的表现,在功能上也做了大胆的尝试:摆脱视频加载、缓冲、格式支持对 video 的依赖。尤其是在 mp4 点播上做了较大的努力,让本不支持流式播放的 mp4 能做到分段加载,这就意味着可以做到清晰度无缝切换、加载控制、节省视频流量。同时,它也集成了对 flv、hls、dash 的点播和直播支持。

安装:

npm install xgplayer

npm install xgplayer-flv

npm install xgplayer-hls

按需引入即可,代码如下:

import MonitorLiveBroadComp from "./pages/Monitor/index";
import { useEffect, useState } from 'react'
import logo from './logo.svg'
import './App.css';
import mp4Player from 'xgplayer';
import flvPlayer from 'xgplayer-flv';
import hlsPlayer from 'xgplayer-hls';
import ismobilejs from 'ismobilejs';
import picNotStart from './assets/img/img_video_default_notstart@2x.png';
import picTranscode from './assets/img/img_video_default_transcoding@2x.png';
import querystring from 'query-string';
import { apiHost } from "./hosts";

const {cid, token} = querystring.parse(window.location.search);
if (!cid || !token) console.warn('需要token和cid信息');

const isMobile = ismobilejs();

enum clsSt {
  wait = 0,
  earlyExtra = 3,
  during = 1,
  lateExtra = 4,
  end = 2,
}

function App() {
  const [mode, setMode] = useState<'hls'|'flv'|'mp4'|'stop'|'wait'|'transcode'>('wait');
  const [url, setUrl] = useState('');
  useEffect(() => {
    fetch(apiHost+`/api/client/monitor/stream?classroomId=${cid}`, {
      method: 'GET',
      headers: { token: ''+token }
    }).then(data => data.json()).then(json => {
      if (json.code !== 200) throw new Error(`获取推流信息失败(${json.code}, ${json.msg}).`);
      const {status, streamUrl, videoUrl} = json.data;
      const inClass = [clsSt.earlyExtra, clsSt.lateExtra, clsSt.during].indexOf(status) > -1;
      if (inClass && streamUrl) {
        const streamType = isMobile.apple.device ? 'hls' : 'flv';
        setMode(streamType);
        setUrl(streamUrl.replace(/\.(flv|m3u8)$/, streamType === 'flv' ? '.flv' : '.m3u8'));
      } else if (inClass) {
        setMode('stop');
        setUrl('');
      } else if (status === clsSt.end && videoUrl) {
        setMode('mp4');
        setUrl(videoUrl);
      } else if (status === clsSt.end && !videoUrl) {
        setMode('transcode');
        setUrl('');
      }
    }).catch(err => {console.error(err)});
    return () => {}
  }, []);
  useEffect(() => {
    const Player = ({
      'flv': flvPlayer,
      'hls': hlsPlayer,
      'mp4': mp4Player,
    } as any)[mode];
    let playerIns: any;
    url && setTimeout(() => {
      playerIns = new Player(Object.assign({
        id: 'monitorVideo',
        url: url,
        width: '100%',
        height: '100%',
        playsinline: true,
        closeVideoTouch: true,
        ignores: ['fullscreen'],
      }, ({
        'flv': {
          isLive: true,
          preloadTime: 30,
          minCachedTime: 5,
          // cors: false,
        },
        'hls': {
          isLive: true,
          config: {duration: NaN}
        },
        'mp4' : {
          playbackRate: [0.5, 0.75, 1, 1.5, 2],
        },
      }as any)[mode]));
      mode === 'hls' && Object.defineProperty(playerIns, 'duration', {value: NaN});
    }, 0)
    return () => {
      playerIns?.pause();
      playerIns?.destroy();
    };
  }, [url, mode]);

  return (
    <div className={isMobile.apple.tablet ? 'App ipad' : 'App'}>
      <div className="video-wrap">
        <div id="monitorVideo" className="video-container"></div>
        {mode === 'transcode' && <div className="notify"><img src={picNotStart} alt="" /><p>视频转码中...</p></div> }
        {mode === 'wait' && <div className="notify"><img src={picTranscode} alt="" /><p>课程尚未开始</p></div> }
        {mode === 'stop' && <div className="notify"><p>主讲可能退出教室,请尝试刷新</p></div> }
      </div>
      <MonitorLiveBroadComp />
    </div>
  )
}

export default App

 类似资料: