React 中播放HLS 视频流 ,超简单的组件高度复用

发布于:2025-08-16 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、封装HLS播放组件

直接上代码:

请先导入 hls.js 依赖 
封装的React组件,设置有错误捕捉无闪动继续加载画面

import React, { useEffect, useRef } from 'react';
import Hls from 'hls.js';
type HlsPlayerProps = {
    url?: string; // HLS m3u8 地址
    width?: number;
    height?: number;
    isLive?: boolean;
};

const HlsPlayer: React.FC<HlsPlayerProps> = ({ url }) => {
    const videoRef = useRef<HTMLVideoElement>(null);
    const hlsRef = useRef<Hls | null>(null);

    const handleHlsError = (hls: Hls, data: any) => {
        console.error('HLS 播放错误', data);

        if (data.fatal) {
            switch (data.type) {
                case Hls.ErrorTypes.NETWORK_ERROR:
                    console.warn('网络错误,尝试重新加载分片...');
                    hls.startLoad(); // 继续加载,不 destroy
                    break;
                case Hls.ErrorTypes.MEDIA_ERROR:
                    console.warn('媒体错误,尝试恢复...');
                    hls.recoverMediaError(); // 恢复媒体解码
                    break;
                default:
                    console.error('不可恢复错误,停止播放');
                    hls.destroy();
                    break;
            }
        } else if (data.details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) {
            console.warn('缓冲区无数据,尝试继续加载...');
            hls.startLoad(); // 直接恢复加载,不 destroy
        }
    };


    const initHls = () => {
        if (!url || !videoRef.current) return;

        if (hlsRef.current) {
            hlsRef.current.destroy();
            hlsRef.current = null;
        }

        if (Hls.isSupported()) {
            const hls = new Hls({});
            hls.loadSource(url);
            hls.attachMedia(videoRef.current);

            hls.on(Hls.Events.MANIFEST_PARSED, () => {
                videoRef.current?.play();
            });

            hls.on(Hls.Events.ERROR, (event, data) => handleHlsError(hls, data));
            hlsRef.current = hls;
        } else if (videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
            videoRef.current.src = url;
            videoRef.current.addEventListener('loadedmetadata', () => {
                videoRef.current?.play();
            });
        } else {
            console.error('当前环境不支持 HLS 播放');
        }
    };

    useEffect(() => {
        initHls();
        return () => {
            if (hlsRef.current) {
                hlsRef.current.destroy();
                hlsRef.current = null;
            }
        };
    }, [url]);

    // 如果没传 URL,显示加载占位
    if (!url) {
        return (
            <div style={{
                width: '100%',
                height: '100%',
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                background: 'rgba(0,0,0,0.1)',
                color: '#999',
                fontSize: 14
            }}>
                正在加载视频...
            </div>
        );
    }


    return (
        <div style={{ width: '100%', height: '100%' }}>
            <video
                ref={videoRef}
                style={{ width: '100%', height: '100%', objectFit: 'cover', }}
                autoPlay
                muted
                loop
                playsInline
            />
        </div>
    );
};

export default HlsPlayer;

二、HLS组件播放使用


// 其中的videoUrl 就是HLS播放的视频流
<div style={{ width: '200ox', height: '200px' }}>
            <HlsPlayer url={videoUrl}></HlsPlayer>
</div>

三、监控展示效果

直接播放画面


网站公告

今日签到

点亮在社区的每一天
去签到