HLS 流媒体技术:畅享高清视频,忘却 MP4 卡顿的烦恼!

前言

在转转学堂这个学习平台中,提供了上门、门店和质检中心等培训视频课程,满足了各业务需求。作为全体员工学习的主要渠道之一,平台涉及了超过 3000 人,大多数业务相关的视频课程都将在该平台上进行学习,因此该平台的视频播放体验问题也至关重要。

过去没有专门抽空去梳理,今天刚好有机会,回顾过去及梳理一下跟大家分享一下。接下来,讲一下我们在视频播放上遇到的问题及如何一步步解决的。

过去问题

在学堂上线之后,时不时有人反馈视频播放比较卡。起初,我们觉的这个卡顿跟我们没太多关系,用的播放器都是浏览器内置的,没办法干涉到底层的能力。再后来,反馈的情况越来越多,不得不重视起来,以下是过去收集到的反馈信息:

黄某 1:刚才还有业务找我说视频卡顿。

黄某 1:学堂的视频今天出现卡顿的情况。

李某:这个优化时间大概多久呀,目前课程都以开放使用,卡顿会影响挺多业务使用的哦。

黄某 2:大佬们,想问下学堂卡顿的问题现在是否优化了,我们老板今天到学堂体验的时候发现卡顿问题还是存在,辛苦关注下。

产品 1:现在质检的在用我们的视频学习,他们反馈视频很卡,很影响他们的学习效率。

这无疑也给予了我们一些压力,不处理好这个事情的话,后续更多人用的话,吐槽的会更多,我们也会更难堪。😣

我们的视频用的格式是 mp4,在播放时常出现卡顿现象,尤其对于较大的文件,拖动时加载卡顿更加明显,以下是个提供个演示视频供大家感受一下:

解决方案

针对以上业务反复的说卡顿问题,我们实在是扛不住了,于是下定决心是要解决这个问题。我们先后折腾了几个方案,但是效果不佳,直到最后一个方案(即流媒体格式),加上切换全新的播放器,才算是解决到了问题的根本,以下是我们折腾的几个方案的过程。

1. 全新改造:搭载腾讯云 TCPlayer 播放器

由于对于视频卡顿的底层原理研究比较浅,最开始觉的卡顿是不是换一个播放器就可以得以解决,于是对比了市面上的一些播放器,相对来说,腾讯的 TCPlayer 比较成熟且符合开发条件,因此就尝试改造起来。

我们从官网了解到,TCPlayer 有许多优势,其中主要具有以下特征:

  • 高性能播放:TCPlayer 具备卓越的性能,在各种网络环境下提供流畅、稳定的视频播放体验。
  • 多格式支持:TCPlayer 支持多种常见的视频格式,包括 MP4、FLV、HLS、M3U8 等,以适应不同的需求和场景。
  • 自适应码率:TCPlayer 支持自适应码率技术,根据观众的网络环境动态调整视频的码率和分辨率,确保高质量的播放和较低的卡顿率。
  • 强大的功能扩展:TCPlayer 提供丰富的功能扩展接口和插件机制,可以根据业务需求进行灵活的拓展和定制。
  • 多平台兼容:TCPlayer 可以在多个平台上使用,包括网页、移动应用和其他设备。它提供了适配不同平台的开发工具和文档。
  • 全面的控制与交互:TCPlayer 支持全面的播放控制和用户交互功能,如播放、暂停、跳转、全屏等,使用户能够方便地操作和控制视频播放。

从页面上显示效果如下:

于是决定将 h5 播放器改成腾讯云的播放器,调研测试了一下,页面样式确实美观了很多,能够解决了过去多个端样式不一致的问题。但从底层来看,还是没有解决根本问题,同时也带来了另外一个问题代码改造成本过高,随之也带来维护成本高。基于问题解决的思路考虑,我们将这个方案暂定。

参考文档:直播 SDK Web(TCPlayer)-无 UI 集成方案-文档中心-腾讯云

2. 强化优化:优化视频分辨率、编码等参数减少体积

归根到底我们还是想从视频的底层属性上去做一些优化,我们了解到视频他有很多可控的参数,从外部收集了一些信息,对于影响视频播放速度的因素有:

  • 视频比特率:指视频文件中每秒传输的比特数,通常以"比特/秒"(bps)或"千比特/秒"(Kbps)为单位。比特率决定了视频的画面质量和文件大小,较高的比特率通常会带来更好的画面质量,但会导致文件更大。
  • 关键帧:关键帧(也称为 I 帧)在视频编码中起着重要作用,它们是视频序列中完整自身的帧,而其他帧(P 帧和 B 帧)则是通过参考其他帧进行压缩编码的。调整关键帧间隔会影响视频的压缩效率、画面质量和播放性能。
  • 帧率:调整帧率是指更改视频中每秒显示的帧数。视频帧率是指每秒显示的图像数量,通常以"帧/秒"(fps)为单位。调整帧率会影响视频播放的流畅度、视觉感受以及文件大小。
  • 音频比特率:音频比特率是指在音频编码中每秒传输的比特数,它会直接影响音频的质量和文件大小。选择适当的音频比特率需要综合考虑音频质量、存储空间和带宽要求等因素。

综合考虑以上因素,以下是一些常见的音频比特率选择:

  • 64 kbps: 适用于低带宽环境和需要节省存储空间的情况。音频质量可能会有所降低。
  • 128 kbps: 是许多在线音频和视频平台的默认音频比特率。提供了较好的音频质量,并且在大多数情况下能够满足观众需求。
  • 192 kbps 或更高: 对于需要高音质的音频内容,如音乐或专业录制,可以选择较高的比特率。
  • 采样率:音频采样率是指在音频数字化过程中每秒对原始音频信号进行采样的次数。采样率会影响音频的频率范围和质量。

常见的音频采样率包括 44.1 kHz 和 48 kHz。这些采样率在大多数情况下已经能够提供足够的音频质量。

  • 44.1 kHz: 这是 CD 音质的标准采样率,被广泛用于音乐、语音和一般的音频内容。这种采样率能够捕捉人耳所能听到的大部分频率范围。
  • 48 kHz: 这是视频制作、广播和许多数字音频工作流中常用的采样率。它可以适应更广泛的音频需求,并且在专业领域中使用较多。

基于以上的属性配置,我们内部测试了一下,改善配置确实能将视频体积变小,随之加载速度也就相对快一点,于是跟 RD 一起调试了一个符合我们平台够用的一个参数配置,最后跟业务达成一致,后续上传视频之前根据这个参数转一下码。

转码工具配置图:

于是我们梳理了一下规范文档,让上门业务按照这个方法来减轻视频播放的卡顿。上门业务用了这套规范之后,能够大程度减少他们学习的卡顿问题,后面反馈的频率相对比较低。

但到后来,其他业务也用上了该平台,由于规范文档很难拉齐,他们就会按照自己的方式直接将视频上传了,如果视频比较大,那容易导致视频播放卡顿。即使拉齐了,还是有一定程度的卡顿。所以在这个方案里,带来的一个弊端就是每次上传视频之前都要压缩一遍,并且也不能完全解决问题,这并不是大家想要的一个结果。

3. 精妙应用:采用 HLS 流媒体类型流畅播放

经过充分资料的调研,并且跟一些懂领域的技术伙伴沟通交流,他说道:"可以采用流媒体方式播放,现在很少人用 mp4 播放了,切片才是王道。",于是决定用流媒体方式播放看看。

这里流媒体主要用的是 m3u8 格式,m3u8 是一种基于文本的媒体播放列表格式,常用于流媒体传输。它可以将视频切片成多个小的 .ts 文件,并通过 m3u8 文件进行索引和控制。m3u8 格式适用于实时流媒体传输,如直播、在线视频等,并具有自适应码率特性,可以根据网络条件动态调整视频的质量。

我们这做了个 Demo 进行对比,视频时长 6 分钟多,大小 290m 左右,加载速度对比如下:

mp4 demo:

m3u8 demo:

明显能感觉下面的切片方式,加载速度会相对快很多,这个测试得予验证之后,开始落实我们的业务技术实现。

目前用的视频格式是 mp4,我们想了几个将 mp4 转成 m3u8 流媒体格式的方案。

1)采用腾讯云转码接口:由于我们云储存都是用的腾讯云,看能不能直接用腾讯云的接口。腾讯云转码是需要收费的,按照视频的长度来算,比如一个视频 6 分钟,每分钟收费 1 块钱,那么转码这个视频就需要收起 6 块钱的费用,一天上传 20 个视频的话,一天 120 元,一年就 43800 元,还是有一定成本的,基于这个考虑,暂时待定。

2)前端实现文件转码服务。可以采用 FFmpeg 对文件进行处理,FFmpeg 功能非常强大,提供了丰富命令和方法,以下是该工具的主要功能:

  • 音频/视频编码和解码:FFmpeg 支持多种音频和视频编码格式,可以进行编码和解码操作。
  • 视频转码和格式转换:FFmpeg 可以将一个视频文件转换为不同的格式,如从 MP4 转换为 AVI、FLV、MKV 等。
  • 视频剪辑和裁剪:FFmpeg 可以将视频文件进行剪辑、裁剪和拼接,实现视频的编辑和合并。
  • 图片和视频处理:FFmpeg 可以从视频中提取帧,也可以将多个图片合成为视频。
  • 录制和转播:FFmpeg 可以通过捕获音频和视频输入进行实时录制和转播。
  • 流媒体传输:FFmpeg 支持将音频和视频实时传输到网络中,用于实现流媒体服务。
  • 音频和视频过滤:FFmpeg 提供了丰富的音频和视频过滤器,可以实现降噪、去水印、调整亮度对比度等功能。
  • 媒体信息解析:FFmpeg 可以解析音频和视频文件的元数据信息,如分辨率、编码器、码率等。

这只是 FFmpeg 的一些主要功能,它还有更多的用途和功能,可根据具体需求进行深入学习和使用。

这来讲下前端 Node 大致实现思路:

a. 后端对前端上传过来的文件通过 FFmpeg 包进行处理,将其转成 m3u8 及 ts 文件格式;

底层命令实现如下:

css 复制代码
ffmpeg -i input.mp4 -hls_time 10 -hls_list_size 0 -y output.m3u8

生成的文件切片:

b. 然后将输出的 m3u8 及 ts 的相关文件上传到云储存里去;

c. 返回 m3u8 地址给前端;

综合考虑,这个实现成本有点大,处理不好的话也容易出问题。想着是不是可以让架构组实现一下,毕竟这个功能其他业务也会用到,应该做为通用的接口会合适点,不然各自开发这个成本也挺大,基于这个考虑,前端实现方案待定。

3)交由架构组支持视频文件转换 m3u8 格式。

第一时间与架构组的相关人员沟通下诉求,讲了下我们的现状和诉求及收益,看能否支持一下。后面我们跟产品拉了个会议简单沟通了一下,架构负责人表示能够支持。在与架构沟通中给了 3 种方案给我们选择:

  • 前端调用 sdk 上传后再调用转码接口;(上传时长较长)
  • 前端上传后扔给后端处理分片上传,然后再转码接口;(压力给到后端)
  • 前端调用分片接口上传,完成后再调转码接口(前端调用上传分片比较复杂,需要调 3 个步骤接口,再调转码接口)

代码实现情况如下:

js 复制代码
//前端分片上传
function chunkFile(file, chunkSize) {
  const fileSize = file.size;
  let offset = 0;

  while (offset < fileSize) {
    const chunk = file.slice(offset, offset + chunkSize);
    uploadChunk(chunk); // 上传块到服务器进行处理

    offset += chunkSize;
  }
}

function uploadChunk(chunk) {
  // 这里仅作为示例,你需要根据实际情况进行适当修改
  const formData = new FormData();
  formData.append('chunk', chunk);

  fetch('/upload', {
    method: 'POST',
    body: formData
  })
    .then(response => {
      // 处理响应
    })
    .catch(error => {
      // 处理错误
    });
}

// 示例用法
const fileInput = document.getElementById('file-input');

fileInput.addEventListener('change', () => {
  const file = fileInput.files[0];
  const chunkSize = 1024 * 1024; // 每个块的大小(这里设为1MB)

  chunkFile(file, chunkSize);
});

基于这 3 种方案,考虑目前管理端对上传时长也没太大诉求。我们就选择简单一点,于是选择第一种方案,分片的方案可以先实现,后续业务对这块有痛点的话,我们再切换成分片上传的形式,最终采用的方案是:切换腾讯 TCPlayer 播放器+流媒体格式播放,这个卡顿问题得予解决。

最终呈现效果图:

技术难疑

这里主要是使用 TCPlayer 播放流媒体格式的同时,我们也遇到了一些问题,记录下来方便给后续使用的人避免踩坑。

  1. 提示 lack license url 错误。

web 播放器基础版是免费的,需要申请下 license 才行,每次一年的期限,过期后需要自行续期。

  1. 控制台会显示错误信息,但这并不会对功能的正常使用造成影响。为了解决这个问题,建议升级 tcplayer.js 到 5.1.0 版本。这个更新版本能够有效解决该错误。
  1. 在多个视频分页切换时,我发现一个初始化的问题。在点击下一页之前,我会销毁所有的腾讯云播放器实例。然而,当切换到下一页时,使用同一个视频标签的视频也会被移除,结果导致下一个视频消失了。

经过与腾讯前端技术沟通后,可能对我们的业务不太了解,没法想象出问题是咋样的。对此他们也没有给出明确的解决建议。因此,我们决定自行处理该逻辑。在经过一番思考后,我意识到模板没有重新渲染是一个可能导致问题的原因。于是第二天,我尝试了另外一种解决方案,在切换页码时,强制将 v-if 判断语句设为 false,然后在获取到数据后再将其设为 true。结果出乎意料地成功了!这样一来,模板得以重新渲染,问题也得到了解决。核心问题就是相同地址的视频采用的 id 值导致播放器实例重复了,销毁后其其他相同地址 id 的视频也被销毁了,所以需要每次切换页码的时候都要渲染模版才能加载成功。

最后

上线时隔一年,各业务部门再也没有反馈过视频卡顿的问题。这一改进过程中得到了业务反馈的积极回应,表示视频加载速度显著提升,视频体验更加顺畅。

过去,用户在加载视频时常常遇到 3-5 秒甚至更长的等待时间,给观看体验带来了困扰。现在,切换加载速度极大提升,仅需不到 1 秒的时间即可加载完成。通过以上方案的调研及测试,我们成功消除了视频播放卡顿的问题,大大提升了用户的观看体验,后续将持续关注并优化视频播放,以确保用户能够享受到最佳的观看体验。

PS:如果您有更好的实现方式或者疑问,欢迎在底部留言探讨。

转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。 关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~

相关推荐
程序员的程1 天前
我做了一个前端股票行情 SDK:stock-sdk(浏览器和 Node 都能跑)
前端·npm·github
KlayPeter1 天前
前端数据存储全解析:localStorage、sessionStorage 与 Cookie
开发语言·前端·javascript·vue.js·缓存·前端框架
沉默-_-1 天前
从小程序前端到Spring后端:新手上路必须理清的核心概念图
java·前端·后端·spring·微信小程序
裴嘉靖1 天前
前端获取二进制文件并预览的完整指南
前端·pdf
李剑一1 天前
uni-app使用瓦片实现离线地图的两种方案
前端·trae
木易 士心1 天前
深入剖析:按下 F5 后,浏览器前端究竟发生了什么?
前端
几何心凉1 天前
离开舒适区之后:从三年前端到 CS 硕士——我在韩国亚大读研的得失
前端·人工智能·年度总结
小二·1 天前
前端测试体系完全指南:从 Vitest 单元测试到 Cypress E2E(Vue 3 + TypeScript)
前端·typescript·单元测试
pas1361 天前
18-mini-vue element
前端·vue.js·ubuntu