浏览器中的音视频知识总结
本文适合使用音视频入门的小伙伴进行阅读。
欢迎关注前端早茶,与广东靓仔携手共同进阶~
作者:广东靓仔
一、前言
广东靓仔最近前阵子看到字节开源了西瓜播放器,感觉还不错。
https://github.com/bytedance/xgplayer
二、视频是什么
视频,其实就是一系列连续播放的图片,如果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)的思路。
编码的流程如下:
四、总结并补充一些概念
分辨率
屏幕是由一个个像素点组成的,我们常见的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左右。
音频是什么
音频这里的概念有点多,我也不太会,如果一次有看不懂的地方,请发在评论区。我改。
声音是由物体振动产生的,振动的快慢(频率)决定了声音的音调(男高音,男低音),振动的幅度决定了声音的大小(音量|响度),振动的物体的特性决定了声音的音色。音调、音量和音色称为声音的三要素。
声音可以用模拟信号来表示的,模拟信号的概念如下:
模拟信号是指用连续变化的物理量表示的信息,其信号的幅度,或频率,
或相位随时间作连续变化,或在一段连续的时间间隔内,
其代表信息的特征量可以在任意瞬间呈现为任意数值的信号。
横轴是时间
PCM
数据,Pulse Code Modulation,包含以下内容:采样大小
一个采样用多少bit存放,常用的16bit,采样大小越大
采样率
1s采样多少次
声道数
左声道、右声道,双声道
音频的比特率(1s种音频的大小)计算方式为
音频码率=采样大小*采样率*声道
44100 * 16 * 2 = 1378.125 kbps
如果是1分钟,需要的大小为
1378.125 * 60 / 8 / 1024 = 10.09 MB
六、音频编码
封装格式
操作音视频必备工具-FFMPEG
FFMPE是音视频处理最常用的开源软件,本文主要介绍它的命令行工具。
首先,安装FFMPEG:
分MAC、WINDOW、LINUX
七、一些概念
支持的封装格式
查看ffmpeg支持的封装格式(container)
ffmpeg -formats
以上输入会很多,可以使用grep过滤,例如我们想查看是否支持FLV格式,可以使用以下命令:
ffmpeg -codecs | grep FLV
支持的编码格式
H.262
H.264
H.265
MPEG-4
常见的音频编码格式如下:
MP3
AAC
查看ffmpeg支持的编码格式,视频编码和音频编码都在内
ffmpeg -codecs
编码器
libx264:最流行的开源 H.264 编码器
NVENC:基于 NVIDIA GPU 的 H.264 编码器
libx265:开源的 HEVC 编码器
libvpx:谷歌的 VP8 和 VP9 编码器
libaom:AV1 编码器
音频编码器
libfdk-aac
aac
以下命令查看已安装的编码器
ffmpeg -encoders
ffprobe查看视频信息
ffprobe是ffmpeg提供的一个命令行工具,用来查看视频元数据以及音视频码流的编码信息等,使用很简单
ffprobe 1.mp4
输出如下:
ffmpeg命令行使用格式
ffmpeg {1} {2} -i {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 -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
# -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
八、视频播放器的原理
先说一下播放器是如何播放视频的,这里的播放器可以是本地的播放器,也可以是浏览器中的播放器。
大概流程如下:
浏览器中音视频知识
为什么有些视频播放不了
音视频解码阶段
,因为浏览器支持的解码器有限,所有有些编码的视频码流浏览器无法解码,流程中断,所以也就无法播放。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的通用属性
常用事件
video和audio通用事件
常用方法
play() 控制视频开始播放
pause() 控制视频暂停播放
有了上述的属性、事件及方法,我们就可以做很多事了,比如自定义播放器,使用播放器本地预览视频等。
浏览器中实现视频播放器的基本思路
整体思路如下:
监听
loadedmetadata
事件,获取视频时长(duration),真实宽高(videoWidth,videoHeight)点击播放/暂停时,调用视频元素的play/pause方法
播放时,监听
timeupdate
,获取当前播放时间(currentTime),计算出进度条的进度拖动进度条,设置视频当前播放时间,与步骤3相反
视频初始加载时,显示loading。即组件初次渲染时,loading属性默认为true,即显示加载效果,当视频元数据加载时,取消loading
视频卡顿时,显示loading。该功能的实现是监听的
waiting
事件,不卡顿时,取消loading,监听的是canplay
事件
九、总结
关注我,一起携手进阶
欢迎关注前端早茶,与广东靓仔携手共同进阶~