前端加载视频直播流

6 篇文章 0 订阅
2 篇文章 0 订阅

1.flv格式的视频

import React, { useEffect, useRef, useState } from 'react';
import { Icon } from 'antd';
import flvjs from 'flv.js';
import cls from 'classnames';
import styles from './index.scss';

const VIDEO_MESSAGE = {
  LOADING: '正在载入视频...',
  FAILED: '视频载入失败',
}

export default function FlvVideo({ url }) {
  const videoRef = useRef(null);
  const playerRef = useRef(null);
  const [msg, setMsg] = useState('');
  const [success, setSuccess] = useState(false);
  const [loading, setLoading] = useState(false);

  // unmount时销毁
  useEffect(() => {
    return () => {
      if (playerRef.current) {
        playerRef.current.destroy();
      }
    }
  }, []);

  useEffect(() => {
    if (playerRef.current) {
      playerRef.current.destroy();
      playerRef.current = null;
      setLoading(false);
      setMsg('');
    }

    if (url) {
      const videoElement = videoRef.current;
      if (flvjs.isSupported()) {
        const flvPlayer = flvjs.createPlayer({
          type: 'flv',
          url,
          isLive: true,
          cors: true,
          hasVideo: true,
          hasAudio: false,
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();
        setLoading(true);
        setMsg(VIDEO_MESSAGE.LOADING);
        flvPlayer.play().then(() => {
          console.log('[success] video loaded.');
          setMsg('');
          setSuccess(true);
          setLoading(false);
        });
        flvPlayer.on(flvjs.Events.ERROR, err => {
          setMsg(VIDEO_MESSAGE.FAILED);
          setSuccess(false);
          setLoading(false);
          console.error(`[${err}] ${VIDEO_MESSAGE.FAILED}`);
        });
        playerRef.current = flvPlayer;
      } else {
        setSuccess(false);
        setMsg('当前浏览器不支持播放')
      }
    }
  }, [url]);

  return <div className={cls(styles['video-view'])}>
    {!success && <div className={styles.msg}>
      {loading && <div><Icon type="loading" spin /></div>}
      <div className={cls({ [styles.blue]: loading })}>{msg}</div>
    </div>}
    {!!url && <video ref={videoRef} className={cls(styles.video, {[styles.hidden]: !success })} muted controls disablePictureInPicture controlsList="nodownload">Your browser does not support HTML5 video.</video>}
  </div>
}

2.m3u8

import React, { useRef, useEffect, useState } from 'react';
import Hls from 'hls.js';
import styles from './index.scss';

const VIDEO_MESSAGE = {
  LOADING: '正在载入视频...',
  FAILED: '视频载入失败',
  RETRY: '正在尝试重新载入...',
  NOT_SUPPORTED: '当前浏览器不支持播放',
  NO_SOURCE: '无视频源',
};

export default function HlsVideo({ url }) {
  const videoRef = useRef();
  const [msg, setMsg] = useState('');

  useEffect(() => {
    const videoEle = videoRef.current;
    if (url && videoEle) {
      if (Hls.isSupported()) {
        setMsg(VIDEO_MESSAGE.LOADING);
        const hls = new Hls();
        hls.loadSource(url);
        hls.attachMedia(videoEle);
        hls.on(Hls.Events.MANIFEST_PARSED, function() {
          setMsg('');
          videoEle.play();
        });
        hls.on(Hls.Events.FRAG_PARSED, function() {
          setMsg('');
        });
        // 简单错误处理
        hls.on(Hls.Events.ERROR, function(event, data) {
          if (data.fatal) {
            switch (data.type) {
              case Hls.ErrorTypes.NETWORK_ERROR:
                console.log('fatal network error encountered, try to recover');
                setMsg(VIDEO_MESSAGE.RETRY);
                hls.startLoad();
                break;
              case Hls.ErrorTypes.MEDIA_ERROR:
                console.log('fatal media error encountered, try to recover');
                setMsg(VIDEO_MESSAGE.RETRY);
                hls.recoverMediaError();
                break;
              default:
                hls.destroy();
                setMsg(VIDEO_MESSAGE.FAILED);
                break;
            }
          } else {
            // 非 fatal 级别的错误,hls会自动重试
            setMsg(VIDEO_MESSAGE.RETRY);
          }
        });
      } else {
        setMsg(VIDEO_MESSAGE.NOT_SUPPORTED);
      }
    } else {
      // setMsg(VIDEO_MESSAGE.NO_SOURCE);
    }
  }, [url]);

  return <div className={styles['video-view-hls']}>
    {!!msg && <div className={styles.msg}>{msg}</div>}
    <video
      className={styles.video}
      ref={videoRef}
      muted
      controls
      disablePictureInPicture
      controlsList="nodownload"
    >
      Your browser does not support HTML5 video.
    </video>
  </div>;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值