Web 视频流处理

现在视频网站有很多,为了补全这块知识,我就通过 PHP 实现读取视频流返回浏览器的功能。这是为了达到隐藏真实链接的目的,但又发现了一些问题,视频无法快进,加载速度慢。通过搜索得到视频是当静态资源一样一次性返回的。而且每次请求都是从头开始的读取视频文件,但是可以使用断点续传的方式来处理快进失败的问题。下面简单的梳理下相关的知识点:

视频流的请求及响应

无处理的请求 mp4 过程

请求头响应头

请求头说明

  • range: bytes=0-

响应头说明

  • Accept-Ranges: none: 不支持范围请求
  • status: 200 OK: 完全返回,一次性返回
  • content-type: video/mp4: 视频类型
  • Content-Length: 554058: 返回内容大小

断点续传式请求 mp4 过程

断点续传请求头响应头

初次请求

请求头

  • Content-Type: video/mp4
  • Range: bytes=0-1023: 请求 1024 byte 大小的视频流

响应头

  • status: 206 Partial Content: 支持范围请求
  • Accept-Ranges: bytes: 内容单位
  • Content-Length: 1024: 内容大小
  • Content-Range: bytes 0-1023/146515: 返回内容范围

后续请求

请求头

  • Content-Type: video/mp4
  • Range: bytes=1024-2047

响应头

  • status: 206 Partial Content:合适的请求范围
  • status: 416 Requested Range Not Satisfiable:超出内容范围的状态
  • Content-Length: 1024: 内容大小
  • Content-Range: bytes 1024-2047/146515: 返回内容范围

程序实现方式

  1. 读取客户端请求头的 Range 要获取的范围
  2. 打开目标文件,获取要读取的范围内容文件流
  3. 组装 206 状态、内容类型、响应范围、响应大小、内容 响应体并返回

扩展

编解码器

音视频通常是以 mp4、avi、mp3等格式展示的,但是这和编解码器没有太大的关联。可以把他当作一个文件夹,文件夹中包含了音频、视频,也可以理解当作承载音频、视频的媒体容器。而音视频又是用编码器实现的。

  • 封装格式、媒体容器、多媒体封装格式都表示文件后缀
  • h.264、h.265 是编码器的编码
  • FPS 帧率(一秒里切换的画面数),24以上比较平滑,30 或 60 是理解的目标

常用的视频编解码器

常用的音频编解码器

WEB 视频播放原理

媒体资源扩展(Media Source Extensions 简称 “MSE”, 是一个现今多数浏览器都遵守的规范。它创建来是为了让 HTML 和 JavaScript 允许那些复杂的媒体用例。在 HTML5 之前网站如果想支持音视频就得在客户端中安装想关辅助软件,如 Flash 插件。官方推出的规范和 Flash 的停止维护让这个推广更快速。

浏览器都有了解析视频的能力,所以 http 请求到视频流就能进行解析播放。

应用场景

  • 视频平台是怎么处理视频的

视频平台除了要注意用户上传的视频内容是否合法外,还需要处理对视频进行处理,如获取视频封面,生成不同的质量的视频。平台一般都有自己研发的工具上传视频,我认识是一种利用用户资源来做视频初始化的方法之一。上传成功就是截取生成不同质量的视频,通常通过 ffmpeg 来实现。

  • 视频通过程序返回会占用带宽

视频一般都会存储在第三方的云存储中,加密以及防盗都由第三方提供。如果仅仅自己使用的话,可以使用断点续传的方式来实现,本地或内网都不需要考虑带宽问题。

  • 直播推流平台

通常使用第三方云服务,自己搭建的话可以参考玩转直播系列之从 0 到 1 构建简单直播系统(1)

FFMPEG 转码

视频网站中我们能看到 360P、480P、720P、1080P 等不同的清晰度,能让用户根据网络情况和流量情况来选择。用户上传的视频有可能使用了奇奇怪怪的视频宽高比例,但是视频比较也不太标准。

常用设置

  • 宽高比
    • 4:3
    • 16:9
  • 360P = 640 * 360 = (40 * 16) * (40 * 9)
  • 720P = 1280 * 720 = (80 * 16) * (80 * 9)
  • 1080P = 1920 * 1080 = (120 * 16) * (120 * 9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 截取视频第1帧当封面
ffmpeg -i upload.mp4 -ss 1 -vframes 1 video_image.jpg

# 分P
ffmpeg -i upload.mp4 -s 1920x1080 -profile:v high upload_720p.mp4

# 查看支持的编码器(-vcodec 可用参数)
ffmpeg -codecs
# 可以通过 Decoders: 说明,根据开头的标识,查看格式支持那些内容项

# 查看支持的封装格式(-f 可用参数)
ffmpeg -formats

# 获取视频的信息
ffmpeg -i upload.mp4

# 切换编解码器
ffmpeg -c:v {upload.mp4 视频解码器} -c:a {upload.mp4 音频解码器} -i upload.mp4 -c:v {输出视频编码器} -c:a {输出音频编码器} outfile.avi
# -c:a 音频解码器 -i 参数前,后为编码器
# -c:v 视频解码器 -i 参数前,后为编码器

获取视频的信息

  • 通过 Stream #0:0[0x1](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, smpte170m/smpte170m/bt709, progressive), 320x240, 80 kb/s, 29.65 fps, 29.97 tbr, 90k tbn (default) 得到当前是视频项,使用 h264 编码器,320x240 宽高比,29.65帧(约等于30帧)等重要信息。
  • 通过 Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 115 kb/s (default) 得到当前为音频项,使用 aac 格式

参数链接