亚马逊AWS官方博客
使用无服务器服务构建高可用,低成本的动态添加水印的视频点播系统 – Part 1
“如无必要,勿增实体”
–奥卡姆剃刀原则
浏览本文需要约 10 分钟,建议按照章节分段阅读。
随着移动互联网的发展,音视频逐渐成为传播信息的重要媒介,其中所包含的信息也越来越重要,对于音视频文件的保护也变的越来越重要。为了保护知识产权,防止视频被人搬运或者恶意使用,给视频添加水印是一种比较简单实用的方案。然而对于高价值音视频文件,固定的水印内容无法做到阻止录屏传播的作用,也无法追溯视频泄露的源头。
那么基于播放者信息在音画中添加动态水印成为一种重要的手段,现在市面上叠加动态水印的解决方案主要有两种:
1、CS 场景,使用专用播放器和专用视频文件格式
2、BS 场景,使用前端 JavaScript 叠加包含水印信息的透明层
对于 BS 场景的解决方案,在前端进行处理往往是不可信的,访问者可以采取跟踪浏览器请求获取干净视频流、编写油猴脚本屏蔽水印层等手段破坏水印。随着使用浏览器播放视频变得越来越普遍,如何在 BS 场景里在后端为视频增加硬水印成为一个迫切需要解决的问题,本文就这个需求场景介绍如何在亚马逊云科技海外区域,基于无服务器服务实现点播视频动态水印功能。
1. 当前视频系统
1.1 视频转码
管理人员登录管理后台上传原始视频存储到 S3,完成上传后服务端调用 AWS Elemental MediaConvert 服务,将视频转码成 HLS 视频流,生成 TS 切片,通过 m3u8 文件进行检索,如下图所示,视频切片文件和播放列表都存储于 S3 中。
1.2 视频访问
通过互联网登录访问视频系统,用户播放请求会先发送到视频播放服务(Application Server on EC2),该服务会向用户返回一个 m3u8 播放列表文件,该文件记录了视频文件信息及视频切片的路径,浏览器会基于播放时间逐个向播放服务请求视频切片,播放服务收到视频切片请求后使用其持有的 IAM 凭证(Access Key/Secret Key,或者 IAM Role),生成 S3 存储桶中该视频 TS 切片的预签名 URL(Pre-Signed URL一个能够提供对 S3 资源临时访问权限的 URL,在不暴露 S3 资源的访问密钥的情况下,允许其他人或者应用程序访问 S3 中的资源),并响应给用户,用户使用该 PresignURL 向 S3 请求视频切片文件并完成播放。
2. 新增需求
以上图的架构为基础,实现视频动态添加水印,即不同的用户在观看视频时,叠加带有用户标识及播放时间戳的水印。比如 A 和 B 用户在不同时间观看同一 mp4 视频时,视频叠加的水印内容分别为:a@xxx.com/2023-11-01 09:00和b@yyy.com/2023-11-02 10:00,并将水印内容在后端硬编码到视频流中防止视频被盗录。
3. 需求分析
该需求有两个难点:
1)动态水印信息硬编码到视频中且可以实时播放,意味着每个视频切片都需要消耗巨大的算力进行编码,且需要在请求到达时以极低的延迟获取到算力完成转码并返回,当并发播放时所需的算力规模是巨大的。
2)水印信息需要以一种简单、低延迟、可靠且安全的方式传递给编码服务,在该方案中额外引入的任何延迟都可能导致视频播放卡顿。
4. 实现过程
4.1 S3 Object Lambda
如果要实现不同的用户访问不同的视频,分别打上不同用户的水印,通常情况下可以有两种选择,第一种是创建、存储和维护属于每个用户的视频库,这样做肯定不现实;第二种是在 S3 前面构建一个代理层,做请求拦截和处理,但会增加管理的复杂性和不必要的成本。那么除此之外,还有没有更好的解决方案?
S3 Object Lambda 是一项新功能,允许添加代码来处理从 S3 检索的数据,然后再将其返回到应用程序。S3 Object Lambda 可与现有应用程序配合使用,并使用 AWS Lambda Function 从 S3 检索数据时自动处理和转换数据。Lambda Function 是通过标准 S3 Get 请求内联调用的,不需要更改应用程序代码。如下图所示,可以根据不同用户访问的视频,通过 Lambda Function 来实现不同的水印标记。
为了更好地理解 S3 Object Lambda,通过为多个应用程序提供不同的数据视图为例,通过一份原始数据,基于不同的应用场景,都可以通过 S3 Object Lambda 来实现不同的数据视图。
4.2 S3 Object lambda 与 S3 event notification 的区别
S3 event notification | S3 Object Lambda | |
触发的对象 | SNS topic,SQS queue 和 Lambda | Lambda |
触发的事件 | 可以由多种 S3 event 触发但不包括 S3 的 Get 请求 | S3 GET requests HeadObject ListObjects ListObjectsV2 |
4.3 S3 Object Lambda + ffmpeg
针对企业的需求,加水印转码部分使用 S3 Object Lambda 和 ffmpeg 实现,水印信息以编码进 presignURL 中的方式传递给转码服务。
视频水印添加方案 | 使用组件 | 配置过程 | 前置条件 |
使用无服务器服务 | S3 Object Lambda、Pillow 库和 ffmpeg | Lambda、Amazon S3、AWS Identity and Access Management(IAM)、ffmpeg、Boto3 和 Python 脚本语言的基础知识来构建此工作流程 | Lambda 函数最多可配置 10240 MB 内存对应6vCPU,这使得工作流程非常适合处理用户生成的内容(UGC) |
如下图所示,视频播放服务在生成 PresignURL 时在请求 URL query 中增加 X-Amz-WatermarkContent 等参数,值为水印控制信息,并且将其也加入待签字符串中进行签名,以防篡改。
1)创建水印 Lambda 函数,函数内存大小设置为 10240M(最大值)超时时间设置为 59s,用于基于 url 中传递的水印信息为视频添加水印,代码流程图及关键代码见 第五节-Lambda 配置。
2)为视频存储桶创建 S3Endpoint,基于该 S3Endpoint 创建 S3 ObjectLambda,将 Getobject 动作与水印 Lambda 函数关联。
3)为签署 PresignURL 使用的 IAMUser 或 Role 分配如下类似的权限:
5. Lambda 配置
由于所需的 ffmpeg 及 Pillow 库比较大,超过了代码包大小及单个 layer 的大小,故以两个 layer 的形式上传到 Lambda 中。详细源码参考:https://github.com/52aws/serverless_video_watermark
代码流程图如下所示:
ffmpeg 转码命令及参数:
-preset superfast 是转码速度等级参数,经过测试该配置最快,具体环境中可以自行测试选出最快的转码速度。
6. 水印效果展示
原始视频出处:
https://media.amazonwebservices.com/aws-china-media/uTBgpK07E38.mp4
水印效果展示:
经过测试,1080p 分辨率下每 10s 的视频切片 Lambda 转码时长为 3s 左右,可以做到实时流畅播放。在测试中,单区域 lambda 并发执行轻松跑到了 800 多,按 vCPU 计算,相当于并发调度了超过 5000 个核心同时进行转码。
Lambda 执行日志:
Lambda 并发监控截图:
7. 总结
本文主要讲述了使用 S3 Object Lambda 和 ffmpeg 实现一套高可用、低成本的视频动态添加水印的方案,基于函数计算和 Serverless 工作流的弹性高可用视频处理架构,充分体现了云原生时代 Serverless 化思想,以事件驱动的形式触发函数执行,真实计算资源真正意义上的按需使用。对于使用而言,这套方案在保证业务灵活度的同时,可以显著降低维护成本与资源成本,并大幅度地缩短项目交付时间。
本文抛砖引玉,为大家提供了一种通用的动态水印生成的思路。您通过改变水印层生成的方式,也可以实现视频水印在不同位置的动态移动,或将水印进行隐写,亦或是将水印隐写到音轨中。
在本系列第二篇文章中,我们会探讨如何使用 CloudFront 等服务提高全球用户的访问体验,以及在国内区域如何落地这套系统,从而构建一个全球通用的高可用,低成本的 Serverless 动态添加水印视频点播系统。
8. 参考资料
[2] Processing user-generated content using AWS Lambda and FFmpeg
[3] Building a serverless GIF generator with AWS Lambda: Part 1
[4] 签署 AWS API 请求
[5] Using Amazon S3 Object Lambda to Dynamically Watermark Images as They Are Retrieved
[6]Amazon S3 Features | Object Lambda | AWS