本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用流式传输视频 CloudFront
媒体工作流通常将完成的内容(视频点播 (VOD) 文件、HTTP 直播 (HLS) 包、图像和图形)存储在 FSx for ONTAP 卷上,编辑、制作人和自动化系统使用 NFS 或 SMB 写入该卷。
通过连接到 FSx for ONTAP 卷的 Amazon S3 接入点, CloudFront 可以直接从该卷中提供内容。编辑和制作系统像往常一样通过 NFS 或 SMB 向卷发布内容,通过接入点 CloudFront 获取内容,观众则从最近的 CloudFront 边缘位置接收内容。
在本教程中,您将示例视频编码为 HLS 自适应比特率包,将输出上传到连接到 FSx for ONTAP 卷的接入点,使用原始访问控制配置 CloudFront 分发以使观众无法绕过直接访问音量,并验证直播是否端 CloudFront 对端播放。
注意
本教程大约需要 40 到 60 分钟才能完成。 AWS 服务 使用者会对您创建的资源产生费用。如果您及时完成所有步骤,包括清理部分,则美国东部(弗吉尼亚北部)的预期费用将低于 1美元 AWS 区域。该估算值不包括 FSx 对 ONTAP 容量本身的持续收费。
模式是如何运作的
请求流为:
观众的播放器(浏览器、移动应用程序、智能电视)向 CloudFront 域请求HLS主播放列表。
CloudFront 检查其边缘缓存。如果未成功, CloudFront 则使用签名版本 4 (Sigv4) 及其源访问控制 (OAC) 对请求进行签名,然后将其转发到接入点的 Amazon S3 终端节点。
接入点根据其访问策略授权请求,该策略允许 CloudFront 服务主体范围限于您的分发,并从 FSx for ONTAP 卷返回请求的对象。
CloudFront 在边缘缓存响应并将其返回给查看者。
HLS 包混合了两种类型的文件,它们受益于不同的缓存策略:
播放列表 (
.m3u8) 描述了哪些片段构成了直播内容。使用简短的Cache-ControlTTL,这样您就可以快速发布更新的播放列表。片段 (
.ts) 包含编码后的视频和音频。写入后,片段的内容永远不会改变,因此请使用长的、不可变Cache-Control的 TTL。
先决条件
第 1 步:将源视频编码为 HLS 包
使用 FFmpeg 制作 360p、720p 和 1080p 的三种变体 HLS 软件包,并具有逼真的过顶 (OTT) 比特率。生成的软件包包括一个主播放列表,该播放列表引用了每个变体的播放列表,每个播放列表都列出了四秒钟的传输流片段。
-
下载源视频。
$mkdir -p ~/media && cd ~/media curl -sSL -o sintel-1080p.mp4 \ https://download.blender.org/durian/trailer/sintel_trailer-1080p.mp4 -
使用三种自适应比特率变体将视频编码为 HLS。
$mkdir hls && cd hls ffmpeg -i ../sintel-1080p.mp4 \ -filter_complex "[0:v]split=3[v1][v2][v3]; \ [v1]scale=w=640:h=360[v1out]; \ [v2]scale=w=1280:h=720[v2out]; \ [v3]scale=w=1920:h=1080[v3out]" \ -map "[v1out]" -c:v:0 libx264 -b:v:0 800k -maxrate:v:0 856k -bufsize:v:0 1200k \ -map "[v2out]" -c:v:1 libx264 -b:v:1 3000k -maxrate:v:1 3200k -bufsize:v:1 4500k \ -map "[v3out]" -c:v:2 libx264 -b:v:2 5500k -maxrate:v:2 5900k -bufsize:v:2 8250k \ -preset veryfast -g 48 -keyint_min 48 -sc_threshold 0 \ -map a:0 -map a:0 -map a:0 -c:a aac -b:a:0 96k -b:a:1 128k -b:a:2 128k \ -f hls -hls_time 4 -hls_playlist_type vod -hls_flags independent_segments \ -hls_segment_filename "stream_%v/seg_%03d.ts" \ -master_pl_name master.m3u8 \ -var_stream_map "v:0,a:0,name:360p v:1,a:1,name:720p v:2,a:2,name:1080p" \ "stream_%v/playlist.m3u8"该命令生成一个目录树,其中包含一个主播放列表、三个变体播放列表以及每个变体的传输流片段。
hls/ ├── master.m3u8 ├── stream_360p/ │ ├── playlist.m3u8 │ ├── seg_000.ts │ └── ... ├── stream_720p/ │ ├── playlist.m3u8 │ ├── seg_000.ts │ └── ... └── stream_1080p/ ├── playlist.m3u8 ├── seg_000.ts └── ...
步骤 2:将 HLS 包上传到接入点
上传软件包两次,一次用于包含短 TTL 的播放列表,一次用于具有长且不可变的 TTL 的片段。正确设置Content-Type很重要:大多数玩家都需要 for .m3u8 和 application/vnd.apple.mpegurl f video/mp2t or .ts。
access-point-alias替换为您的接入点别名。
$# Playlists: short TTL, m3u8 content type aws s3 cp ~/media/hls/ "s3://access-point-alias/content/sintel/" \ --recursive --exclude "*" --include "*.m3u8" \ --content-type "application/vnd.apple.mpegurl" \ --cache-control "max-age=60" # Segments: long immutable TTL, ts content type aws s3 cp ~/media/hls/ "s3://access-point-alias/content/sintel/" \ --recursive --exclude "*" --include "*.ts" \ --content-type "video/mp2t" \ --cache-control "max-age=31536000,immutable"
确认上传的两个文件都符合预期的内容类型和缓存标头。
$aws s3api head-object --bucketaccess-point-alias\ --key content/sintel/master.m3u8 \ --query '{ContentType:ContentType,CacheControl:CacheControl}'
步骤 3:创建源站访问控制
源访问控制 (OAC) 允许您对接入点的请求进行 CloudFront 签名,因此 CloudFront只能获取对象。如果没有 OAC,则查看者可以通过直接从接入点端点请求对象来绕过 CloudFront 。
$aws cloudfront create-origin-access-control \ --origin-access-control-config \ 'Name=fsxn-media-oac,SigningProtocol=sigv4,SigningBehavior=always,OriginAccessControlOriginType=s3'
记下响应中的 Id。您将在下一步中使用它。
步骤 4:创建分 CloudFront 配
使用接入点别名作为源域创建 CloudFront 分配。使用CachingOptimized托管缓存策略,该策略遵循您在步骤 2 中设置的Cache-Control标头。
-
将以下配置保存到名为的文件中
dist.json,替换占位符。{ "CallerReference": "fsxn-media-1", "Comment": "FSx for ONTAP media delivery", "Enabled": true, "DefaultRootObject": "", "Origins": { "Quantity": 1, "Items": [{ "Id": "fsxn-ap", "DomainName": "access-point-alias.s3.region.amazonaws.com", "S3OriginConfig": {"OriginAccessIdentity": ""}, "OriginAccessControlId": "oac-id", "ConnectionAttempts": 3, "ConnectionTimeout": 10 }] }, "DefaultCacheBehavior": { "TargetOriginId": "fsxn-ap", "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"], "CachedMethods": {"Quantity": 2, "Items": ["GET", "HEAD"]} }, "Compress": true, "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6" }, "PriceClass": "PriceClass_100", "ViewerCertificate": {"CloudFrontDefaultCertificate": true} }注意
PriceClass_100仅在北美和欧洲使用 CloudFront 边缘站点,这样可以降低本教程的成本。对于全局边缘覆盖范围,请将该值更改为PriceClass_All。有关更多信息,请参阅为 CloudFront 分配选择价格等级。 -
创建发行版。
$aws cloudfront create-distribution --distribution-config file://dist.json \ --query 'Distribution.{Id:Id,DomainName:DomainName,ARN:ARN}'记下响应中的分发 ID、ARN 和域名。部署该分发大约需要五分钟。部署时,您可以继续执行步骤 5。
步骤 5:附加允许的接入点策略 CloudFront
接入点策略向 CloudFront 服务主体授予读取对象的权限,该权限仅限于使用AWS:SourceArn条件的特定分配。
-
将以下策略保存到名为的文件中
ap-policy.json,替换占位符。{ "Version": "2012-10-17", "Statement": [{ "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": {"Service": "cloudfront.amazonaws.com"}, "Action": "s3:GetObject", "Resource": "arn:aws:s3:region:account-id:accesspoint/access-point-name/object/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::account-id:distribution/distribution-id" } } }] } -
将策略附加到接入点。
$aws s3control put-access-point-policy \ --account-idaccount-id\ --nameaccess-point-name\ --policy file://ap-policy.json
步骤 6:验证播放
等待分发达到Deployed状态。
$aws cloudfront get-distribution --iddistribution-id\ --query 'Distribution.Status'
通过获取主播放列表 CloudFront。
$curl -sS "https://distribution-domain/content/sintel/master.m3u8"
响应应列出三种变体。
#EXTM3U #EXT-X-VERSION:6 #EXT-X-STREAM-INF:BANDWIDTH=1031744,RESOLUTION=640x360,CODECS="avc1.64001e,mp4a.40.2" stream_360p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=3497301,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2" stream_720p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=6311285,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2" stream_1080p/playlist.m3u8
检查响应标头的内容类型、缓存控制和缓存状态是否正确。
$curl -sSI "https://distribution-domain/content/sintel/stream_1080p/seg_000.ts"
成功的响应会显示content-type: video/mp2tcache-control: max-age=31536000,immutable、和一个x-cache标头,指示响应是来自边缘还是源头。
最后,使用 FFmpeg 端对端播放直播,以确认所有片段都正确提取和解码。
$ffprobe -v error \ -show_entries stream=codec_name,width,height \ -show_entries format=duration \ "https://distribution-domain/content/sintel/master.m3u8"
你也可以在 Safari 或 VLC 中打开主播放列表网址,或者使用诸如 hls.js
扩展模式
使用带有 HTTPS 的自定义域名。为您的域申请 ACM 证书,将其附加到分配中,然后添加指向该 CloudFront 域的 CNAME 记录。有关说明,请参阅将自定义 URL 与配合使用 CloudFront。
使用签名网址或签名 Cookie 保护优质内容。对于需要授权的内容(订阅服务、抢先体验预览、地理围栏内容),请使用 CloudFront 签名 URL 或签名 Cookie。请参阅使用签名网址和签名 Cookie 提供私有内容。
发布新内容时使缓存失效。替换播放列表或上传新的 HLS 包时,请使用从
aws cloudfront create-invalidationedge 中移除旧版本 CloudFront 。对于具有长 TTL 的不可变分段,通常不需要失效,因为每个包的分段文件名都是唯一的。为基于浏览器的玩家启用 CORS。如果其他网域中基于浏览器的 HLS 播放器加载了您的直播,请使用响应
Access-Control-Allow-Origin标头策略向 CloudFront响应添加标头。记录查看者请求。启用 CloudFront标准日志记录或实时日志,以捕获查看者对分析、计费或滥用检测的请求。
问题排查
- 403 禁止进入 CloudFront
缺少接入点策略,不包括 CloudFront 服务主体,或者
AWS:SourceArn条件引用了错误的分发 ARN。使用验证策略aws s3control get-access-point-policy并确认分发 ARN 与您的aws cloudfront create-distribution回复中的分发 ARN 相匹配。- 播放器加载主播放列表但无法播放
检查片段文件是否有
Content-Type: video/mp2t,播放列表是否有Content-Type: application/vnd.apple.mpegurl。一些玩家拒绝使用通用内容类型的片段。 Re-upload 使用正确的--content-type标志。- 新的播放列表需要时间才能吸引观众
CloudFront 缓存标题设置的 TTL 的播放
Cache-Control列表。如果您需要较短的 TTL,请使用较小的max-age值重新上传播放列表,或者创建无效状态。区段没有这个问题,因为它们的内容不会改变。x-cache: Miss from cloudfront根据每一个请求当某个区域的查看者第一次请求文件时,这是正常的。 CloudFront 失败时从原点获取并缓存 TTL 的响应。随后从该边缘站点请求相同文件的请求将返回
Hit from cloudfront。- 拒绝直接访问接入点
这是预期行为。OAC 要求来自服务主体的 SigV4-signed 请求 CloudFront,接入点策略限制对 CloudFront 服务主体的访问。观看者只能通过分发域访问内容。
清理
禁用并删除该分配,然后删除其余资源。必须先禁用发行版,然后才能将其删除,这需要几分钟。
禁用需要来自的两个值get-distribution-config:ETagf --if-match or 和 for 的内部DistributionConfig对象--distribution-config(完整的响应还包含 ETag,它update-distribution不接受)。
$# Capture the current ETag and the DistributionConfig body GET_ETAG=$(aws cloudfront get-distribution-config --iddistribution-id\ --query 'ETag' --output text) aws cloudfront get-distribution-config --iddistribution-id\ --query 'DistributionConfig' --output json \ | jq '.Enabled = false' > dist-updated.json # Disable the distribution. The response returns a new ETag. UPDATE_ETAG=$(aws cloudfront update-distribution --iddistribution-id\ --if-match "$GET_ETAG" --distribution-config file://dist-updated.json \ --query 'ETag' --output text) # Wait for Status to reach Deployed before deleting. aws cloudfront get-distribution --iddistribution-id\ --query 'Distribution.Status' # Delete the distribution using the ETag from the update call. aws cloudfront delete-distribution --iddistribution-id\ --if-match "$UPDATE_ETAG" # Fetch the OAC ETag, then delete the OAC. OAC_ETAG=$(aws cloudfront get-origin-access-control --idoac-id\ --query 'ETag' --output text) aws cloudfront delete-origin-access-control --idoac-id\ --if-match "$OAC_ETAG" aws s3control delete-access-point-policy \ --account-idaccount-id--nameaccess-point-nameaws s3 rm "s3://access-point-alias/content/sintel/" --recursive