针对项目中遇到的问题,接触到音视频开发,针对目前常见的三方库进行大致的总结和分类,以及搭配方案。
视频格式
参考: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的特性问题。
针对一些第三方库,总结如下:
| 库名称 | 支持协议 | 支持视频编码 | 支持FLV | PC浏览器兼容性 | Android兼容性 | iOS兼容性 | 优点 | 缺点 |
|---|---|---|---|---|---|---|---|---|
| Video.js | HTTP, HTTPS, HLS, DASH | H.264 | 通过插件支持 | 高 | 高 | 高 | 丰富的插件,广泛支持,文档详尽 | 需要额外插件实现FLV支持,支持H.265。github.com/coffe1891/v… |
| flv.js | FLV over HTTP | H.264 | 原生支持 | 高 | 高 | 高 | 专门用于FLV播放,性能良好,低延迟 | 仅支持FLV流,不支持其他协议 |
| hls.js | HLS | H.264,(H.265取决于浏览器对 MSE)和 HEVC 编解码器的支持情况,建议直接理解为不支持) | 不支持 | 高 | 高 | 高 | 专注于HLS,低延迟播放 | 依赖于MSE,不支持FLV,不支持H.265 |
| Clappr | HTTP, HTTPS, HLS | H.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… |
| Flowplayer | HTTP, HTTPS, HLS, DASH | H.264, H.265 | 通过flash插件支持 | 高 | 高 | 高 | 商业级解决方案 | 要收费,需额外flash插件支持FLV |
目前整理下来,针对各个平台,比较合理的搭配方式:
| 平台/协议 | HTTP/HTTPS | HLS | FLV | DASH | H.264 | H.265 |
|---|---|---|---|---|---|---|
| PC | Video.js | videojs-http-streaming | flv.js/videojs-flvjs | Shaka Player | 是 | 通过[videojs-flvh265]支持(github.com/coffe1891/v… |
| Android | Video.js (通过WebView) + ExoPlayer | HLS (通过WebView/ExoPlayer) | flv.js | DASH (通过WebView/ExoPlayer) | 是 | 通过[videojs-flvh265]支持(github.com/coffe1891/v…) |
| iOS | Video.js (通过WebView) + AVPlayer | HLS (通过WebView/AVPlayer) | flv.js | DASH (通过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.…