亚马逊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 分配如下类似的权限:

{
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Action" : [
          "s3-object-lambda:GetObject"
        ],
        "Resource" : <s3_object_lambda_access_point arn>
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "s3:GetObject"
        ],
        "Resource" : [
          " <s3_access_point arn>/*"
        ]
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "lambda:InvokeFunction"
        ],
        "Resource" : [
          <watermark Lambda arn>
        ]
      }
    ]
  })
}

5. Lambda 配置

由于所需的 ffmpeg 及 Pillow 库比较大,超过了代码包大小及单个 layer 的大小,故以两个 layer 的形式上传到 Lambda 中。详细源码参考:https://github.com/52aws/serverless_video_watermark

代码流程图如下所示:

ffmpeg 转码命令及参数:

{ffmpeg_path} -y -i "{input_file}" -i {image_file} -filter_complex "[0:v][1:v]overlay=0:0" -preset superfast -f mpegts -copyts -c:v libx264 -c:a copy {output_file}

-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. 参考资料

[1] Introducing Amazon S3 Object Lambda – Use Your Code to Process Data as It Is Being Retrieved from S3 | AWS News Blog

[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

本篇作者

田亮

热爱户外运动,拥有丰富的云计算架构经验,AWS Authorized Instructor Program 成员,现供职于某知名金融投资公司。在从事 AWS 相关工作前,他负责国内某私有云厂商的交付工作。

范杰

18 年 JAVA 开发和架构经验,曾就职于京东,用友等企业在互联网,企业管理类等业务领域有丰富的工作经验,擅长车联网,电商,企业管理领域等技术,并且有丰富的项目管理经验。

孙彦巧

亚马逊云科技解决方案架构师,负责云计算解决方案的架构设计和咨询。有多年 AWS 从业经验,热衷于容器、微服务架构及 Devops 方面的研究和应用。

李少鹏

亚马逊云科技技术客户经理,十年以上的 IT 架构、运维和客户支持经验积累,专注于企业级客户的架构设计、成本优化和技术支持。在 DevOps、CI/CD 和容器等领域拥有丰富的技术和支持经验,致力于帮助客户实现技术创新和业务发展。