了解HLS实时流看这篇就够了

技术运维

什么是 HTTP 实时流(HLS)?

HTTP 实时流(HLS)是使用最广泛的视频流协议之一。尽管它称为 HTTP“实时”流,但它同时适用于点播流和实时流。HLS 将视频文件分解为较小的可下载 HTTP 文件,并使用 HTTP 协议来交付。客户端设备加载这些 HTTP 文件,然后将它们作为视频进行播放。

HLS 的一个优点是,所有连入互联网的设备都支持 HTTP,因而它比需要使用专用服务器的流协议更易于实施。另一个优点是 HLS 流可以根据网络状况提高或降低视频质量,而不会中断播放。这就是在用户观看视频的过程中视频质量可能会变好或变差的原因。这个功能称为“自适应比特率视频传输”或“自适应比特率流式传输”,如果没有它,慢速网络条件可能导致视频播放完全停止。

HLS 由 Apple 为 Apple 产品开发,但现在已广泛用于许多设备。

HLS常用于各大电影电视剧等视频网站。

为什么播放视频使用HLS(.m3u8)而不是mp4文件?

关于.m3u8文件

m3u8文件是一种用于表示媒体播放列表的文件格式,通常用来描述 HLS(HTTP Live Streaming)流媒体,用于在线视频流和音乐播放列表。它通常包含一系列媒体文件的路径或 URL,所以我们在一个视频网站播放的时候打开Chrome的开发者工具,会看到它不断地在加载.ts文件片段:

视频播放列表中的ts文件

同样mp4也可以在页面做视频播放,为什么HLS更胜一筹?

其根本原因主要在于 HLS 的特性更适合 流媒体传输,尤其是实时直播、视频点播等应用场景。以下是一些关键原因:

1. 支持分片传输

HLS 将视频分割成许多小片段(通常是 2-10 秒的 .ts 文件),通过 M3U8 文件中的 URL 进行有序传输,而 MP4 是一个完整的视频文件。这带来了几个优势:

  • 更好的网络适应性:HLS 的分片机制使得它可以根据网络状况灵活调整传输质量。例如,当网络质量不好时,客户端可以自动请求低分辨率的片段,而无需重新加载整个视频。
  • 分段加载:用户只需要加载当前播放片段,而不必像 MP4 那样一次性下载整个文件,适合长视频或直播场景。

2. 实时直播支持

HLS 是专为 实时直播 设计的,允许不断添加新的视频片段,使客户端可以边下载边播放最新的视频内容。这在以下场景中尤为关键:

  • 低延迟直播:HLS 支持实时直播,并可以通过减少片段长度和减少缓冲时间来降低延迟。
  • 动态更新:M3U8 文件可以动态更新,添加新的流片段,适用于直播和长时间的活动,比如体育赛事、新闻直播等。

MP4 则更适合用于 预录制的视频播放,不太适合用于实时场景。

3. 多码率自适应 (ABR)

HLS 支持多种码率和分辨率的切换,也叫做 自适应比特率流 (Adaptive Bitrate Streaming, ABR)。这意味着,HLS 可以根据用户的网络带宽自动选择合适的码率和分辨率:

  • 用户体验更好:用户在网络状况良好的时候可以看到高清内容,而在网络波动或减速时,HLS 会自动切换到较低的分辨率,以保证播放流畅,而不会发生长时间的缓冲。
  • 避免卡顿:对于移动设备和不稳定的网络环境(如 4G 切换 Wi-Fi 等),ABR 能够确保用户体验较少的中断。

MP4 不支持动态码率切换,播放时网络波动可能导致缓冲或停止。

4. 渐进式下载与即时播放

HLS 支持边下载边播放,特别是在大型视频文件或者直播场景中,用户无需等待完整的视频下载完成就可以开始播放。而 MP4 视频通常是一个整体文件,虽然也可以边下载边播放,但加载速度和播放体验不如 HLS 流畅,特别是视频较大的情况下。

5. 内容保护与加密支持

HLS 支持 AES-128 加密,可以对流媒体进行端到端的加密,保护视频内容,防止未授权的访问。对于流媒体平台,版权保护至关重要。

  • DRM 集成:HLS 可以与各种数字版权管理(DRM)技术结合,进一步保护流媒体内容的安全性。

MP4 虽然也支持 DRM 和加密,但没有 HLS 的端到端加密和分片传输的优势明显。

6. 跨设备支持

HLS 由苹果公司开发,最初用于 iOS 设备。随着时间推移,HLS 已经成为一种广泛支持的标准,兼容大多数设备和浏览器:

  • 原生支持:HLS 在 iOS 和 macOS 上有原生支持,不需要额外插件。而且,现代的 Android、Windows、智能电视、机顶盒、浏览器等大部分设备也支持 HLS。
  • 浏览器支持:在网页上通过 HTML5 播放 HLS 流也十分便捷,而 MP4 文件更多是直接下载到本地后播放,或者通过播放器加载,灵活性较差。

总而言之

  • HLS 更适合流媒体和直播,因为它支持分片传输、多码率自适应、低延迟播放,以及良好的网络适应性。
  • MP4 更适合下载和离线播放,它是一个单一文件格式,适合短视频、预录制内容或需要离线保存的场景。

HLS 的动态更新、实时流、ABR 等特性使其成为流媒体平台、直播服务的首选,而 MP4 则适合文件传输或本地存储。

在前端是如何工作的?

当前H5视频播放器并不支持HLS视频格式的播放,要获得该格式的支持需要在前端引入HLS.js或者videojs等第三方播放器插件。

示例:

video标签source参数src中引入.m3u8后缀的文件,而type中需要指定"application/x-mpegURL"

  <video
    id="my-video"
  >
    <!--<source src="demo.mp4" type="video/mp4" />-->
    <source
        src="https://www.towait.com/20240619/SBicdVRe/index.m3u8"
        type="application/x-mpegURL">
  </video>

使用FFmpeg将mp4转换成m3u8文件

准备FFmpeg

下载FFmpeg,并将其加入系统变量,这里不做过多阐述。

格式化命令

$ ffmpeg -i demo1.mp4 -codec: copy -start_number 0 -hls_time 10 -hls_list_size 0 -f hls demo1.m3u8

输出结果

ffmpeg -i demo1.mp4 -codec: copy -start_number 0 -hls_time 10 -hls_list_size 0 -f hls demo1.m3u8
ffmpeg version 2024-09-22-git-a577d313b2-essentials_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
  built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
  libavutil      59. 37.100 / 59. 37.100
  libavcodec     61. 17.100 / 61. 17.100
  libavformat    61.  6.100 / 61.  6.100
  libavdevice    61.  2.101 / 61.  2.101
  libavfilter    10.  3.100 / 10.  3.100
  libswscale      8.  2.100 /  8.  2.100
  libswresample   5.  2.100 /  5.  2.100
  libpostproc    58.  2.100 / 58.  2.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'demo1.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: mp42mp41isomavc1
    creation_time   : 2021-02-01T09:58:39.000000Z
  Duration: 00:00:27.64, start: 0.000000, bitrate: 4593 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, 4590 kb/s, 25 fps, 25 tbr, 25 tbn (default)
      Metadata:
        creation_time   : 2021-02-01T09:58:39.000000Z
        handler_name    : L-SMASH Video Handler
        vendor_id       : [0][0][0][0]
        encoder         : AVC Coding
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Output #0, hls, to 'demo1.m3u8':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: mp42mp41isomavc1
    encoder         : Lavf61.6.100
  Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, q=2-31, 4590 kb/s, 25 fps, 25 tbr, 90k tbn (default)
      Metadata:
        creation_time   : 2021-02-01T09:58:39.000000Z
        handler_name    : L-SMASH Video Handler
        vendor_id       : [0][0][0][0]
        encoder         : AVC Coding
Press [q] to stop, [?] for help
[hls @ 0000016c76f2b5c0] Opening 'demo10.ts' for writing
[hls @ 0000016c76f2b5c0] Opening 'demo1.m3u8.tmp' for writing
[hls @ 0000016c76f2b5c0] Opening 'demo11.ts' for writing
[hls @ 0000016c76f2b5c0] Opening 'demo1.m3u8.tmp' for writing
[hls @ 0000016c76f2b5c0] Opening 'demo12.ts' for writing
[hls @ 0000016c76f2b5c0] Opening 'demo1.m3u8.tmp' for writing
[out#0/hls @ 0000016c76f1ff40] video:15490KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
frame=  691 fps=0.0 q=-1.0 Lsize=N/A time=00:00:27.56 bitrate=N/A speed= 631x

这时候我们的文件夹内会有文件,这是一个15Mb的视频文件,它被分割为3个.ts文件

转换后的m3u8和ts文件

如何批量转换?

我在github上找到一个脚本,但是目前我没有做测试

@echo off
echo The filename: %~n1
echo The extention: %~x1

REM Make new directories in the same folder.
md media\%~n1\hls

REM Get the cover jpg and preview gif from video
ffmpeg -i %~n1%~x1  -ss 20.00 -vframes 1 ./media/%~n1/hls/cover_h1.jpg
ffmpeg -i %~n1%~x1  -ss 20.00 -vframes 1 -s 760x428 ./media/%~n1/hls/cover_l1.jpg
ffmpeg -ss 00:00:10 -t 3 -i %~n1%~x1 -s 640x360 -r  2 ./media/%~n1/hls/preview.gif

REM Start to work on videos
ffmpeg -i %~n1%~x1 -profile:v baseline -level 3.0 -s 640x360 -start_number 0 -hls_time 10 -hls_list_size 0 -threads 5 -preset ultrafast -f hls ./media/%~n1/hls/360_out.m3u8
ffmpeg -i %~n1%~x1 -profile:v baseline -level 3.0 -s 800x480 -start_number 0 -hls_time 10 -hls_list_size 0 -threads 5 -preset ultrafast -f hls ./media/%~n1/hls/480_out.m3u8
ffmpeg -i %~n1%~x1 -profile:v baseline -level 3.0 -s 1280x720 -start_number 0 -hls_time 10 -hls_list_size 0 -threads 5 -preset ultrafast -f hls ./media/%~n1/hls/720_out.m3u8
ffmpeg -i %~n1%~x1 -profile:v baseline -level 3.0 -s 1920x1080 -start_number 0 -hls_time 10 -hls_list_size 0 -threads 5 -preset ultrafast -f hls ./media/%~n1/hls/1080_out.m3u8

REM Check if any error
if %ERRORLEVEL% == 0 goto :next
echo "Errors encountered during execution. Exited with status: %errorlevel%"
goto :endofscript

:next
echo "Generating overall m3u8 play list...."
REM Generate an overall play list.
(
echo #EXTM3U
echo #EXT-X-STREAM-INF:BANDWIDTH=375000,RESOLUTION=640x360
echo 360_out.m3u8
echo #EXT-X-STREAM-INF:BANDWIDTH=750000,RESOLUTION=854x480
echo 480_out.m3u8
echo #EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720
echo 720_out.m3u8
echo #EXT-X-STREAM-INF:BANDWIDTH=3500000,RESOLUTION=1920x1080
echo 1080_out.m3u8
) > ./media/%~n1/hls/%~n1.m3u8
echo "Overall m3u8 play list generated."

goto :endofscript

:endofscript
echo "Work complete."

REM Brought to you by Duke Yin www.dukeyin.com
pause

FFmpeg一些常用的web视频格式转换

为什么需要用这么多格式?

在 HTML5 中,使用 <video> 标签播放视频时,通常会同时提供多种格式(如 MP4、WebM 和 Ogg),这是为了确保视频可以在不同的浏览器中正常播放。原因如下:

1. 浏览器的兼容性问题

不同浏览器对视频格式的支持并不相同,尤其是早期的 HTML5 实现中,各个浏览器支持的格式差异很大。为了确保视频可以在更多的浏览器中播放,通常会提供多种格式。

常见的视频格式及其支持情况:

  • MP4(H.264 编码 + AAC 音频)
    • 支持度较广:几乎所有现代浏览器(包括 Chrome、Firefox、Safari、Edge、Internet Explorer)都支持 MP4。
    • 优点:高压缩率、质量好、广泛支持。
    • 缺点:涉及专利和版权问题,需要支付专利费用。
  • WebM(VP8/VP9 编码 + Vorbis 音频)
    • 支持:主要在 Chrome、Firefox、Opera 上支持。
    • 优点:开源且免专利费用。
    • 缺点:不被 Safari 和 Internet Explorer 支持。
  • Ogg(Theora 编码 + Vorbis 音频)
    • 支持:Firefox、Chrome、Opera。
    • 优点:开源,免专利费用。
    • 缺点:质量和压缩率不如 MP4 和 WebM,且 Safari 和 Internet Explorer 不支持。

2. 提升用户体验

通过提供多种格式,可以确保视频能在大多数用户的设备和浏览器上正常播放,避免用户因为视频格式不兼容而无法观看视频。

3. HTML5 标签的工作原理

当浏览器遇到多个 <source> 标签时,它会按顺序尝试加载这些视频源,直到找到一个自己支持的格式。这样可以自动选择最适合该浏览器的视频格式。

<video controls>
    <source src="video.mp4" type="video/mp4">
    <source src="video.webm" type="video/webm">
    <source src="video.ogv" type="video/ogg">
    Your browser does not support the video tag.
</video>

在这个例子中:

  • 浏览器会首先尝试加载 video.mp4 文件,如果浏览器支持 MP4 格式,就会播放 MP4 视频。
  • 如果浏览器不支持 MP4 格式,则会继续尝试加载 video.webm
  • 如果 WebM 格式也不支持,浏览器会最后尝试 Ogg 格式。

mp4转webm

ffmpeg -i demo1.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -b:a 128k -c:a libopus demo1.webm

mp4转ogv

ffmpeg -i demo1.mp4 -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 demo1.ogv

需要注意的是ogv的引用,type填写video/ogg

<video controls>
    <source src="video.ogv" type="video/ogg">
</video>

OK,结束

Post Comment