EdgeOne 边缘函数—如何动态改写 M3U8 媒体文件

news2024/11/26 15:49:49

目前,各大主流厂商都推出了自己的边缘 Serverless 服务,如 CloudFlare Workers、 Vercel EdgeRuntime 等;腾讯云 EdgeOne 边缘函数提供了部署在边缘节点的 Serverless 代码执行环境,只需编写业务函数代码并设置触发规则,即可在靠近用户的边缘节点上弹性、安全地运行代码。

一、前言

HTTP Live Streaming(HLS)是一种基于HTTP 的流媒体传输协议,广泛应用于直播和点播视频内容的传输。M3U8 文件是 HLS 技术中的一部分,包含对多个媒体文件的引用(通常是 TS 文件)。

  1. 自适应流:HLS 支持自适应比特率流,可以根据观众的网络条件和设备性能自动调整视频质量。

  2. 广泛的设备和平台支持:HLS 由 Apple 开发,因此所有 Apple 设备都有原生支持。此外,许多其他平台和设备也支持HLS。这使得 HLS 成为跨平台流媒体传输的理想选择。

  3. 加密和 DRM 支持:HLS 支持内容加密,以及与各种数字版权管理(DRM)方案的集成。

  4. 实时和点播流:HLS 既可以用于实时流(如直播),也可以用于点播内容。这使得它在各种流媒体场景中都非常有用。

HLS 在流媒体领域得到了广泛的应用,无论是大型的流媒体服务,还是小型的独立开发者,都在使用这项技术。

二、边缘改写 M3U8 文件

在实际使用过程中,开发者可能需要对 M3U8 文件进行改写和处理,以下是一些常见的场景:

  1. 自定义播放列表:开发者可能需要根据用户的网络状况、设备性能或地理位置,选择不同的媒体流。

  2. 内容安全和访问控制:为了保护版权内容,开发者可能需要对 M3U8 文件进行处理,以实现加密、添加访问令牌等功能。

  3. 广告插入:在流媒体内容中插入广告是一种常见的商业模式。开发者可以通过修改 M3U8 文件,在视频播放的特定时间点插入广告片段。

对 M3U8 文件进行改写和处理可以帮助开发者实现更丰富、更灵活的流媒体应用场景。

得益于 EdgeOne 边缘函数的可编程能力,开发者可以在边缘节点是处理 M3U8 媒体文件,动态的修改和注入内容。

三、应用场景

下面我们以三个场景为例,了解如何使用边缘函数实现 动态改写 M3U8 文件

1. 代码示例旨在展示边缘函数的能力,仅列举常见方案的基本实现;
2. 文章中涉及的代码可 私信获取查看;

3.1 添加 URL 鉴权

改写 M3U8 文件内容,为每个 TS 文件请求添加 URL 鉴权参数,主要用于保护视频内容的安全。以下是一些可能的场景:

  1. 付费内容:例如,一些视频网站可能会提供付费的电影、电视剧或直播服务。这些网站可以通过URL鉴权来确保只有付费用户才能访问内容;

  2. 会员内容:一些网站可能会为会员提供独家内容。这些网站可以使用 URL 鉴权来限制只有会员才能访问这些内容;

我们可以在边缘函数中实现动态添加 URL 鉴权参数,以达到保护内容的目的。

假定原始 M3U8 文件为:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.000000,
8k60_-bulgaria_8k_hdr_60p_fuhd692899210.ts
#EXTINF:10.000000,
8k60_-bulgaria_8k_hdr_60p_fuhd692899211.ts
#EXTINF:10.000000,
8k60_-bulgaria_8k_hdr_60p_fuhd692899212.ts
...
#EXTINF:9.360422,
8k60_-bulgaria_8k_hdr_60p_fuhd6928992133.ts
#EXT-X-ENDLIST

客户端获取 M3U8 文件的 HTTP 请求携带 Type A 参数 auth_key,形如:http://localhost:8080/xxx.m3u8?auth_key=1698752518-0-00001-ff87dbc0598...

此次请求触发边缘函数,根据 M3U8 HTTP 请求的 auth_key 参数,获取到 timestampranduid 等关键信息,根据这些参数计算出每个 TS 请求的 Type A 鉴权参数 auth_key,并修改 M3U8 文件中,每个 TS 请求的 URL:

...
async function rewriteLine({ line, querySign }) {
  if (/^\s*$/.test(line)) {
    return line;
  }

  if (line.charAt(0) === "#") {
    if (line.startsWith("#EXT-X-MAP")) {
      const key = await createSign(querySign, line);

      line = line.replace(/URI="([^"]+)"/, (matched, p1) => {
        return p1 ? matched.replace(p1, `${p1}?key=${key}`) : matched;
      });
    }
    return line;
  }

  const key = await createSign(querySign, line);

  return `${line}?${AUTH_KEY_NAME}=${key}`;
}

async function createSign(querySign, line) {
  const { basePath, ts, rand, uid } = querySign;
  const pathname = `${basePath}/${line}`;

  const md5hash = await md5([pathname, ts, rand, uid, SECRET_KEY].join("-"));
  const key = [ts, rand, uid, md5hash].join("-");

  return key;
}
... 

经过上面的处理,原 M3U8 文件中的 TS 请求都被改写:

客户端播放器解析 M3U8 文件,发起 TS 请求,携带 Type A 鉴权参数 auth_key,形如:http://localhost:8080/xxx.ts?auth_key=1698752518-0-00001-88cbab261a...

获取 TS 资源的 HTTP 请求仍然会触发边缘函数执行,此时函数会进行 auth_key 的校验:

...
async function checkTypeA(urlInfo) {
  const sign = urlInfo.searchParams.get(AUTH_KEY_NAME) || "";
  const elements = sign.split("-");

  if (elements.length !== 4) {
    return {
      flag: false,
      message: "Invalid Sign Format",
    };
  }

  const [ts, rand, uid, md5hash] = elements;
  if (!ts || !rand || !uid || !md5hash) {
    return {
      flag: false,
      message: "Invalid Sign Format",
    };
  }

  if (!isNumber(ts)) {
    return {
      flag: false,
      message: "Sign Expired",
    };
  }

  const now = Math.floor(Date.now() / 1000);
  if (now > Number(ts)) {
    return {
      flag: false,
      message: "Sign Expired",
    };
  }

  const hash = await md5(
    [urlInfo.pathname, ts, rand, uid, SECRET_KEY].join("-")
  );
  if (hash !== md5hash) {
    return {
      flag: false,
      message: "Verify Sign Failed",
    };
  }
  return {
    flag: true,
    message: "success",
  };
}
...

如果 TS URL 携带的 auth_key 校验通过,会正常返回资源,客户端可以正常播放视频,如图所示:

如果 TS URL 携带的 auth_key 不合法,或者未携带参数,边缘函数将会返回 403,视频不会正常播放:

注意:
添加 URL 鉴权参数仅是一种访问控制的方式,在 《 EdgeOne 边缘函数 - 如何实现“防盗”与访问控制》 中介绍的访问控制方案,均可与 M3U8 文件改写结合使用。

3.2 插入广告

在 M3U8 文件中通过添加 TS 文件的方式插入广告,是一种常见的在线视频广告投放方式。这种方式可以在视频流中无缝插入广告。主要应用场景有:

  1. 在线视频平台:例如 YouTube、Netflix 等,可以在视频的开始、中间或结束时插入广告;

  2. 直播平台:例如 Twitch、斗鱼等,可以在直播的特定时刻插入广告;

这种方式相比其他广告插入方式有以下优势:

  1. 灵活性:可以根据需要在任何时刻插入广告,例如在视频的开始、中间或结束;

  2. 兼容性:这种方式不依赖于特定的播放器,只要设备支持 HLS,就可以播放广告;

  3. 个性化:可以根据用户的行为、兴趣或地理位置等因素,投放定制的广告;

我们可以利用这种思路,在边缘节点上动态修改 M3U8 文件中的 TS 文件列表。

假定原始 M3U8 文件为:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.000000,
8k60_-bulgaria_8k_hdr_60p_fuhd692899210.ts
#EXTINF:10.000000,
8k60_-bulgaria_8k_hdr_60p_fuhd692899211.ts
#EXTINF:10.000000,
8k60_-bulgaria_8k_hdr_60p_fuhd692899212.ts
...
#EXTINF:9.360422,
8k60_-bulgaria_8k_hdr_60p_fuhd6928992133.ts
#EXT-X-ENDLIST

通过边缘函数,将预先准备好的广告 TS 片段注入:

const AD_TS = `#EXTINF:10.000000,
http://m3u8-1251557890.cos.ap-guangzhou.myqcloud.com/apple_watch_apple_watch_hermes184006680.ts
#EXTINF:10.000000,
http://m3u8-1251557890.cos.ap-guangzhou.myqcloud.com/apple_watch_apple_watch_hermes184006681.ts
#EXTINF:10.000000,
http://m3u8-1251557890.cos.ap-guangzhou.myqcloud.com/apple_watch_apple_watch_hermes184006682.ts
#EXT-X-DISCONTINUITY`;

...
async function handleM3U8(request) {
  ...
  const response = await fetchOrigin(request);
  if (response.status !== 200) {
    return response;
  }

  const originalM3U8 = await response.text();

  const modifiedM3U8 = originalM3U8.replace(
    "#EXT-X-MEDIA-SEQUENCE:0",
    `#EXT-X-MEDIA-SEQUENCE:0\n${AD_TS}`
  );

  return new Response(modifiedM3U8, response);
}
...

经过上面的处理,原 M3U8 文件中插入了广告 TS 片段:

当客户端播放器拿到改写的 M3U8 文件后,将会首先播放广告:

广告播放完毕,无缝切换,播放视频内容:

注意:
广告内容在一段时间内相对固定,因此无需每次重复进行 M3U8 改写,可以使用 Cache 进行合理缓存;

3.3 地域定制

根据地理位置投放广告可以更有效地达到广告目标,提高广告效果,提供个性化体验。在场景 2 的基础上,我们可以进一步修改代码,借助边缘函数 Request API 的 request.eo.geo 参数,获取客户端的地理位置,注入不同的广告内容,实现精细化广告投放。

const AD_TS_1 = `...AD_TS_1...`;
const AD_TS_2 = `...AD_TS_2...`;

const ADS = {
  CN: AD_TS_1,
  US: AD_TS_2,
};

...
async function handleM3U8(request) {
  ...
  const response = await fetchOrigin(request);
  if (response.status !== 200) {
    return response;
  }

  const originalM3U8 = await response.text();
  const alpha2code = request.eo.geo.countryCodeAlpha2;
  const AD_TS = ADS?.[alpha2code];
  const modifiedM3u8 = originalM3U8;
  
  if (AD_TS) {
    modifiedM3U8 = originalM3U8.replace(
      "#EXT-X-MEDIA-SEQUENCE:0",
      `#EXT-X-MEDIA-SEQUENCE:0\n${AD_TS}`
    );
  }

  return new Response(modifiedM3U8, response);
}
...
注意:
与基于  request.eo.geo 定制广告 TS 片段同理,开发者可以定制视频的其他局部 TS,受限于文章篇幅,本文不做展示。

四、总结

使用 EdgeOne 边缘函数在边缘节点改写 M3U8 文件,在保证 CDN 加速效果的同时,可以实现便捷、灵活的流媒体处理,根据用户的实际情况动态调整媒体流,从而优化业务流程,降低维护成本。

参考 API 列表

  • Runtime API - Fetch
  • Runtime API - Request
  • Runtime API - Web Crypto

欢迎各位童鞋来体验和使用 EdgeOne 边缘函数,挖掘更多玩法:

  • EdgeOne 控制台
  • 边缘函数官网文档
  • 边缘函数脚手架 TEF CLI

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1835092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决IDEA使用卡顿的问题,设置JVM内存大小和清理缓存

解决IntelliJ IDEA中卡顿问题,可以尝试以下几个常见且有效的步骤: 1 增加IDEA的JVM内存分配: 位于IDEA安装目录的bin文件夹下,找到对应的操作系统配置文件(idea64.exe.vmoptions(Windows)或id…

k8s删除状态为 Terminating 的pod

卸载calico pod时候pod资源状态会卡在terminating,这时候需要手动进行删除 使用以下命令即可 kubectl delete pod podName -n NAMESPACE --force --grace-period0记住一定要加命名空间,不然会报错没有找到

AI发展面临的问题? —— AI对创造的重新定义

一、AI的问题描述 AI与数据安全问题:随着AI技术的发展和应用,数据安全问题日益突出。AI模型训练依赖于大量数据,而这些数据中可能包含个人隐私、商业秘密等敏感信息。如果数据在采集、存储、使用过程中处理不当,可能导致数据泄露或…

测试单选框

单选按钮:用于在一组互相排斥的选项中选择其中一项; 由一个圆圈和紧随其后的文本标题组成,当它被选中时,圆圈中就标上一个黑点。 通常将一组单选按钮放在一个组框控件中,在一组单选按钮中,第一个(Tab键顺序…

可燃气体报警器:户外工地安全预警先锋,定期检定保障安全无忧

在现代化的建设进程中,户外工地作为城市发展的重要推动力,其安全问题一直备受关注。 工地现场往往涉及多种易燃易爆气体,一旦发生泄漏,后果不堪设想。因此,如何有效预警并防范可燃气体泄露,成为户外工地安…

【系统架构设计师】二、操作系统知识(操作系统概述|进程管理)

目录 一、操作系统概述 1.1 操作系统定义 1.2 操作系统的功能 1.3 操作系统的分类 1.4 嵌入式操作系统主要特点 二、进程管理 2.1 进程的组成与状态 2.2 前趋图 2.3 进程资源图 2.4 进程调度 2.5进程调度算法 2.6 死锁 2.7 进程与线程 2.7.1 进程 2.7.2 线程 2…

双指针练习:有效三角形的个数

题目链接:611.有效三角形的个数 题目描述: 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 解法一(暴力求解)(会超时): 算法思路: 三层…

视频汇聚安防综合管理系统EasyCVR平台GB28181设备注册未上线的原因排查与解决

视频汇聚安防综合管理平台EasyCVR视频监控系统基于云边端架构,可支持海量视频汇聚集中管理,能提供视频监控直播、云端录像、云存储、录像检索与回看、告警(协议告警/智能告警/1400视图库告警)、平台级联、AI智能分析接入等视频能力…

【学习Docker】

学习Docker可以分为几个步骤和阶段,以下是一个建议的学习路径,适合初学者到进阶用户: ### 1. 理解基本概念 - **容器化与虚拟化**:了解容器化与传统虚拟化之间的区别,容器的轻量级和效率。 - **Docker组件**&#xff…

【耐水好】强耐水UV胶水主要重视什么?

【耐水好】强耐水UV胶水主要重视什么? 应用性方面: 强耐水UV胶水主要重视以下几个方面: 耐水性:强耐水UV胶水经过精心调配和改良,以提供出色的耐水性能。这种胶水能够形成防水层,有效防止水分渗入并保护被…

乐鑫ESP32-C6支持WiFi 6通信,设备联网交互方案,启明云端乐鑫代理商

随着物联网设备的不断增多,对可靠、高容量和低功耗无线连接的需求变得尤为迫切。这就是Wi-Fi 6(即802.11ax)应运而生的原因,这一技术在各个环境中的应用印证了此类需求的重要性。 设备智联在我们的日常生活中越来越常见。从智能家…

未授权访问漏洞总结

以下总结了常见的未授权访问漏洞,还在持续更新中,遇到就会补充。欢迎大家关注~ 目录 FTP未授权访问(21) 漏洞原理 漏洞检测 漏洞利用 漏洞修复 LDAP未授权访问(389) 漏洞原理 漏洞检测 漏洞利用 …

Ubuntu网络管理命令:ifconfig

安装Ubuntu桌面系统(虚拟机)_虚拟机安装ubuntu桌面版-CSDN博客 关于ifconfig命令,在11.1节已经介绍过了。通过该命令可以查看和配置网络接口。ifconfig是一个比较古老的命令,在Ubuntu 22以及其他的许多发行版中,已经不…

Playwright-html-report源码解析

执行命令生成html格式报告 Playwright在执行完成测试,支持生成html格式的测试报告,如下图所示,使用"npx playwright test"执行测试,执行完成后,会提示“npx playwright show-report”命令。执行该命令&#…

AI大模型探索之路-实战篇:智能化IT领域搜索引擎之HuggingFace网站在线搜索

系列篇章💥 No.文章1AI大模型探索之路-实战篇:智能化IT领域搜索引擎的构建与初步实践2AI大模型探索之路-实战篇:智能化IT领域搜索引擎之GLM-4大模型技术的实践探索3AI大模型探索之路-实战篇:智能化IT领域搜索引擎之知乎网站数据获…

【乐吾乐2D可视化组态编辑器】导航

支持点击图元,切换画面或跳转链接。 乐吾乐2D可视化组态编辑器地址:https://2d.le5le.com/ 切换画面 1. 添加事件 2. 设置事件行为 事件行为"发送消息",消息名选择"导航"。 3. 配置消息参数 消息参数,…

LeetCode 48.旋转图像

1.做题要求: 2.从此题我们可以看出规律为第几行要变为倒数第几列,所以我们最好先把二维数组存入一维数组中,然后先从最后一列遍历,把一维数组里的元素,依次等于遍历的元素即可: void rotate(int** matrix, int matrixSize, int*…

1984-2022年全球河流和湖泊表面积 (Surface Area of Rivers and Lakes,SARL)数据集

简介 Nyberg 等人(2024 年)开发的 "河流和湖泊表面积(SARL)"数据集对 38 年间(1984-2022 年)河流和湖泊的水面面积变化进行了全面分析。这个分辨率为 30 米的全球数据集为了解地表水的动态提供了…

一文读懂 Transformer 神经网络模型

今天我们来聊一下人工智能(AI)生态领域相关的技术 - Transformer 神经网络模型 。 自从最新的大型语言模型(LLaM)的发布,例如 OpenAI 的 GPT 系列、开源模型 Bloom 以及谷歌发布的 LaMDA 等,Transformer 模…

java线程安全 ,死锁以及线程状态的介绍与使用

线程安全 1.什么时候发生:当多个线程访问同一个资源时,导致了数据有问题1.线程安全问题–>线程不安全的代码 public class MyTicket implements Runnable{//定义100张票int ticket 100;Overridepublic void run() {while(true){if (ticket>0){System.out.println(Thre…