webrtc音视频相关

Posted by Qz on June 12, 2020

“Yeah It’s on. ”

web rtc

https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API

https://github.com/QinZhen001/front-end-demo/blob/master/src/pages/other/web-rtc/index.tsx

WebRTC 点对点通信原理

WebRTC 介绍

WebRTC 协议介绍

信令与视频通话

音视频流媒体原理以及基础入门知识

音视频通信的流程有五步:采集、编码、通信、解码、渲染。

WebRTC(Web Real-Time Communication)是一种基于Web技术的实时通信协议,它主要包括三个主要组成部分:RTCPeerConnection、RTCDataChannel和MediaStream。

RTCPeerConnection是WebRTC的核心组件,它允许浏览器之间建立点对点(Peer-to-Peer)连接,并通过建立网络连接传输音频、视频和数据。RTCPeerConnection使用底层的协议来处理网络传输,例如ICE(Interactive Connectivity Establishment)协议用于处理网络地址的交换和NAT穿越,DTLS(Datagram Transport Layer Security)用于保护传输的数据。

RTCDataChannel是一个可靠的、双向的、有序的连接,可以用于在两个浏览器之间传输任意类型的数据。它使用底层的协议来处理数据传输,例如SCTP(Stream Control Transmission Protocol)用于传输和监控数据流。

MediaStream允许浏览器捕获和处理音频和视频流,并将其发送到其他浏览器。它使用底层的协议来处理音视频流的传输,例如RTP(Real-time Transport Protocol)用于实时传输音视频数据。

除了上述的底层协议,WebRTC还使用其他协议来支持不同功能的实现,例如SDP(Session Description Protocol)用于描述会话信息,STUN(Session Traversal Utilities for NAT)用于处理NAT穿越等。

总之,WebRTC底层协议主要涉及ICE、DTLS、SCTP、RTP等,这些协议共同实现了WebRTC的实时通信功能。

媒体协商

不同浏览器对于音视频的编解码能力是不同的。比如: Peer-A 端支持 H264、VP8 等多种编码格式,而 Peer-B 端支持 H264、VP9 等格式。为了保证双方都可以正确的编解码,最简单的办法即取它们所都支持格式的交集-H264。在 WebRTC 中,有一个专门的协议,称为Session Description Protocol(SDP),可以用于描述上述这类信息。因此参与音视频通讯的双方想要了解对方支持的媒体格式,必须要交换 SDP 信息。而交换 SDP 的过程,通常称之为媒体协商

网络协商

参与音视频实时通信的双方要了解彼此的网络情况,这样才有可能找到一条相互通讯的链路。理想的网络情况是每个浏览器的电脑都有自己的私有公网 IP 地址,这样的话就可以直接进行点对点连接。但实际上出于网络安全和 IPV4 地址不够的考虑,我们的电脑与电脑之间或大或小都是在某个局域网内,需要NAT(Network Address Translation, 网络地址转换)。在 WebRTC 中我们使用 ICE 机制建立网络连接

信令服务器

两个设备之间建立 WebRTC 连接需要一个信令服务器来实现双方通过网络进行连接。信令服务器的作用是作为一个中间人帮助双方在尽可能少的暴露隐私的情况下建立连接。

ICE

ICE (Interactive Connecctivity Establishment, 交互式连接建立),ICE 不是一种协议,而是整合了 STUN 和 TURN 两种协议的框架。其中STUN(Sesssion Traversal Utilities for NAT, NAT 会话穿越应用程序),它允许位于 NAT(或多重 NAT)后的客户端找出自己对应的公网 IP 地址和端口,也就是俗称的“打洞”。但是,如果 NAT 类型是对称型的话,那么就无法打洞成功。这时候 TURN 就派上用场了,TURN(Traversal USing Replays around NAT)是 STUN/RFC5389 的一个拓展协议在其基础上添加了 Replay(中继)功能,简单来说其目的就是解决对称 NAT 无法穿越的问题,在 STUN 分配公网 IP 失败后,可以通过 TURN 服务器请求公网 IP 地址作为中继地址。

在 WebRTC 中有三种类型的 ICE 候选者,它们分别是:

  • 主机候选者
  • 反射候选者
  • 中继候选者

主机候选者,表示的是本地局域网内的 IP 地址及端口。它是三个候选者中优先级最高的,也就是说在 WebRTC 底层,首先会尝试本地局域网内建立连接。

反射候选者,表示的是获取 NAT 内主机的外网 IP 地址和端口。其优先级低于 主机候选者。也就是说当 WebRTC 尝试本地连接不通时,会尝试通过反射候选者获得的 IP 地址和端口进行连接。

中继候选者,表示的是中继服务器的 IP 地址与端口,即通过服务器中转媒体数据。当 WebRTC 客户端通信双方无法穿越 P2P NAT 时,为了保证双方可以正常通讯,此时只能通过服务器中转来保证服务质量了。

connectivity

https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API/Connectivity

SDP

https://developer.mozilla.org/zh-CN/docs/Glossary/SDP

SDP (Session Description Protocol) 是一个描述peer-to-peer (en-US) 连接的标准。SDP 包含音视频的:编解码 (codec),源地址,和时间信息。

AudioBuffer

https://developer.mozilla.org/zh-CN/docs/Web/API/AudioBuffer

https://github.com/mdn/webaudio-examples/blob/main/audio-buffer/index.html

AudioBuffer 接口表示存在内存里的一段短小的音频资源,利用AudioContext.decodeAudioData()方法从一个音频文件构建,或者利用 AudioContext.createBuffer()从原始数据构建。把音频放入 AudioBuffer 后,可以传入到一个 AudioBufferSourceNode进行播放。

MediaStream

https://developer.mozilla.org/zh-CN/docs/Web/API/MediaStream

MediaStream 接口是一个媒体内容的流.。一个流包含几个轨道,比如视频和音频轨道。

MediaStreamTrack

https://developer.mozilla.org/zh-CN/docs/Web/API/MediaStreamTrack

MediaStreamTrack 接口在 User Agent 中表示一段媒体源,比如音轨或视频。

Each MediaStreamTrack may have one or more channels. The channel represents the smallest unit of a media stream, such as an audio signal associated with a given speaker, like left or right in a stereo audio track.

AudioBufferSourceNode

AudioBufferSourceNode 接口继承自 AudioScheduledSourceNode,表现为一个音频源,它包含了一些写在内存中的音频数据,通常储存在一个 ArrayBuffer 对象中。

RTCPeerConnection

RTCPeerConnection 接口代表一个由本地计算机到远端的 WebRTC 连接。该接口提供了创建,保持,监控,关闭连接的方法的实现。

UDP

WebRTC底层使用UDP协议主要有以下几个原因:

  1. 实时性:UDP协议对实时性要求较高,适用于需要快速传输数据的实时应用场景,如音视频通话、实时游戏等。与TCP协议相比,UDP协议无需建立连接和保持状态,可以更快地传输数据。
  2. 低延迟:UDP协议没有TCP协议中的拥塞控制、流量控制、重传等机制,在数据传输过程中不对数据包进行确认和重传,因此可以减少传输延迟,提高实时传输的效率。
  3. 带宽利用率:UDP协议的无连接特性使得传输效率更高。在视频通话等实时应用中,有时丢失一些数据包对用户体验的影响较小,而追求高带宽利用率更为重要。
  4. NAT穿透:UDP协议更容易实现NAT穿透,可以更好地解决防火墙和网络地址转换的限制,使得WebRTC可以在不同的网络环境中进行通信。

需要注意的是,WebRTC在传输层上并不直接使用UDP协议,而是基于UDP协议实现了自己的传输协议(DTLS/SRTP),以提供更好的安全性和可靠性。

Janus

https://janus.conf.meetecho.com/docs/

General purpose WebRTC server

video.js

Tech

https://juejin.cn/post/6968628379213889550

Tech 是 videojs 中处理视频播放的技术

videojs 核心源码中提供了 Html5 作为默认 Tech,用于播放浏览器默认支持的视频类型。同时支持扩展 Tech,用于支持浏览器无法直接播放的视频类型,例如 flv、hls、dash 等。

middleware

https://videojs.com/blog/feature-spotlight-middleware/

Video.js middleware are like Express middleware but routes are based on video MIME types.

There are two important pieces to be aware of with middleware:

  1. dynamic source handling
  2. intercepting the player and tech interactions.
<video controls class="video-js">
  <source src="123" type="video/my-catalog">
</video>

Then, you could register a middleware for that route – the type video/my-catalog.

// middleware methods get the player instance as an argument
videojs.use('video/my-catalog', function(player) {

  // middleware are expected to return an object with the methods on it.
  // It can be a plain object or an instance of something.
  return {

    // setSource allows you to tell Video.js whether you're going to be handling the source or not
    setSource(srcObj, next) {
      const id = srcObj.src;

      videojs.xhr({
        uri: '/getVideo?id=' + id
      }, function(err, res, body) {

        // pass null as the first argument to say everything is going fine and we can handle it.
        next(null, {
          src: body.sourceUrl,
          type: body.sourceType
        })
      });
    }
  };
});

HLS

HLS(HTTP Live Streaming)

https://juejin.cn/post/6968628379213889550

关于 Hls 的支持,videojs 官方目前提供的最新支持是 videojs-http-streaming,简称 VHS,替代过去的 videojs-contrib-hls

Github 上也有一些第三方实现,基于 hls.js 的扩展,例如基于 Tech.registerTech 实现的 videojs-hlsjs,和基于 registerSourceHandler 实现的 videojs-hlsjs-plugin

对比这两个第三方库,可以发现使用 Tech.registerTech 会比使用 registerSourceHandler 代码更简单。

videojs 较新的版本已经默认内置了 VHS,只有 videojs.core.js 才是剔除了 VHS 的核心代码。

显示当前时间

在进度条中显示当前时间

进过一系列的研究 始终无法通过js操作来显示 (currentTimeDisplay设置无效) 但是可以通过css实现

https://github.com/videojs/video.js/issues/6534

这个issues中的思路我们可以参考 但是它改的css有点问题 我们采用我们的方式:

<video  className="video-js" />
.video-js .vjs-time-divider {
  display: block;
}

.video-js .vjs-control-bar .vjs-duration {
  display: block;
}

.video-js .vjs-control-bar .vjs-current-time {
  display: block;
}

这样就可以在进度条control-bar中显示当前时间

源码

https://juejin.cn/post/6961014406842941448

mpv

https://mpv.io/

a free, open source, and cross-platform media player

switch audio track

https://github.com/mpv-player/mpv/issues/3444

快捷键: Shirt + 3

ffmpeg

浏览器环境需要 ffmpeg.wasm

https://ffmpegwasm.netlify.app/#demo

export interface FFmpeg {
    /*
     * Load ffmpeg.wasm-core script.
     * In browser environment, the ffmpeg.wasm-core script is fetch from
     * CDN and can be assign to a local path by assigning `corePath`.
     * In node environment, we use dynamic require and the default `corePath`
     * is `$ffmpeg/core`.
     *
     * Typically the load() func might take few seconds to minutes to complete,
     * better to do it as early as possible.
     *
     */
    load(): Promise<void>;
    /*
     * Determine whether the Core is loaded.
     */
    isLoaded(): boolean;
    /*
     * Run ffmpeg command.
     * This is the major function in ffmpeg.wasm, you can just imagine it
     * as ffmpeg native cli and what you need to pass is the same.
     *
     * For example, you can convert native command below:
     *
     * ```
     * $ ffmpeg -i video.avi -c:v libx264 video.mp4
     * ```
     *
     * To
     *
     * ```
     * await ffmpeg.run('-i', 'video.avi', '-c:v', 'libx264', 'video.mp4');
     * ```
     *
     */
    run(...args: string[]): Promise<void>;
    /*
     * Run FS operations.
     * For input/output file of ffmpeg.wasm, it is required to save them to MEMFS
     * first so that ffmpeg.wasm is able to consume them. Here we rely on the FS
     * methods provided by Emscripten.
     *
     * Common methods to use are:
     * ffmpeg.FS('writeFile', 'video.avi', new Uint8Array(...)): writeFile writes
     * data to MEMFS. You need to use Uint8Array for binary data.
     * ffmpeg.FS('readFile', 'video.mp4'): readFile from MEMFS.
     * ffmpeg.FS('unlink', 'video.map'): delete file from MEMFS.
     *
     * For more info, check https://emscripten.org/docs/api_reference/Filesystem-API.html
     *
     */
    FS<Method extends FSMethodNames>(method: Method, ...args: FSMethodArgs[Method]): FSMethodReturn[Method];
    setProgress(progress: ProgressCallback): void;
    setLogger(log: LogCallback): void;
    setLogging(logging: boolean): void;
    exit(): void;
}

提取音轨

ffmepg -i /Users/qz/Documents/company_project/test-audio/test/music.mp4 -c:a libmp3lame -b:a 320K -map 0:1 music-second.mp3 -map 0:0 music.first.mp3

例子:

import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';

const file = await fetchFile(mp4Src)
    console.log('input file', file)
    ffmpeg.FS('writeFile', 'input.mp4', file);
    await ffmpeg.run('-i', 'input.mp4', '-c:a', "libmp3lame", "-map", "0:1", "music-second.mp3", "-map", "0:0", "music-first.mp3");
    Mp3musicSecond = ffmpeg.FS('readFile', 'music-second.mp3');
    Mp3musicFirst = ffmpeg.FS('readFile', 'music-first.mp3');
    const url1 = URL.createObjectURL(new Blob([Mp3musicFirst.buffer], { type: 'video/mp3' }));
    const url2 = URL.createObjectURL(new Blob([Mp3musicSecond.buffer], { type: 'video/mp3' }));

    audioSourceRef1.current.src = url1
    audioSourceRef2.current.src = url2

    audioRef1.current.load()
    audioRef2.current.load()

验证完成:

  • 提取出来数据 ArrayBuffer => Blob => ObjectURL => audio tag => 播放成功
  • 提取出来数据 ArrayBuffer => new AudioContext => decodeAudioData => AudioBuffer => AgoraRTC.createBufferSourceAudioTrack => audioTrack play 和 startProcessAudioBuffer => 播放成功

合并音轨

http://www.ffmpeg.org/ffmpeg-filters.html#amix

协议

RTP,RTCP

实时传输协议(Real-time Transport Protocol),RTP协议常用于流媒体系统(配合RTCP协议),视频会议和一键通系统(配合H.323或SIP),使它成为IP电话产业的技术基础。RTP协议和RTP控制协议RTCP一起使用,而且它是建立在UDP协议上的。

实时传输控制协议(Real-time Transport Control Protocol或RTP Control Protocol或简写RTCP)是实时传输协议的一个姐妹协议。RTCP为RTP媒体流提供信道外控制。RTCP本身并不传输数据,但和RTP一起协作将多媒体数据打包和发送。RTCP定期在流多媒体会话参加者之间传输控制数据。RTCP的主要功能是为RTP所提供的服务质量提供反馈。

RTSP+RTP经常用于IPTV领域。因为其采用UDP传输视音频,支持组播,效率较高。但其缺点是网络不好的情况下可能会丢包,影响视频观看质量。

RTP协议的延迟主要取决于网络传输的延迟和数据包的处理时间等因素,一般在几十到几百毫秒之间。

RTP 底层是基于UDP 的,UDP只是负责传输数据包,RTP提供时间标志戳及其他技术来保证流媒体在实时传输时的时间正确性。

WebRTC(Web实时通信)是基于RTP(实时传输协议)实现的

RTP是传输层协议

RTSP

RTSP是传输层(RTP是传输层)之上的应用层协议

RTSP,全称为Real Time Streaming Protocol,即实时流传输协议。它是一种用于控制实时多媒体数据传输的应用层协议。RTSP协议允许客户端通过控制服务器来播放、暂停、调节音量、跳跃等操作,与流媒体服务器之间进行交互。RTSP常用于流媒体播放器、IP摄像机等设备上,用于实现实时音视频的传输和控制。

RTSP 和 RTMP 的区别:

  1. 目的和使用场景:RTMP主要用于实时传输媒体数据,如音频和视频,它适用于一对一或一对多的直播和点播场景。RTSP主要用于控制网络流媒体服务器,它主要用于需要进行流式传输和控制的多媒体应用。
  2. 协议结构:RTMP是基于TCP的应用层协议,它通过建立TCP连接,并在该连接上传输媒体数据和控制信息。RTSP是一个用于实时传输控制的应用层协议,它使用TCP或UDP来传输控制消息,而媒体数据则使用RTP或者RTCP。
  3. 支持性和平台兼容性:RTMP在多种操作系统和平台上都有广泛的支持,包括Windows、Mac、Linux等。RTSP也有广泛的支持,但它可能不同程度地依赖于不同的操作系统和流媒体服务器。
  4. 编码支持:RTMP支持多种编码类型,包括H.264、AAC等,可以在较低的带宽下提供高质量的传输和播放。RTSP也支持多种编码类型,但具体的编码支持取决于流媒体服务器和客户端的能力。

总的来说,RTMP适用于实时的直播和点播场景,而RTSP适用于需要进行流式传输和控制的多媒体应用。两种协议各有优劣,选择使用哪一种取决于具体的应用需求和平台支持。

RTMP

RTMP(Real-Time Messaging Protocol,实时消息传输协议)是一种用于音频、视频和数据传输的协议。它由Adobe Systems开发,并且在Adobe Flash Player和Adobe AIR等播放器中使用。RTMP协议可以将音频、视频和数据从Flash播放器传输到流媒体服务器,然后再将其传送给其他用户。

RTMP协议是一种基于TCP的协议,通过TCP的可靠连接来传输数据。它支持实时的音视频传输,并且可以在不同的传输速率下自动调整视频和音频的质量,以适应不同的网络环境。

RTMP协议包括两个部分:RTMP和RTMPT。

  • RTMP(Real-Time Messaging Protocol)是RTMP协议的常用版本,它使用TCP连接进行数据传输,并且支持实时的音频、视频和数据传输。
  • RTMPT(Real-Time Messaging Protocol over HTTP Tunneling)是通过HTTP隧道使用RTMP协议的版本。它将RTMP的数据包封装在HTTP请求中,可以通过HTTP端口进行传输,因此可以绕过防火墙和代理服务器的限制。

RTMP协议广泛应用于流媒体领域,例如用于视频直播、音视频会议、在线游戏等。它具有低延迟、高可靠性和良好的扩展性等特点,适用于多种不同的网络环境。

它有三种变种:

  • 工作在TCP之上的明文协议,使用端口1935;
  • RTMPT封装在HTTP请求之中,可穿越防火墙;
  • RTMPS类似RTMPT,但使用的是HTTPS连接;

总结: RTMP协议基于TCP来实现,每个时刻的数据,收到后立刻转发,一般延迟在1-3s左右

HLS

HTTP Live Streaming(HLS)是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议,可实现流媒体的直播和点播。HLS点播,基本上就是常见的分段HTTP点播,不同在于,它的分段非常小。基本原理就是将视频或流切分成小片(TS), 并建立索引(M3U8)HTTP Live Streaming(HLS)是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议,可实现流媒体的直播和点播。HLS点播,基本上就是常见的分段HTTP点播,不同在于,它的分段非常小。基本原理就是将视频或流切分成小片(TS), 并建立索引(M3U8).

相对于常见的流媒体直播协议,例如RTMP协议、RTSP协议、MMS协议等,HLS直播最大的不同在于,直播客户端获取到的,并不是一个完整的数据流。

HLS协议在服务器端将直播数据流存储为连续的、很短时长的媒体文件(MPEG-TS格式),而客户端则不断的下载并播放这些小文件,因为服务器端总是会将最新的直播数据生成新的小文件,这样客户端只要不停的按顺序播放从服务器获取到的文件,就实现了直播。

由此可见,基本上可以认为,HLS是以点播的技术方式来实现直播。

总结: HLS协议基于HTTP短连接来实现,集合一段时间数据,生成ts切片文件,然后更新m3u8(HTTP Live Streaming直播的索引文件),一般延迟会大于10s

HTTP-FLV

HTTP-FLV基于HTTP长连接,通RTMP一样,每个时刻的数据,收到后立刻转发,只不过使用的是HTTP协议,一般延迟在1-3s

CDN

CDN架构设计比较复杂。不同的CDN厂商,也在对其架构进行不断的优化,所以架构不能统一而论。这里只是对一些基本的架构进行简单的剖析。

CDN主要包含:源站、缓存服务器、智能DNS、客户端等几个主要组成部分。

源站:是指发布内容的原始站点。添加、删除和更改网站的文件,都是在源站上进行的;另外缓存服务器所抓取的对象也全部来自于源站。对于直播来说,源站为主播客户端。

缓存服务器:是直接提供给用户访问的站点资源,由一台或数台服务器组成;当用户发起访问时,他的访问请求被智能DNS定位到离他较近的缓存服务器。如果用户所请求的内容刚好在缓存里面,则直接把内容返还给用户;如果访问所需的内容没有被缓存,则缓存服务器向邻近的缓存服务器或直接向源站抓取内容,然后再返还给用户。

智能DNS:是整个CDN技术的核心,它主要根据用户的来源,以及当前缓存服务器的负载情况等,将其访问请求指向离用户比较近且负载较小的缓存服务器。通过智能DNS解析,让用户访问同服务商下、负载较小的服务器,可以消除网络访问慢的问题,达到加速作用。

客户端:即发起访问的普通用户。对于直播来说,就是观众客户端。

补充

音频

https://zhuanlan.zhihu.com/p/34295106

声音是一种波。计算机只能处理离散的信号,通过收集足够多的离散的信号,来不断逼近波形,这个过程我们叫做采样。

采样频率(Sample Rate)

每秒采集声音的数量,它用赫兹(Hz)来表示。

定义了每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。采样率是指将模拟信号转换成数字信号时的采样频率,也就是单位时间内采样多少点。一个采样点数据有多少个比特。比特率是指每秒传送的比特(bit)数。单位为 bps(Bit Per Second),比特率越高,传送的数据越大,音质越好.

声音通道(Channel)

每个通道存储的声音会从其中的一个喇叭出来就好了,不过可以通过算法的模拟来让没有那么多喇叭也能出来类似的效果。

声道数:声道数是音频传输的重要指标,现在主要有单声道和双声道之分。双声道又称为立体声,在硬件中要占两条线路,音质、音色好, 但立体声数字化后所占空间比单声道多一倍。

PCM 数据

PCM 数据是脉冲编码调制(Pulse Code Modulation)的缩写,是一种数字音频编码方式。在 PCM 中,音频信号会被采样成一系列的数字化值,每个值对应着采样时的声音强度。这些数字化值通常是用二进制数表示,可以存储在计算机中或者传输到其他设备或系统中。PCM 数据是一种常见的音频格式,包括 CD 音乐、数字音频文件等,也是许多数字信号处理方案的基础。

比特率(bps [bits per second])

每秒钟要播放多少 bit 的数据。公式一目了然:

比特率 = 采样率 × 采样深度 × 通道。

音频裁剪

js实现音频PCM数据合并、拼接、裁剪、调节音量等功能

/**
* 音频裁剪
* @param audioBuffer 待裁剪的数据
* @param duration 音频总时长
* @param startOffset 裁剪偏移时间,单位s
*/
clipAudio(audioBuffer,duration,startOffset = 0){
	return new Promise((resolve,reject) => {
		// 获取音频通道数量
		const channels = audioBuffer,.numberOfChannels;
		// 获取采样率
		const rate = audioBuffer.sampleRate;
		
		// 计算截取后需要的采样数量
		const endOffset = rate * duration;
		const frameCount = endOffset - 0;
		
		// 创建新的audioBuffer数据
		const newAudioBuffer = new AudioContext().createBuffer(channels,frameCount,rate);
		
		// 创建Float32的空间,作为copy数据的载体
		const anotherArray = new Float32Array(frameCount);
		
		// 裁剪后放置的起始位置
		const offset = 0;
		
		// 遍历通道,将每个通道的数据分别copy到对应的newAudioBuffer的通道
		for(let channel = 0; channel < channels;channel++){
      // 将样本从 AudioBuffer 的指定通道复制到目标数组中
			audioBuffer.copyFromChannel(anotherArray, channel, rate * startOffset);
      // 将样本从源数组复制到AudioBuffer的指定通道。
			newAudioBuffer.copyToChannel(anotherArray, channel, offset);
		}
		// 完成裁剪
		resolve(newAudioBuffer);
	})
	
}

WAV

WAV可以在mac 和 网页上进行播放。

请注意,不是所有的浏览器都支持播放WAV文件。在某些情况下,您可能需要将WAV文件转换为其他格式(例如MP3或OGG),以确保在各种浏览器中的兼容性。

判断浏览器是否支持播放WAV文件:

var audio = new Audio("path_to_wav_file.wav");
if (audio.canPlayType("audio/wav") !== "") {
  // 浏览器支持播放WAV文件
} else {
  // 浏览器不支持播放WAV文件
}

WAV 和 MP3

WAV文件和MP3是两种常见的音频文件格式。

  • WAV(Waveform Audio File Format)是一种无损的音频文件格式,它的文件体积相对较大,因为它保存音频数据的完整信息,包括采样率、采样位数等。WAV文件通常用于存储无损音频数据,如音乐制作、CD音轨等。由于它的音质较高,很多专业音频工作者和音乐制作人都会选择使用WAV文件进行录制和编辑。
  • MP3(MPEG-1 Audio Layer III)是一种有损的音频文件格式,它通过压缩音频数据来减小文件体积,因此相对于WAV文件,MP3文件体积更小。在压缩过程中,MP3会丢弃一些人耳较难察觉的音频数据,从而达到较高的压缩比。由于MP3文件相对较小,易于传输和存储,因此成为了互联网上非常流行的音频格式,经常在音乐下载、流媒体等场景中使用。

需要注意的是,由于MP3是有损压缩格式,相对于WAV来说会损失一些音质。因此,如果对音质要求较高的情况下,可以选择WAV文件作为首选,而如果追求文件体积小并且对音质要求相对较低,可以选择MP3文件。

webaudio-examples

https://github.com/mdn/webaudio-examples

https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API

webrtc-adapter

https://www.npmjs.com/package/webrtc-adapter

adapter.js is a shim to insulate apps from spec changes and prefix differences in WebRTC. The prefix differences are mostly gone these days but differences in behaviour between browsers remain.

js是一种将应用程序与WebRTC中的规范变化和前缀差异隔离开来的机制。这些天,前缀的差异已经消失了,但浏览器之间的行为差异仍然存在。

视频

m3u8

application/vnd.apple.mpegURL 是一种MPEG-DASH(Dynamic Adaptive Streaming over HTTP)视频流的容器格式,也即.m3u8文件。

这种格式通常用于流媒体服务中,允许动态自适应流媒体传输,以适应观众的网络状况和设备能力。.m3u8 是一个文本文件,其中包含媒体片段的URL,可以用于播放HLS(HTTP Live Streaming)视频流。HLS是苹果公司开发的一种流媒体传输协议,适用于iOS和macOS设备上的视频播放。

browserHlsSupported(): boolean {
    const mediaElement = document.createElement('video');
    return !!mediaElement.canPlayType('application/vnd.apple.mpegURL');
  }

flv、hls、dash

协议 传输方式 视频封装格式 数据分段 延时 H5播放
http-flv http流 flv 连续流 flv.js
rtmp tcp流 flv tag 连续流 不支持
hls http Ts文件 切片文件 hls.js
mpeg-dash http mp4 3gp webm 切片文件 文件列表是mp4webm的dash,可以直接播放

FLV (Flash Video) 是 Adobe 公司推出的另一种视频格式,是一种在网络上传输的流媒体数据存储容器格式。其格式相对简单轻量,不需要很大的媒体头部信息。整个 FLV 由 The FLV Header, The FLV Body 以及其它 Tag 组成。因此加载速度极快。采用 FLV 格式封装的文件后缀为 .flv。

而我们所说的 HTTP-FLV 即将流媒体数据封装成 FLV 格式,然后通过 HTTP 协议传输给客户端。

HLS (HTTP Live Streaming) 则是苹果公司基于 HTTP 的流媒体传输协议。主要应用于 iOS 设备,包含(iPhone, iPad, iPod touch) 以及 Mac OSX 提供音视频直播服务和录制内容(点播)等服务。

相对于常见的流媒体协议,HLS 最大的不同在于它并不是一下请求完整的数据流。它会在服务器端将流媒体数据切割成连续的时长较短的 ts 小文件,并通过 M3U8 索引文件按序访问 ts 文件。客户端只要不停的按序播放从服务器获取到的文件,从而实现播放音视频。

HLS支持AES加密,可以对视频内容进行加密保护;FLV的安全性较差,容易被破解和盗取。

HLS在传输过程中有一定的延迟,通常为几秒到十几秒;FLV的传输延迟较低,可以实现较低的实时性。

HLS使用了自适应码率技术,根据网络条件动态调整码率和缓冲区大小,以提供更好的播放体验;FLV没有自适应码率技术,网络不稳定时容易出现卡顿和缓冲。

总体来说,HLS更适用于移动设备和各种平台的流媒体传输,具有更好的兼容性和安全性;FLV在过去常用于Flash平台上的流媒体传输,现在已经逐渐被其他传输协议所取代。

RTMP 协议为流媒体而设计,在推流中用的比较多,同时大多 CDN 厂商支持RTMP 协议。

卡顿率

视频卡顿率是指在播放视频时出现卡顿现象的频率。具体来说,视频卡顿率是指每秒钟连续播放的视频帧中,有多少帧出现了卡顿现象。常见的视频卡顿原因包括网络缓慢、计算机性能不足、视频文件损坏等。视频卡顿率越低,表示视频播放的流畅程度越高。

PVC

PVC(Perceptual Video Coding)视频感知编码,是一种在保障同等画质的前提下降低带宽消耗的视频编码方式。例如,在带宽受限场景下提升视频流畅性,在移动网络场景下降低流量消耗。

video bitrate

视频比特率(video bitrate)指的是视频编码中每秒传输的比特数。单位为bps(Bit Per Second)。比特率越高,视频的质量越好,但文件大小也越大。因此,在选择视频比特率时需要权衡视频质量和文件大小。较低的比特率会导致视频压缩和失真,而较高的比特率可以提供更清晰的图像和更高的视频质量。

码率

码流(Data Rate)是指视频文件在单位时间内使用的数据流量,也叫码率或码流率,通俗一点的理解就是取样率,是视频编码中画面质量控制中最重要的部分,一般我们用的单位是kb/s或者Mb/s。一般来说同样分辨率下,视频文件的码流越大,压缩比就越小,画面质量就越高。码流越大,说明单位时间内采样率越大,数据流,精度就越高,处理出来的文件就越接近原始文件,图像质量越好,画质越清晰,要求播放设备的解码能力也越高。

帧率

帧率也称为FPS(Frames Per Second)- - - 帧/秒。是指每秒钟刷新的图片的帧数,也可以理解为图形处理器每秒钟能够刷新几次。越高的帧速率可以得到更流畅、更逼真的动画。每秒钟帧数(FPS)越多,所显示的动作就会越流畅。

帧率越高,cpu消耗就高

  • 秀场视频直播,一般帧率20fps
  • 普通视频直播,一般帧率15fps

分辨率

视频分辨率是指视频成像产品所成图像的大小或尺寸。常见的视像分辨率有352×288,176×144,640×480,1024×768。在成像的两组数字中,前者为图片长度,后者为图片的宽度,两者相乘得出的是图片的像素,长宽比一般为4:3.

  • 480P : 640 x 480 个像素点
  • 720P : 1280 x 720 个像素点
  • 1080P : 1920 x 1080 个像素点

帧率、码率与分辨率之间关系

码率和帧率没有半毛钱关系

video.js

https://videojs.com/getting-started

Video.js is an extendable framework/library around the native video element.

全屏 screenfull

videojs的源码,发现可以用screenfull.js这个库直接实现全屏,非常方便。

// 无需自己做浏览器兼容
import screenfull from "screenfull";

if (screenfull.isEnabled) {
    screenfull.request(video);
}

科普

「完全理解」video 标签到底能播放什么

封装与解包

H.264 和 AAC,可以被封装成 MP4 或 FLV。但是 Chrome 只能播放前者而不支持后者,细想其实很没道理。就好比两个东西被装在 A 盒子里的时候能拆开用,但是装在 B 盒子里就不行了

因为本质上重要的是东西(H.264、H.265),而不是盒子(MP4、FLV)

把编码封装成文件的步骤叫做封装(remux),文件拆解成编码的步骤叫解包(demux)

封装,抽象的说其实就是把东西不同排列码到一块

解码器和编码器

解码器(Decoder)和编码器(Encoder)是一对相反的操作。

编码器是将原始数据转换为另一种表示形式的设备或算法。它通过将输入数据映射到一个较低维度的特征空间来捕捉数据的重要特征。编码器常用于数据压缩、特征提取和降维等任务。

解码器是编码器的逆过程。它将经过编码的数据转换回原始表示形式。解码器根据编码器生成的特征向量或码字来重构原始数据。解码器常用于数据恢复、文本生成、图像重建和语音合成等任务。

编码器和解码器通常结合使用,构成了自动编码器(Autoencoder)模型。自动编码器由一个编码器和一个解码器组成,通过训练数据的重构误差来学习数据的压缩表示和重建能力。自动编码器常用于无监督学习、特征学习和生成模型等任务。

硬编解码

通过硬件实现编解码,减轻CPU计算的负担,如GPU等

软编解码

如 H264、H265、MPEG-4等编解码算法,更消耗CPU

多音轨和多声道的区别

多音轨和多声道是两个完全不同的概念:

  • 多音轨指的是在放置音乐元素的位置,可以笼统对应混音设备上的具体轨道。主要是用于音乐制作中。
  • 多声道是指录制采样或者播放时的音源数量,用来营造声音位置效果,声道越多声音的立体感和现场感越强。人们的听觉是通过两只耳朵对声源的反馈,除了对音色,音高的感知以外,还可以通过感知声音的传播速度差异等来确定音源的位置,多声道就是通过不同声道的细微差异而让声音给人们多一些空间感。

SFU架构

SFU(Selective Forwarding Unit)架构是一种常用于实时通信(例如视频会议、直播等)的数据传输架构。在SFU架构中,每个参与通信的终端设备(如用户的电脑、手机等)都与服务器建立连接,并将实时传输的数据(如音频、视频等)发送到服务器。服务器根据数据的特性和终端设备的需求,选择性地将特定的数据转发给其他参与者,而不是将所有数据复制发送给所有终端设备。这样可以减少网络带宽的使用,提高数据传输的效率和质量。

在SFU架构中,服务器起到了中心节点的角色,负责中转和转发数据。它可以对数据进行处理、编解码、混音等操作,以适应不同终端设备的需求和网络环境的限制。终端设备之间则通过服务器进行数据传输,从而实现实时通信。

与传统的点对点通信相比,SFU架构具有一些优势。首先,SFU可以有效地减少网络带宽的消耗。因为服务器只选择性地转发特定的数据,而不是将所有数据复制发送给所有终端设备,可以节省带宽资源。其次,SFU可以提供更好的数据传输质量。服务器可以对数据进行处理、优化和转码等操作,以适应不同的终端设备和网络环境,可以提供更好的音视频质量和更稳定的通信效果。同时,SFU还可以支持更大规模的通信,因为服务器可以同时处理和转发多个终端设备的数据。

总之,SFU架构通过服务器中转和选择性转发数据,可以提高实时通信的效率、质量和可扩展性,广泛应用于视频会议、直播等实时通信场景中。

SRS流媒体服务器

https://ossrs.net/lts/zh-cn/docs/v5/doc/introduction

SRS服务器的作用是实现流媒体的推送、转码和播放功能。

SRS(Simple-RTMP-Server)是一个基于RTMP协议的流媒体服务器,它可以接收RTMP协议的推流,并将其转码为多种格式,包括HTTP-FLV、HLS等,以便在不同的终端设备上进行播放。SRS服务器可以实现实时的音视频数据传输,支持高并发、低延迟的流媒体传输服务。

SRS服务器的主要功能如下:

  1. 接收RTMP推流:SRS服务器能够接收RTMP协议的音视频推流,将其转发到后续流程进行处理。
  2. 转码和转封装:SRS服务器支持对RTMP流进行实时转码和转封装,将其转换为多种格式,方便在不同的终端上播放。
  3. 多协议支持:SRS服务器可以将RTMP流转换为多种协议,如HTTP-FLV、HLS等,以便在不同的设备和平台上进行播放。
  4. 支持HTTP回源:SRS服务器可以从HTTP服务器回源获取流媒体文件,以实现稳定的流媒体传输服务。
  5. 支持弹幕:SRS服务器支持实时弹幕推送功能,可以与弹幕服务进行集成,实现实时的弹幕效果。
  6. 支持多路流媒体处理:SRS服务器可以同时处理多路流媒体数据,支持高并发的流媒体传输服务。

总之,SRS服务器是一个功能强大的流媒体服务器,能够实现实时的推流、转码和播放功能,为用户提供高质量的流媒体传输服务。

GOP

GOP是视频编解码技术中的一种格式,全称为“Group of Pictures”,即一组图片。在视频压缩编码中,视频帧按照一定的顺序分为多个GOP,每个GOP由多个图像组成。GOP的设置可以影响视频的压缩率和质量。常见的视频编码标准如H.264、MPEG-2等也采用了GOP。

I帧、P帧、B帧、IDR帧

  • I帧:帧内编码帧
  • P帧:前向预测编码帧

  • B帧:双向预测内插编码帧。

  • IDR(Instantaneous Decoding Refresh)–即时解码刷新。

P帧是I帧后面相隔1~2帧的编码帧;

P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);

I和IDR帧都是使用帧内预测的。它们都是同一个东西而已,在编码和解码中为了方便,要首个I帧和其他I帧区别开,所以才把第一个首个I帧叫IDR,这样就方便控制编码和解码流程。

一般平均来说,I的压缩率是7(跟JPG差不多),P是20,B可以达到50,可见使用B帧能节省大量空间

弱网优化

  • 播放器Buffer
  • 丢帧策略 (优先丢P帧,其次I帧,最后音频)
  • 自适应码率算法
  • 双向链路优化

问题

设置referrer解决403

抖音视频的url直接在浏览器中打开是没有问题的,直接打开本地的.html文件也是可以正常播放视频的,但访问服务器上的请求过来的页面就无法播放视频,浏览器里按F12查看network发现video标签里的src请求视频资源时报403 Forbiddn 错误。

经过对比发现错误的请求头中多了个Referer

估计请求的是服务器 referer 做了判断,不是正常的referer就拒绝了,可以模拟他们的 referer 请求试下,测试发现, 通过 https 站点打开的页面, 可以正常打开视频链接,在 https 下, 发送的请求是不会带有 Referer 的header 的, 这个时候是可以正常加载视频的. 所以, 我们在 页面的 head 标签内, 增加一行代码,指定浏览器任何情况下都不发送Referer,这样就可以正常加载资源了。

<meta name="referrer" content="no-referrer">

autoplay

https://webkit.org/blog/6784/new-video-policies-for-ios/

<video autoplay> elements will now honor the autoplayattribute, for elements which meet the following conditions:

  • <video> elements will be allowed to autoplay without a user gesture if their source media contains no audio tracks.

  • <video muted> elements will also be allowed to autoplay without a user gesture.
  • If a <video> element gains an audio track or becomes un-muted without a user gesture, playback will pause.
  • <video autoplay> elements will only begin playing when visible on-screen such as when they are scrolled into the viewport, made visible through CSS, and inserted into the DOM.
  • <video autoplay> elements will pause if they become non-visible, such as by being scrolled out of the viewport.

没有音轨的video可以自动播放

有音轨但是muted静音的video可以自动播放

http下无法调用摄像头和麦克风

https://blog.csdn.net/qq_33878858/article/details/114382864

在浏览器地址栏中输入“chrome://flags/#unsafely-treat-insecure-origin-as-secure”

将该选项置为Enabled