【青训营】走进web多媒体技术

252 阅读7分钟

什么是Web多媒体技术

随着近几年短视频的流行,包括各大直播,音视频的技术学习又被提上新的热度。web场景的音视频技术也得到了新的应用和突破

Web前端

交互体验、前端工程化、跨端能力...

数字多媒体

音视频原理、封装容器、编解码算法...

  • 点播 按照客户的需求,返回一段固定时长的视频,包括短视频(抖音),中视频(B站),长视频(电视剧、电影)
  • 直播 将用户的画面和声音推送到客户端,供其他用户观看浏览
  • 图片 图片下发、下载的网络链路监控诊断,图片格式的兼容性调整,图片的动态编辑
  • 实时通信 高质量低延迟的音视频通信能力,视频会议,在线教育,互动娱乐
  • 云游戏 运行在服务端,降低客户端的要求,对音视频的低延迟要求非常高
  • 视频编辑 对视频的解码和合成

音视频基础知识

image-20210918111923471.png

我们平时说的分辨率就是像素点,每个像素点里面又有3个子像素点,分别对应着RGB三个颜色通道

视频是由一系列连续的图像组成的,按照一定时间连续播放,速率就是我们所说的帧率,例如24帧就是每秒播放24张画面

假设8bit表示一个子像素,清晰度1280*720,帧率25fps,时长60s

未压缩视频大小 = 8bit * 3 * 1280 * 720 * 25 * 60 = 3.9G

经过H264压缩后视频大小 = 11MB

压缩比360:1

所以我们在视频生产之后需要对视频进行压缩调整,使得我们在传输和下载的过程中节省流量

视频编码:

未压缩视频---->编码器---->压缩后存储、传输

视频解码:

已压缩视频---->解码器---->还原出初始像素

image-20210918112437066.png

假设上面左边是某个视频里面的某一帧,我们发现在蓝天部分,每一个小块的信息相似度非常高,例如左上角的四个小块,可以近似的使用一个小块的信息代替其他三个,也就是说只需要保存一个小块的信息,就能还原四个小块的信息,这样就可以节省很多容量,如果我们通过算法,把每个小块的信息冗余消除,那么需要存储的变量是非常小的。

上面说的是空间范围内的,我们现在看右边的时间范围内的,假设上下是两帧图像,那么在这两帧中,有大量的冗余信息,包括草地、足球、场地等等,那么我们可以通过算法,只记录第一帧的画面,然后在第二帧只记录与第一帧不同的信息,那么也可以达到节省存储的目的。

编码格式发展:

image-20210918113848487.png

我们的编码技术随着需求也在不断进步,新的编码技术压缩率更高,背后的算法复杂度也更高,对我们的硬件要求也更高

H.264是在浏览器兼容性最好的,应用非常广泛

下面是谷歌公司开发的编码技术

容器封装格式:

我们将视频通过编码器进行编码之后,得到的是“裸流”,如果直接播放,只能从头播放到尾,不能进行中间操作。所以我们需要将裸流进行包装,放在固定格式的文件中,这个文件就是音视频裸流的“容器”,包括meta信息,时长、帧率、数据帧的尺寸、位置。

image-20210918114111505.png

浏览器提供的原生多媒体能力

我们想要在浏览器播放音视频,最简单的方法就是使用video和audio元素

<!DOCTYPE html>
<html>
    <body>
        <video autoplay=true controls="controls" width=600 height=300>
            <source src="//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4">
        </video>
        <audio controls src="//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/music/audio.mp3">
        </audio>
    </body>
</html>

作用:解码+渲染 编码格式使用的是H.264

支持视频格式:MP4、MP3

image-20210918120549789.png

<!DOCTYPE html>
<html>
    <body>
        <button onclick = "palyVid()">播放视频</button>
        <button onclick = "pauseVid()">暂停视频</button>
        <button onclick = "loadVid()">重新加载视频</button>
        <video id="vs" src="demo.mp4"></video>
        <script>
            const myVideo = document.getElementById("vs")
            
            function playVid(){
                myVideo.play()
            }
            
            function pauseVid(){
                myVideo.pause()
            }
            
            function loadVid(){
                myVideo.load()
            }
        </script>
    </body>
</html>

image-20210918120952522.png

<!DOCTYPE html>
<html>
    <body>
        <button onclick = "getVolume()">当前播放音量</button>
        <button onclick = "setVolume()">设置播放音量</button>
        <button onclick = "getCurTime()">获取当前播放时间</button>
        <button onclick = "setCurTime()">设置播放时间</button>
        <video id="vs" src="demo.mp4"></video>
        <script>
            const myVideo = document.getElementById("vs")
            
            function playVid(){
                alert(getVolume.play())
            }
            
            function pauseVid(){
                myVideo.volume = 0.2
            }
            
            function playVid(){
                alert(myVideo.currenTime)
            }
            function pauseVid(){
                myVideo.currenTime = 5
            }
        </script>
    </body>
</html>

image-20210918121511049.png

video和audio的缺点

  • 不支持直接播放hls、flv等视频格式

  • 视频资源的请求和加载无法通过代码控制

    • 分段加载(节约流量)
    • 清晰度无缝切换
    • 精确预加载

主流视频网站使用video元素

image-20210918121907858.png

上面这个demo可以看出,video元素在请求的时候,请求类型是media,代表这个请求是浏览器的媒体元素自己内部发出的

image-20210918121837177.png

上面这个YouTube的video使用,但是src并不是直接把视频的地址赋给src,而是一个blob开头的资源链接,资源请求的类型是xhr,是web端通过js主动发出的http请求,是可以通过js代码主动进行控制的

MediaSource

image-20210918122420557.png

扩展浏览器视频播放能力,支持视频分段加载(直接传入fmp4分片),替代flash播放器

支持播放MP4(实现流式播放)、hls、flv等

可实现视频分段加载,清晰度无缝切换、精确预加载等

上面YouTube使用的就是这种技术

let mimeCodec = "video/mp4; codecs='avc1.42E01E,mp4a.40.2'"
let mediaSource = new MediaSource()
​
​
video.src = URL.createObjectURL(mediaSouce)
mediaSource.addEventListener('sourceopen',()=>{
    let mediaSource = this
    let sourceBuffer = mediaSource.addSourceBuffer(mimeCodec)
    fetchAB('frag_bunny.mp4',function(buf){
        souceBuffer.addEventListener('updateend',function(){
            video.play()
        })
        sourceBuffer.appendBuffer(buf)
    })
})
​
function fetchAB(url,cb){
    let xhr = new XMLHttpRequest
    xhr.open('get',url)
    xhr.responseType = 'arraybuffer'
    xhr.onload = function(){cb(xhr.response)}
    xhr.send( )
}

image-20210918180435191.png

上面是MP4视频文件的结构,是由一个个单元组成的,最上层是三个类型的单元组成

  • ftyp 格式信息
  • moov 视频源信息,meta信息,包括声轨等信息
  • mdat 源数据

image-20210918180540197.png

这上面是fMP4视频文件结构,我们发现前面两个单元跟MP4是一样的,但是后面就是一个个的段落,对音视频进行分段保存

使用mse实现MP4流式播放

image-20210918181525014.png

先请求资源,然后H.264拿到裸流,封装成fmp4,然后放到mse里面,然后就可以播放啦

Web多媒体技术的发展和突破

加密音视频播放

image-20210918181654063.png

我们平时看的电视剧或者电影,视频网站都会做防盗的处理,如果不做就可以直接使用检查工具查看资源。

我们在请求的时候,下发的是加密资源,下载到客户端之后再进行解密播放

自适应码率(ABR)

image-20210918181942013.png

我们在B站看视频的时候,清晰度选择里面有一个“自动”的选项,就是在我们的网络环境变差或者播放器缓存非常高的的时候,自动切换到低码率的状态,降低视频卡顿,使用户能尽可能的进行流畅的视频观看

弹幕

弹幕使视频网站焕发了新的生机,弹幕现在基本上是每个视频网站的必备

image-20210918182332233.png

  • 无碰撞
  • 交互弹幕
  • 防挡人像

软解:实现Web端播放H.265格式和国产浏览器防劫持

web浏览器一般只支持H.264,但是H.265格式的压缩率比较高,所以H.265需求也是非常高,一般使用H.265就是使用webassembly技术,它支持将c语言的文件编译成js可以调用的,其实就是将c语言编译的H.265解码器,转译成js可以调用的形式,然后再浏览器中请求到资源之后,就用webassembly转译的解码器进行解码,解码的视频原始像素信息之后,使用webgl进行渲染

音频一般是AudioContext API进行解码播放,处理音视频同步问题

软解的另一个使用途径是防止国产浏览器的劫持,如下,某国产浏览器会将播放器进行替换,增加一些功能,那么我们原始的播放器的api都会被替换

劫持的原理就是检测页面的video标签,软解是webgl进行渲染,不适用video标签

image-20210918182655512.png

网页推流

有直播需求的小伙伴知道,我们在直播的时候是需要下载OBS这个软件的,它获取到你要发送的音视频流,然后打包发送,现在只需要打开一个网页就可以完成推流,非常方便

image-20210918183614442.png

图片解码

因为图片格式的不同,有些格式不能被浏览器渲染,这就需要工程师对图片进行解码渲染

image-20210918183714474.png

云游戏原理和特点

image-20210918183834601.png

云游戏就是游戏运行在远端的服务器上,然后服务器根据游戏的运行,将音视频画面推送给客户端

云游戏主要两个特点

  • 无需安装、对硬件要求低
  • 低延迟、强兼容性要求