
背景
在移动互联网时代,涌现了一大波视频直播平台,例如以淘宝、京东为代表的电商直播,以抖音、快手为代表的娱乐互动直播,以斗鱼、YY为代表的游戏直播,以猿辅导、作业帮为代表的教育直播……

无论是哪种形式的直播,对性能和交互体验的要求都极高。在技术选型上,采用native来落地直播终端也成了业内的默认选择。
来作业帮后也跟同事交流中,得知之前虽然也基于web实现过直播产品,但确实存在较大的性能问题,且出现问题后,由于没有日志,排查起来非常困难。
所以在直播这个领域,看起来确实没前端啥事。不过,在一些简单的场景下,web端直播还是有一定的应用空间的。例如端到端的音视频通话、简单的拉流播放场景。况且,身在一家有直播业务的公司,别人问起时,总也应该对直播能说上个七七八八。既然如此,那我们就一块儿看看直播是咋玩儿的吧。
直播架构

如图所示,一个直播平台包括三个必要部分:推流端、流媒体服务器和拉流端。推流端通过摄像头、麦克风等设备采集音视频数据后推送到流媒体服务器。流媒体服务器将收到的音视频流进行必要的处理后,将视频流传输到拉流端进行播放。
值得注意的是,在实际的应用场景下,为了保证高并发、低延迟和良好的互动体验,往往采用CDN加速。由流媒体源服务器将视频流分发至各级CDN节点,用户就近访问CDN节点获取视频流。
另一方面,底层的流媒体服务很简单,为了满足运营侧在业务层面各种花式玩法,如红包雨、实时讨论、实时弹幕等往往需要在流媒体服务之上进行业务层服务的整合。
采集

推流端第一步是进行视频的采集。视频的采集分为图像采集和音频采集。
图像的采集主要由摄像头等设备拍摄成 YUV 编码的原始数据。图像可以进行采集的源头一般有三种:摄像头、屏幕录制、本地视频文件。
音频的采集主要通过设备将环境中的模拟信号采集成 PCM 编码的原始数据。与图像的采集类似,音频也可以分别从麦克风、系统声音、本地音频文件中采集数据。
预处理

预处理基本成了直播领域的核心诉求了。常见的预处理功能有美颜、水印、滤镜、混音、降噪、特效等。以美颜为例,用户对美颜的有着强烈需求。借用直播从业者的一句话:“80%的主播没有美颜根本没法儿看!”
美颜的实现原理主要是通过「磨皮+美白」来达到整体美颜的效果。专业术语叫「去噪」,即对图像中的噪点进行去除或者模糊化处理。常见的去噪算法有均值模糊、高斯模糊和中值滤波等。由于脸部的每个部位不尽相同,脸上的雀斑可能呈现出眼睛黑点的样子,在对整张图像进行「去噪」处理的时候不能将眼睛也去掉,这个环节中还会涉及到人脸和皮肤检测技术。
视频编码

对原始视频数据进行预处理后,还需要对视频进行编码。编码简单理解就是压缩。因为原始数据非常大,一个时长15分钟的1080p视频,体积就可达到1.24G。直接进行推流的话,效率太低。
现在比较常用的视频编码的方式是H.264,比较常用的音频编码方式是AAC。
除了H.264外,也出现了H.265、VP9、AV1等新一代的编码方式。H.265号称可以在维持画质基本不变的情况下,让数据传输带宽减少至H.264的一半,但目前影响最大、使用最多的还是H.264标准。
视频封装

视频封装就是将所有的处理好的视频、音频或字幕都包装到一个文件容器内呈现给观众,这个包装的过程就叫封装。
为啥要封装?
主要是为了解决同步问题。如果视频中包含音频的话会变得很复杂,需要通过封装的方式给他们打上时间戳,让音频和视频能同步起来,声音对上嘴型。
有哪些封装方式?
视频的封装方式有很多种,像FLV,TS,MP4, MOV, AVI, WMV, MKV等。但在直播平台中,最常用的是FLV和TS。
推流
推流也就是将封装好的视频流传输到流媒体服务器。对于我们来说,需要了解推拉流过程中用到的三种传输协议:rtmp、http-flv和hls。一般情况下,上行推流时,使用rtmp。拉流时视情况采用不同的协议。可以通过下表来认识三种协议之间的不同:

流媒体服务器
流媒体服务器端提供的最核心功能是收集推流端的视频推流,并将其推送给所有观众端。
除此之外,要想适配各终端和平台,服务端还需要对流进行转码,如支持RTMP、HLS、FLV等格式拉流,支持一路转多路适配不同网络和分辨率的终端设备。
另外,为了安全考虑,直播鉴黄也是必不可少的功能。一般可以通过对视频进行截图,然后对图片内容进行分析,根据结果来控制视频流。
常见的流媒体服务器有:SRS、nginx-rtmp、red5等。搭建一个流媒体服务器并不复杂,基于nginx和它的rtmp扩展就可以实现。
在实际场景下,为了高并发和低延迟,流媒体服务源服务器并不直接处理用户请求,而是将视频流分发到遍布世界各地的各级CDN节点。最终由末端的CDN节点来相应用户的请求。

拉流播放
播放端核心功能是去流媒体服务器拉流,选择适合的播放器进行解码播放。对移动端的播放器组件不熟,这里重点说下前端怎么做。
hls协议传输的视频文件是.ts格式的,浏览器video标签可以直接进行播放。如果播放端使用的是hls协议拉流,播放比较简单。针对部分pc下Chrome浏览器不支持hls的情况,可以使用hls.js插件来兼容。
由于http-flv和rtmp这两种协议传输的视频流是.flv格式,浏览器video标签是不能直接播放的。如果播放端使用的http-flv和rtmp进行拉流,可以使用video.js插件来播放。
demo
讲完了直播的核心流程,来做一个简单的demo。
推流端,可以在网上随便找一个视频文件作为视频流数据源。然后使用ffmpeg来推流。
流媒体服务器,使用nginx和rtmp扩展模块来实现,同时支持rtmp和hls协议拉流。
播放端,针对hls协议使用video标签直接播放,针对rtmp协议,使用video.js进行播放。
关于nginx和rtmp模块的安装,假定你已经弄好了,这里不展开去说了。
1)编辑nginx的配置文件,添加如下内容:
http {
location /hls {
# Serve HLS fragments
types {
application/vnd.apple.mpegurl m3u8;
}
root /tmp;
add_header Cache-Control no-cache;
# To avoid issues with cross-domain HTTP requests (e.g. during development)
add_header Access-Control-Allow-Origin *;
}
}
rtmp {
server {
listen 1935;
ping 30s;
notify_method get;
application myapp {
live on;
# 启用hls拉流
hls on;
# m3u8和ts文件的存储目录
hls_path /tmp/hls;
# ts文件切片大小
hls_fragment 5s;
}
}
}
2)检查配置文件,然后重启nginx。
3)推流工具这里使用ffmpeg。关于工具的安装,请按照官方文档进行自行解决,这里不展开说明。在终端执行如下命令进行推流:
ffmpeg -re -i /path/to/your/video.mp4 -c copy -f flv -flvflags no_duration_filesize rtmp://your_ip:1935/myapp/mystream
-re : 表示使用文件的原始帧率进行读取,因为ffmpeg读取视频帧的速度很快,如果不使用这个参数,ffmpeg可以在很短时间就把video.mp4中的视频帧全部读取完并进行推流,这样就无法体现出视频播放的效果了
-i :这个参数表示输入 ,后面
/path/to/your/video.mp4就是输入文件-vcodec copy : -vcodec表示使用的视频编解码器 ,前缀v表示video。后面紧跟的copy 表示复制使用源文件的视频编解码器,比如原文件的编解码器(codec)是h264,则这里就使用h264。
-acodec copy : -acodec表示使用的音频编解码器,前缀a表示audio。后面的copy 表示使用源文件的音频编解码器。
-f flv : -f表示format ,就是强制输出格式为flv,这一步其实也叫封装(mux),封装要做的事就是把视频和音频混合在一起,进行同步。紧跟在后面的
rtmp://your_ip:1935/myapp/mystream表示输出的"文件名",这个文件名可以是一个本地的文件,也可以指定为rtmp流媒体地址。指定为rtmp流媒体地址后,则ffmpeg就可以进行推流。
4)写一个简单的HTML文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>直播demo</title>
</head>
<body>
<video src="http://your_ip:8080/hls/mystream.m3u8" autoplay controls></video>
</body>
</html>
5)在浏览器中访问该文件,就可以看到直播效果了。
前文已经介绍,由于Chrome浏览器不支持hls协议,请使用Safari浏览器进行体验。demo为了省事儿,没添加hls.js进行兼容,大家可以自行兼容。
rtmp协议的直播也比较简单,大家使用video.js来实现,这里不再赘述。提示,rtmp协议的拉流地址为:rtmp://your_ip:1935/myapp/mystream。
注意,需要开始推流后再访问页面才可以看到直播画面。因为未开始推流前,文件mystream.m3u8还没生成。
总结
以上就是本次分享的全部内容,总结一下有四点:
核心流程为:采集、预处理、编码、封装、推流、流媒体服务、分发、拉流、解码、播放
常见直播协议有:RTMP、HTTP-FLV、HLS
常见封装格式有:FLV、TS
常见编码格式有:H.264、H.265、VP9、AV1
希望大家有所收获~
推荐阅读

好文我在看????