如何在没有 AVPlayer 在播放文件之前下载文件的情况下从 S3 流式传输 MP4 视频?

How can I stream MP4 videos from S3 without AVPlayer downloading the files before playing them?

我在 public S3 存储桶中有很多长(45 分钟 - 90 分钟)的 MP4 视频,我想使用 AVPlayer 在我的 iOS 应用程序中播放它们。

我正在使用 AVPlayerViewController 播放它们,但我需要等待几分钟才能开始播放,因为它会下载整个视频而不是流式传输。

我正在本地缓存它,所以这只是第一次发生,但我很想流式传输视频,这样用户就不必等待整个视频下载。

有些人指出我需要 Cloudfront 来流式传输视频,但在文档中,我读到只有当多人流式传输同一文件时才需要这样做。我正在构建一个 MVP,所以我只需要一个简单的解决方案。

有没有什么方法可以使用 AVPlayerViewController 从 S3 存储桶流式传输 MP4 视频,而无需在向用户播放之前完全下载文件?

TLDR

AVPlayer 不支持您定义的 'streaming'(HTTP 范围请求),因此要么使用支持的替代视频播放器,要么使用支持的 HLS 等真实媒体流协议by AVPlayer & 将在全部下载之前开始播放视频。

CloudFront 通常非常适合交付,但并非真正需要 - 由于 CloudFront,您可能已经看到它被提及 RTMP distributions but they now have been discontinued


详细解答

S3 支持一个名为 byte-range fetches using HTTP range requests - you can verify this by doing a HEAD request to your video file & seeing that the Accept-Ranges 的概念 header 存在一个值设置为字节(或不是 'none')。

在浏览器中加载您的 MP4 文件并注意它可以在您单击播放后立即开始。您还可以移动到视频文件的末尾,但您还没有真正下载整个视频文件。 HTTP 范围请求是允许此机制工作的原因。当用户到达视频的那部分时,可以下载小块视频。这节省了文件服务器和用户带宽,同时提供比客户端下载整个文件更好的用户体验。

服务器首先需要支持 byte-range 获取,然后客户端才能决定发出范围请求(或不)。关键是,一旦服务器支持,HTTP 客户端就可以决定是要分块获取数据还是一次性获取所有数据。

这并不是您所知道的 'streaming' 并且在您的问题中指的是它,但它更 'downloading the video from the server in chunks and playing it back' 使用 HTTP 206 部分内容响应。

在视频中搜索时,您可以在浏览器的“网络”选项卡中看到这一系列的多个 206 响应。不会下载整个视频,但会从您跳到的任何位置流式传输视频。


AVPlayer

的问题

不幸的是,AVPlayer 不支持 'streaming' 使用 HTTP 范围请求和 HTTP 206 部分内容响应。 我已经通过创建在 Xcode.

中演示 iOS 应用程序

这与 S3 无关 - 如果您将这些文件存储在任何其他云提供商或文件服务器上,您会看到该文件在播放前仍处于完全加载状态.


可能的解决方案

既然问题清楚了,有2种解决方法。

使用替代视频播放器

最简单的解决方案是使用支持 byte-range 提取的替代视频播放器。我不是 iOS 开发方面的专家,所以遗憾的是我无法推荐替代方案,但我相信会有一个流行的库,业界更喜欢 in-built AVPlayer.这将为您提供 'streaming'.

的(非常常见的)定义
使用视频流协议

但是,如果您必须使用 AVPlayer,解决方案是使用视频流协议实现真正的媒体流 - 真正的流还允许您利用自适应比特率切换、实时音频切换、许可等功能.

有相当多的此类协议可用,例如 DASH (Dynamic Adaptive Streaming over HTTP), SRT (Secure Reliable Transport) & last but not least, HLS(HTTP 直播)。

如今,互联网上使用最广泛的流媒体协议是 Apple 自己创建的 HLS(嘿,也许不支持范围请求的原因是强制您使用该协议)。 Apple's own documentation 如果您有兴趣,可以深入研究。

在不过多了解协议细节的情况下,HLS 将允许播放通常更快地开始,fast-forwarding 可以更快地传输视频,因为它正在被观看以获得真正的流媒体体验。

继续使用 HLS:

  1. 使用 AWS Elemental MediaConvert 将您的 MP4 文件转换为 HLS 格式 - 除了 .ts 之外,结果输出将是 1(或更多).M3U8 个清单文件媒体片段文件

  2. 将生成的输出上传到 S3

  3. AVPlayer 指向 .M3U8 文件

let asset = AVURLAsset(url: "https://ermiya.s3.eu-west-1.amazonaws.com/videos/video1playlist.m3u8")
let item = AVPlayerItem(asset: asset)
...
  1. 享受near-instant视频的加载

CloudFront

关于 Amazon CloudFront,它本身不是必需的,在这种情况下 S3 就足够了,但快速 Google 搜索会提到它提供的大量好处,尤其是缓存可以帮助您以后节省 S3 成本。


结论

如果可以的话,我会选择转换为 HLS,因为它会产生更多的可能性并且通常是更好的真实流媒体体验,但由于 iOS AVPlayer 限制.

是否使用 CloudFront,将取决于您的用户群、S3 的使用情况和其他因素。

在您创建 MVP 时,我建议您将 MP4 文件批量转换为 HLS 格式,而不使用 CloudFront,这会给您的云配置增加额外的复杂性。