浏览器中的音视频知识总结(工作中需要和音视频打交道必看!)

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

视频是什么

视频,其实就是一系列连续播放的图片,如果1s钟播放24张图片,那么人眼看到的就不再是一张张独立的图片,而是动起来的画面。其中一张图片称为一帧,1s播放的图片数称为帧率。常见的帧率有24帧/s,30帧/s,32帧/s。

视频是由图片构成的,图片是由像素构成的,假设尺寸为 1024*768。每个像素由RGB构成,每个8位,共24位。

这里补充一点2进制的知识

1位10进制数,能够表示0-9,共10种可能
类比一下,1位2进制,能够表示0,1,共表示2种可能性。
一位2进制称为1比特,即1 bit。
byte 字节是计算机计量的基本单位,1 byte= 8bit
1位16进制能够表示0-15,共16种可能性,如果换算成2进制,2^4=16,需要4位二进制才能表示1位16进制数。
1byte=8bit=2个16进制数
像素用16进制表示为 #ffffff,需要6个16进制,也就是3byte

假设帧率是30,那么每秒钟的视频的尺寸如下:

30帧x1024x768x24=566231040Bits=70778880Bytes

一分钟视频的尺寸就是 4246732800Bytes已经是4个G了。

1Byte=8bit
1MB=1024Byte(2^10)
1GB=1024MB(2^20Byte)

可以看到,这个数据量是很大的,不好进行网络传输以及存储,所以需要对视频进行压缩,也就是编码。

编码过程

之所以能够对视频的中图片进行压缩,是因为视频和图片具有以下特点:

  • 空间冗余:图像的相邻像素之间有较强的相关性,一张图片相邻像素往往是渐变的,不是突变的,没必要每个像素都完整地保存,可以隔几个保存一个,中间的用算法计算出来。

  • 时间冗余:视频序列的相邻图像之间内容相似。一个视频中连续出现的图片也不是突变的,可以根据已有的图片进行预测和推断。

  • 视觉冗余:人的视觉系统对某些细节不敏感,因此不会每一个细节都注意到,可以允许丢失一些数据。

  • 编码冗余:不同像素值出现的概率不同,概率高的用的字节少,概率低的用的字节多,类似霍夫曼编码(Huffman Coding)的思路。

编码的流程如下:

2dbed722072aa697d5efcd788c9a0ccb.pngimage-20210828223514420

经过编码之后,视频由一帧帧的图片,变成了一串串让人看不懂的二进制代码,因为编码的方式(算法)的不同,所以就有了编码格式的区分。常见的编码格式有 H.264,MPEG-4,VP8等。

这里需要注意的一点是,因为编码格式是有版权问题的,所以不同的浏览器支持的编码格式不同,所以就会出现有些编码格式的视频在某些浏览器播放不了,或者只有声音没有画面的情况。

我们前端开发只需要记住一点,「主流浏览器支持的视频编码格式是h264」

总结并补充一些概念

分辨率

屏幕是由一个个像素点组成的,我们常见的1080p,是指屏幕竖直方向有1080个像素,共有1920列,一共207万像素。2K,2560x1440,共369万像素。

放一个百度百科的解释

显示分辨率(屏幕分辨率)是屏幕图像的精密度,是指显示器所能显示的像素有多少。由于屏幕上的点、线和面都是由像素组成的,显示器可显示的像素越多,画面就越精细,同样的屏幕区域内能显示的信息也越多,所以分辨率是个非常重要的性能指标之一。可以把整个图像想象成是一个大型的棋盘,而分辨率的表示方式就是所有经线和纬线交叉点的数目。显示分辨率一定的情况下,显示屏越小图像越清晰,反之,显示屏大小固定时,显示分辨率越高图像越清晰。

分辨率对视频体积有一定影响,但是不是分辨率越大,视频越清晰,还要看码率。

###帧率FPS

每秒显示的帧数,就是1s播放的图片数量(Frames per Second)。

百度百科解释:

由于人类眼睛的特殊生理结构,如果所看画面之帧率高于24的时候,就会认为是连贯的,此现象称之为视觉暂留。这也就是为什么电影胶片是一格一格拍摄出来,然后快速播放的。
而对游戏,一般来说,第一人称射击游戏比较注重FPS的高低,如果FPS<30的话,游戏会显得不连贯。所以有一句有趣的话:“FPS(指FPS游戏)重在FPS(指帧率)。
每秒的帧数(fps)或者说帧率表示图形处理器处理场时每秒钟能够更新的次数。高的帧率可以得到更流畅、更逼真的动画。一般来说30fps就是可以接受的,但是将性能提升至60fps则可以明显提升交互感和逼真感,但是一般来说超过75fps一般就不容易察觉到有明显的流畅度提升了。如果帧率超过屏幕刷新率只会浪费图形处理的能力,因为监视器不能以这么快的速度更新,这样超过刷新率的帧率就浪费掉了。

码率(比特率)

码率,也叫比特率,帧率是1S播放多少帧,类比一下,比特率就是1s的视频有多少bit。

这个参数决定了视频是否清晰。

一个1080P的视频,大小可以为1G,也可以为4G,视频越大,说明1S存放的数据越多,比特率越高,压缩比越小,视频越清晰。

1080P,长度为100分钟,大小为1GB的视频的比特率是多少?

总时间为
100分钟=100X60S=6000s
总数据量为
1GB=1024MB= 1024X1024KB=1024X1024X1024Byte=1024X1024X1024X8bit=8589934592bit
帧率为 (数据量/时间)
8589934592/6000 = 1.4Mbit/s

帧率和分辨率都可以影响视频体积,但是帧率是主要因素,在工作中如果看到一个很短的视频非常大,很大可能性是因为帧率很大,为了便于网络传输,需要降低帧率。一般来说主流视频平台的帧率在1Mbit/s左右。

音频是什么

音频这里的概念有点多,我也不太会,如果一次有看不懂的地方,请发在评论区。我改。

声音是由物体振动产生的,振动的快慢(频率)决定了声音的音调(男高音,男低音),振动的幅度决定了声音的大小(音量|响度),振动的物体的特性决定了声音的音色。音调、音量和音色称为声音的三要素。

声音可以用模拟信号来表示的,模拟信号的概念如下:

模拟信号是指用连续变化的物理量表示的信息,其信号的幅度,或频率,或相位随时间作连续变化,或在一段连续的时间间隔内,其代表信息的特征量可以在任意瞬间呈现为任意数值的信号。
699c4545ae7e66a3f5f13e4ac1673ef6.png

横轴是时间

模拟信号是连续的,在传输时特别容易受干扰,所以在模拟信号在传输时经常要转化成不连续的数字信号。转化的过程主要包括:采样、量化、编码等过程。

你可以把采样理解为打点,在0-1s内打48000个点,就采样了48000次,采样率就是48000。

b8b0a7675d7b7daf3f139ed7e00867a1.png

量化是指在纵轴(y轴)上对声音进行数字化,决定了y轴的范围。比如用16bit的数据表示声音的一个采样,16bit表示的范围是[-32768,32767],供65536个可能的取值。

编码就是按照一定的格式记录采样和量化之后的数据。音频的原始数据是PCM数据,Pulse Code Modulation,包含以下内容:

  • 采样大小

    • 一个采样用多少bit存放,常用的16bit,采样大小越大

  • 采样率

    • 1s采样多少次

  • 声道数

    • 左声道、右声道,双声道

音频的比特率(1s种音频的大小)计算方式为

音频码率=采样大小*采样率*声道

以 CD 的音质为例:量化格式为 16 bit (2 byte),采样率 44100 ,声道数为 2,,存放1s钟音频数据需要的大小为

44100 * 16 * 2 = 1378.125 kbps

如果是1分钟,需要的大小为

1378.125 * 60 / 8 / 1024 = 10.09 MB

本段参考内容:

  • 百度百科-模拟信号及模数转换

  • 百度百科-数字信号

  • 音视频学习-掌握音频基础知识

音频编码

CD音质的音频,存放一分钟数据需要的大小为10M,太大了,也需要压缩(编码)。编码的过程大概如下:

3819c859a68b0ce4f5df7874183d2b4e.png

常见的编码方式有:WAV、MP3和AAC格式。

音频的编码方式不像视频那样那么多,而且音频在各个浏览器基本上都可以播放。

具体的每种编码格式包含的音频是怎么构成的,这里就不讲了。

封装格式

我们把视频数据、音频数据打包到一起,然后再添加一些基本信息,例如分辨率、时长、标题等,构成一个文件,这个文件称为封装格式。常见的封装格式有MP4,MOV,MPEG,WEBM等。

主要封装格式如下:

名称 推出机构 流媒体(边下边播) 支持的视频编码 支持的音频编码 目前使用领域
MP4 MPEG 支持 MPEG-2,MPEG-44,H.264等 AAC,MPEG-1等 互联网视频网站
TS MPEG 支持 MPEG-4,H.264等 MPEG-1 Layers I, II, III, AAC, IPTV,数字电视
FLV Adobe Inc. 支持 Sorenson, VP6, H.264 MP3, ADPCM, Linear PCM, AAC等 互联网视频网站
MKV CoreCodec Inc. 支持 几乎所有格式 几乎所有格式 互联网视频网站
AVI Microsoft Inc. 不支持 几乎所有格式 几乎所有格式 BT下载影视






从上表中可以看到,封装格式往往是与视频编码无关的,一个mp4文件,里面的视频流编码可以是h264,也可以是mpeg-4,所以就会出现,同样都是mp4文件,有的浏览器可以放,有的浏览器就放不了的问题,因为能不能放是由视频码流的编码格式决定的。

上表参考自:

  • 视音频编解码技术零基础学习方法-雷霄骅

说完了一些理论知识,下面开始实践一下。

操作音视频必备工具-FFMPEG

A complete, cross-platform solution to record, convert and stream audio and video.

FFMPE是音视频处理最常用的开源软件,本文主要介绍它的命令行工具。

首先,安装FFMPEG,

  • MAC安装FFMPEG

  • WINDOS安装FFMPEG

  • LINUX安装FFMPEG

装不上请自行百度。

一些概念

支持的封装格式

复习一下,我们常见的视频文件,其实是一个容器,里面包含的视频数据、音频数据、字幕(非必须)及一些元数据(视频标题,时长,分辨率信息)等。常见的封装格式有(通过后缀名反映封装格式)

MP4MKVWebMAVI

查看ffmpeg支持的封装格式(container)

ffmpeg -formats

以上输入会很多,可以使用grep过滤,例如我们想查看是否支持FLV格式,可以使用以下命令:

ffmpeg -codecs | grep FLV

支持的编码格式

上面说过,音视频文件需要经过编码压缩,才能保存为文件。不同的编码格式有不同的压缩率,导致不同的清晰度和文件大小。

常见的视频编码格式如下:

H.262H.264H.265MPEG-4

常见的音频编码格式如下:

MP3AAC

查看ffmpeg支持的编码格式,视频编码和音频编码都在内

ffmpeg -codecs

编码器

编码器(encoders)是实现某种编码格式的库文件,只有安装了某种格式的编码器,才能实现对应格式视频/音频的编解码。

FFMPEG内置的视频编码器

libx264:最流行的开源 H.264 编码器NVENC:基于 NVIDIA GPU 的 H.264 编码器libx265:开源的 HEVC 编码器libvpx:谷歌的 VP8 和 VP9 编码器libaom:AV1 编码器

音频编码器

libfdk-aacaac

以下命令查看已安装的编码器

ffmpeg -encoders

ffprobe查看视频信息

ffprobe是ffmpeg提供的一个命令行工具,用来查看视频元数据以及音视频码流的编码信息等,使用很简单

ffprobe 1.mp4

输出如下:

63b3e4205d19deded1bd2c614d706799.png

ffmpeg命令行使用格式

ffmpeg {1} {2} -i {3} {4} {5}

五个部分的参数依次如下:

  1. 全局参数

  2. 输入文件参数

  3. 输入文件,必需

  4. 输出文件参数

  5. 输出文件,必需

举个简单的栗子:

ffmpeg -i 1.mp4 output.webm

上面的代码是把封装格式为mp4的文件转成封装格式为webm格式的文件,只输入了输入文件和输出文件。

以上代码没有指定视频码流的编码格式的音频码流的编码格式,ffmpeg会自动选择编码格式具体选择的是什么编码格式,可以等转换完成之后自己使用ffprobe查看一下。ffprobe output.webm

如果只想转换封装格式,编码格式不变,可以在输出文件参数那里添加-c copy

ffmpeg -i 1.mp4 -c copy output.avi

常见参数

  • -c:指定编码器

  • -c copy:直接复制,不经过重新编码(这样比较快)

  • -c:v:指定视频编码器

  • -c:a:指定音频编码器

  • -i:指定输入文件

  • -an:去除音频流

  • -vn:去除视频流

  • -preset:指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。

  • -y:不经过确认,输出时直接覆盖同名文件。

常见用法

建议新建个文件夹,把所有的命令都试验一遍吧

查看视频信息

使用ffprobe查看视频信息

参数格式:ffprobe [options] [input_file]

# 最简单用法
ffprobe 1.mp4
# 不显示欢迎信息,只显示流相关信息
ffprobe -hide_banner 1.mp4
# 以json形式显示每个流信息
ffprobe -print_format json -show_streams 1.mp4
# 显示容器格式相关信息
ffprobe -show_format 1.mp4

参数说明:

  • hide_banner 不显示欢迎信息和配置信息,只显示视频元数据

  • show_format 显示容器格式相关信息

转换编码格式

转换容器格式和编码格式。

如果没有手动指定封装格式中视频流和音频流的编码格式,ffmpeg会根据输出的封装格式自行决定使用什么编码。

ffmpeg -i input.mp4 output.mpeg

指定视频码流编码格式。

转化为H.264编码,一般使用编码器libx264

# 转化为 H.264格式
ffmpeg -i 1.mp4 -c:v libx264 output.mp4
# 转化为 H.265格式
ffmpeg -i 1.mp4 -c:v libx265 output-265.mp4

参数说明:

  • -c:v 指定视频编码器

  • -c:a 指定音频编码器

转换容器格式

mp4转为avi

ffmpeg -i input.mp4 -c copy output.avi

上面例子中,只是转一下容器,内部的编码格式不变,所以使用-c copy指定直接拷贝,不经过转码,这样比较快

# 不使用 -c copy参数,ffmpeg会自己判断输入文件的编码
ffmpeg -i input.mp4 output.webm

转换时可以手动指定编码格式

# 转换时可以手动指定编码格式
ffmpeg \\
-y \\ # 全局参数
-c:a libfdk_aac -c:v libx264 \\ # 输入文件参数
-i input.mp4 \\ # 输入文件
-c:v libvpx-vp9 -c:a libvorbis \\ # 输出文件参数
output.webm # 输出文件

调整码率(比特率)

调整码率指的是,改变编码的比特率,一般用来将视频文件的体积变小。

比特率计算:视频多少比特(bit)/视频时长(s)

例如一个视频是2.6M 换算成比特 2.6x1024x1024x8=21810380.8 bit

视频是22s

比特率:21810380.8/22=991 Kb/s

设置码率:

# 设置输出的码率为1.5M,ps:最后的输出视频码率会有一些小的偏差
ffmpeg -i input.mp4 -b 1.5M output.mp4
# 默认情况下,ffmpeg使用可变比特率(VBR)进行设置,静态的画面使用较少的码率,动态的画面使用较多的码率

参数说明

  • -b 指定视频流和音频流总体的比特率

  • 可以使用-b:v -b:a 分别指定视频流和音频流的比特率

也可以手动指定 最小比特率,最大比特率,以及缓冲区的大小:

ffmpeg -i input.mp4 -minrate 964k -maxrate 3856k -bufsize 2000k output.mp4

如果是视频会议之类的实时视频流,可以使用固定码率(CBR):

固定码率是指所有的画面使用相同的码率

# -b -minrate -maxrate 需要指定固定的值,maxrate需要指令一个bufsize(缓冲区大小)
ffmpeg -i input.mp4 -b 0.5M -minrate 0.5M -maxrate 0.5M -bufsize 1M output.mp4

改变分辨率

# 将分辨率调整为640*480 
ffmpeg -i input.mp4  -vf scale=640:480 output.mp4

# 按照原比率进行调整
ffmpeg -i input.mp4 -vf scale=480:-1 output.mp4

参数说明

  • vf 滤镜

  • vf scale 调整分辨率

分离视频(去除视频中的音频)

# ffmpeg -i input.mp4 -c:v copy -an output.mp4

参数说明

  • an 去除音频流

分离音频

ffmpeg -i input.mp4 -vn -c:a copy output.aac

参数说明

  • vn 表示去掉视频

  • c:a copy表示不改变音频编码

添加音轨

将外部音频加入视频,比如添加背景音乐或者旁白

# 如果视频原来有声音,不会添加成功,所以需要先去除视频中原来的音频
# 输入有两个文件,ffmpeg会将它们合成为一个文件
ffmpeg -i input.aac -i input.mp4 output.mp4

截图

从指定时间开始,连续对1秒钟的视频进行截图

# 从00:00:05s开始,连续对1秒钟的视频进行截图
ffmpeg -y -i input.mp4 -ss 00:00:05 -t 00:00:01 output_%3d.jpg

如果只需要截取一帧

# 从00:00:10s开始截取一帧
ffmpeg -ss 00:00:10 -i input -vframes 1 -q:v 2 output.jpg

参数说明

  • vframes 1 指定只截取一帧

  • q:v 2表示输出图片的质量 一般是1至5之间

分割一个mp4文件到多个小的mp4文件

可以指定开始时间和持续时间,也可以指定结束时间

ffmpeg -ss <start> -i <input> -t <duration> -c copy <output>
ffmpeg -ss <start> -i <input> -to <end> -c copy <output>

示例:

# 将视频从0s分割到5s的位置 
ffmpeg -ss 00:00:00 -i 1.mp4 -c copy -t 5 aqgy-1.mp4
# 示例:将一个1分30s的视频分成4段
ffmpeg -ss 00:00:00 -i 1.mp4 -c copy -t 00:00:22 aqgy-1.mp4
ffmpeg -ss 00:00:22 -i 1.mp4 -c copy -t 00:00:22 aqgy-2.mp4
ffmpeg -ss 00:00:44 -i 1.mp4 -c copy -t 00:00:22 aqgy-3.mp4
ffmpeg -ss 00:01:06 -i 1.mp4 -c copy -t 00:00:22 aqgy-4.mp4

视频播放器的原理

先说一下播放器是如何播放视频的,这里的播放器可以是本地的播放器,也可以是浏览器中的播放器。

大概流程如下:

ef0ee9dbfdaaa03bb54b83def05631b3.png

「解协议」的作用,就是将流媒体协议的数据,解析为标准的相应的封装格式数据。流媒体协议主要包括RTMP,HLS以及HTTP等。比如一个HTTP的视频链接,http://111.229.14.189/file/1.mp4,经过解协议之后,会得到1.mp4封装格式的视频

「解封装」:解封装就是将音频码流和视频码流从1.mp4文件中分离出来。1.MP4文件经过解封装后,会得到编码格式为h264的视频压缩数据和编码格式为aac的音频压缩数据。

「音视频解码」:将压缩的音视频数据转化原始的数据,视频的原始数据就是一帧帧的图像,音频的原始数据就是YUM数据。

「视音频同步」的作用,就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。

我们在浏览器中打开http://111.229.14.189/file/1.mp4,流程大概就是上面的那些。

浏览器中音视频知识

为什么有些视频播放不了

浏览器播放一个视频的流程上面刚讲过,在音视频解码阶段,因为浏览器支持的解码器有限,所有有些编码的视频码流浏览器无法解码,流程中断,所以也就无法播放。

前端开发的需要记住,视频编码为h264,音频编码为aac的MP4文件在各大浏览器都能播放,因为h264编码格式虽然有版权,但是可以免费使用。

音视频标签

<video controls poster="1.jpg" src="1.mp4" loop muted></video>
<audio controls src="1.mp3"></audio>

src指定资源地址,poster为视频指定一张封面图,controls表示浏览器应该显示UI控件(每个浏览器样式不同)

常用属性

下面是video和audio的通用属性

98814f45da1d5faa7eab621d5e88dc34.png

常用事件

video和audio通用事件

953cf62d7bff94fad99b5082992c2c98.png

常用方法

  • play() 控制视频开始播放

  • pause() 控制视频暂停播放

有了上述的属性、事件及方法,我们就可以做很多事了,比如自定义播放器,使用播放器本地预览视频等。

浏览器中实现视频播放器的基本思路

整体思路如下:

  1. 监听loadedmetadata事件,获取视频时长(duration),真实宽高(videoWidth,videoHeight)

  2. 点击播放/暂停时,调用视频元素的play/pause方法

  3. 播放时,监听timeupdate,获取当前播放时间(currentTime),计算出进度条的进度

  4. 拖动进度条,设置视频当前播放时间,与步骤3相反

  5. 视频初始加载时,显示loading。即组件初次渲染时,loading属性默认为true,即显示加载效果,当视频元数据加载时,取消loading

  6. 视频卡顿时,显示loading。该功能的实现是监听的waiting事件,不卡顿时,取消loading,监听的是canplay事件

音视频领域的一些学习资源推荐

国内学习音视频相关的开发,绕不过的一个大神是 雷霄骅,大佬已经去世了,但是留下的文章永垂不朽。

推荐从这篇文章开始阅读[总结]视音频编解码技术零基础学习方法,从这个点开始,遇到跳转的链接感兴趣的就点过去,由点及面。

国内李超的课程还不错,如果对直播webrtc有需求的,可以查看这个专栏从零打造音视频直播系统 这个是放在我的服务器上的,带宽很低,人多会卡,谨慎访问。

如果你是小白,可以看下李超的编程必备基础-音视频小白系统入门课课程的5、7、8、9、10章,讲的是一些必备的理论知识。

如果对ffmpeg感兴趣的话,可以看下这个教程,英文的,github点赞6千8,https://github.com/leandromoreira/ffmpeg-libav-tutorial

作者:_红领巾 https://juejin.cn/post/7002288264413446157

Node 社群


我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:

1. 点个「在看」,让更多人也能看到这篇文章2. 订阅官方博客 www.inode.club 让我们一起成长

点赞和在看就是最大的支持❤️

猜你喜欢

转载自blog.csdn.net/xgangzai/article/details/124580792