前端音视频开发之视频播放器

788 阅读8分钟

针对项目中遇到的问题,接触到音视频开发,针对目前常见的三方库进行大致的总结和分类,以及搭配方案。

视频格式

参考:MDN Media container formats (file types), MDN Codecs in common media types

音视频的格式由两部分定义,音视频的编码(例如AVC/H264, HEVC/H265, AV1)以及媒体容器格式(或者叫文件类型)(例如FLV,AVI,MP4)。

比如 video/mp4; codecs="avc1.4d002a",代表 编码是h264,文件类型是mp4

HEVC/H265是一种旨在继承 H.264 的视频压缩格式。浏览器很难普遍支持 HEVC,因为它复杂且许可费用昂贵。 HEVC 与AV1竞争,后者具有相似的压缩质量并提供免费许可证。

视频流介绍

视频流大致分为三种

HLS

HLS(Http Live Streaming) 是一个由苹果公司提出的基于HTTP的流媒体网络传输协议,直接把流媒体切片成多段,信息保存到m3u列表文件中, 可以将不同速率的版本切成相应的片;播放器可以直接使用http协议请求流数据。

RTMP

RTMP(Real Time Message Protocol)由 Adobe 公司提出流媒体协议,并且是私有协议,未完全公开,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题,RTMP协议一般传输的是 flv,f4v 格式流。一般在 TCP 1个通道上传输命令和数据。

坑:RTMP 为 Adobe 私有协议,很多设备无法播放,需要使用 Flash Player 作为播放器客户端,IOS设备不支持!且目前谷歌公司宣布安卓Android系统不再继续支持Flash Player。

RTSP

RTSP(Real-Time Stream Protocol)由Real Networks 和Netscape共同提出的流媒体协议,RTSP协议是共有协议,并有专门机构做维护。是TCP/IP协议体系中的一个应用层协议. RTSP协议一般传输的是 ts、mp4 格式的流,RTSP传输一般需要 2-3 个通道,命令和数据通道分离。基于文本的多媒体播放控制协议. RTSP定义流格式,流数据经由RTP传输;

RTSP实时效果非常好,适合视频聊天,视频监控等方向。问题:浏览器不能直接播放,只能通过插件或者转码。

HLS诞生的原因

  • 主要是为了解决RTMP协议存在的一些问题。比如RTMP协议不使用标准的HTTP接口传输数据,所以在一些特殊的网络环境下可能被防火墙屏蔽掉。但是HLS由于使用的HTTP协议传输数据,不会遇到被防火墙屏蔽的情况。

  • RTMP是一种有状态协议,它在视频服务器和客户端之间建立了一个持久的连接,并需要为每个播放视频流的客户端维护状态。这意味着视频服务器需要跟踪每个客户端的状态信息,包括当前播放位置、缓冲区状态等。这种状态维护对于视频服务器的扩展性来说并不友好,因为需要为每个客户端分配资源和处理状态更新。

  • 相比之下,HLS基于无状态协议(HTTP)。在HLS中,视频文件被分割成一系列的小文件(通常是TS文件),并存储在服务器上。客户端通过按顺序下载这些文件来播放视频。

    m3u8文件是HLS协议中使用的一种文件格式,它包含了视频流的信息和播放地址。而TS文件是HLS中的视频文件,被切割成多个小片段,并保存在m3u8文件中的不同URL地址中。播放器通过解析m3u8文件中的地址,按顺序下载这些小片段的TS文件来播放视频。

    由于HTTP是无状态的,服务器不需要维护客户端的状态信息,只需要按需提供文件即可。这使得负载均衡变得简单,就像普通的HTTP文件服务器一样。因此,相对于RTMP,HLS更容易实现视频服务器的平滑扩展,因为它不需要为每个客户端维护状态。这使得HLS成为一种更可靠和可扩展的视频传输协议。

  • 坑一:苹果在自家的IOS设备上只提供对HLS的原生支持,并且放弃了flash。好在Android也原生支持了HLS。

  • 坑二:采用HLS协议直播的视频延迟时间无法下到10秒以下,而RTMP协议的延迟最低可以到3、4秒左右。所以说对直播延迟比较敏感的服务请慎用HLS

播放解决方案

我们不仅要针对不同协议上的兼容(比如flv),还要兼容视频编码格式(H.264和H.265),还要考虑到移动端上android和ios的特性问题。

针对一些第三方库,总结如下:

库名称支持协议支持视频编码支持FLVPC浏览器兼容性Android兼容性iOS兼容性优点缺点
Video.jsHTTP, HTTPS, HLS, DASHH.264通过插件支持丰富的插件,广泛支持,文档详尽需要额外插件实现FLV支持,支持H.265。github.com/coffe1891/v…
flv.jsFLV over HTTPH.264原生支持专门用于FLV播放,性能良好,低延迟仅支持FLV流,不支持其他协议
hls.jsHLSH.264,(H.265取决于浏览器对 MSE)和 HEVC 编解码器的支持情况,建议直接理解为不支持)不支持专注于HLS,低延迟播放依赖于MSE,不支持FLV,不支持H.265
ClapprHTTP, HTTPS, HLSH.264通过flv.js插件支持多协议支持,开源易扩展需要额外插件实现FLV支持
EasyWasmPlayer支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等H.264, H.265支持支持Windows、Linux、Android、iOS全平台终端的H5播放器,且支H.264,H.265github.com/EasyDarwin/…配置复杂,且问题较多segmentfault.com/a/119000003…
FlowplayerHTTP, HTTPS, HLS, DASHH.264, H.265通过flash插件支持商业级解决方案要收费,需额外flash插件支持FLV

目前整理下来,针对各个平台,比较合理的搭配方式:

平台/协议HTTP/HTTPSHLSFLVDASHH.264H.265
PCVideo.jsvideojs-http-streamingflv.js/videojs-flvjsShaka Player通过[videojs-flvh265]支持(github.com/coffe1891/v…
AndroidVideo.js (通过WebView) + ExoPlayerHLS (通过WebView/ExoPlayer)flv.jsDASH (通过WebView/ExoPlayer)通过[videojs-flvh265]支持(github.com/coffe1891/v…)
iOSVideo.js (通过WebView) + AVPlayerHLS (通过WebView/AVPlayer)flv.jsDASH (通过WebView)通过[videojs-flvh265]支持(github.com/coffe1891/v…)

PC端实现逻辑:

import React, { useRef, useEffect } from 'react';
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
import 'videojs-flvjs'; // 支持FLV播放
import shaka from 'shaka-player/dist/shaka-player.ui.js';
import 'shaka-player/dist/controls.css';

// Video.js 组件实现
const VideoPlayer = ({ src, type = 'video/mp4' }) => {
    const videoRef = useRef(null);

    useEffect(() => {
        const player = videojs(videoRef.current, {
            controls: true,
            autoplay: false,
            preload: 'auto',
        });
        
        // 检查支持情况,决定使用何种模式播放视频
        if (type === 'video/flv' && window.flvjs.isSupported()) {
            videojs('my-video').ready(function() {
                let flvPlayer = flvjs.createPlayer({ type: 'flv', url: src });
                flvPlayer.attachMediaElement(videoRef.current);
                flvPlayer.load();
            });
        } else if (type === 'application/x-mpegURL') {
            player.src({ src, type });
        } else if (type === 'application/dash+xml') {
            const shakaPlayer = new shaka.Player(videoRef.current);
            shakaPlayer.load(src).catch(error => console.error(error));
        } else { // 普通MP4视频
            player.src({ src, type });
        }

        return () => {
            if (player) {
                player.dispose();
            }
        };
    }, [src, type]);

    return (
        <div data-vjs-player>
            <video ref={videoRef} id="my-video" className="video-js vjs-default-skin" controls preload="auto"></video>
        </div>
    );
};

export default VideoPlayer;

直播与监控

你以为这就结束了?没有!上面这个搭配只是从视频播放的角度去适配。接下来,针对业务的场景,因为涉及实时监控,场景类似于直播。再介绍两个库:

Jessibuca

  • Jessibuca是一款直播播放器库,支持多种协议(特别是FLV)和H.264及部分H.265编码。
  • 它适用于PC浏览器、Android及iOS平台。对于RTMP和HTTP-FLV这种低延迟协议支持非常好,适合直播的场景。
  • 问题在于Jessibuca主要支持RTMP和HTTP-FLV协议,不支持HLS(本来HLS延迟就高,没有处理HLS的直播)。只是说在iOS设备上可以通过WebView嵌入或使用Jessibuca提供的iOS SDK来播放RTMP和HTTP-FLV协议的视频流。

mpegts.js

还有一个第三方库mpegts.js,这个第三方库在项目中主要处理PC上的播放器。

简单介绍一下这个库:

mpegts.js 主要用于在浏览器中播放 MPEG-TS(MPEG Transport Stream)格式的视频,它是基于 JavaScript 实现的轻量级库,主要适合于处理 HTTP-FLV 和 MPEG-TS 容器格式的视频流。根据官方介绍:

播放通过 http(s) 或 WebSocket 传输的 H.264/H.265 + AAC 编解码器的 MPEG2-TS 流

播放通过 http(s) 或 WebSocket 传输的 H.264/H.265 + AAC 编解码器的 FLV 流

它是一个支持 H.264 和 H.265 编码的视频流播放,且通过 MSE 提供低延迟的播放,适合实时流媒体和直播应用。(项目中使用mpegts.js就是想通过这一个库实现兼容flv、 H.264 和 H.265的直播库)但是!!!有坑!H.265编码格式仅可以在chrome浏览器兼容!在Edge浏览器上需要花钱买解码器,才能支持h265。(硬件支持的情况下,chrome支持HEVC硬解,Edge需要去商城装扩展(付费))github.com/xqq/mpegts.…github.com/xqq/mpegts.…

参考文档:juejin.cn/post/684490…