AWS S3+Media Converter+CloudFront 做video file streaming CDN服务

Phanix
·
·
IPFS
·

虽然最后算算价格跟考虑使用情境应该不会采用这样的solution,但还是来记录一下。

Main idea

S3 bucket 会因为region 限制,所以如果使用者会遍部全球各地,那网路速度变成是服务最大的瓶颈。除非sync 所有资料,但是这样又会让储存费用倍增,对于少量不太会变动的档案这样弄还可以,但是如果是使用者产生的资料就会变得很可怕。
所以想法是开两个s3 bucket, 其中一个当作使用者上传video的storage,另一个当作转档后储存的storage。然后搭配cloudfront读取资料做cdn,提供各地使用者作video file streaming。

开S3 bucket储存档案

开bucket 的时候要决定档案要放在哪个region,所以还是有可能面临到使用者距离这个bucket要花许多传输时间。所以简单的解法是不要让使用者直接对bucket写入档案,而是先传到就近的EC2 instance,再由AWS内部水管传比较快。

然后关闭public access,避免安全漏洞。

在网页环境中要播放video file streaming,常使用HLS.js ,而影片是放在aws 的domain name底下,所以一定会有cors 的问题。所以记得要设定CORS policy,如果是allow * (如上图例最后面)的话会变成任何网站都可以来access 资料,这样不会是好事,所以要乖乖写好允许CORS 的网站。
这样s3 bucket 建立大抵完成。

Create IAM role for Media Convert

在开始使用Media Converter 之前,请先去建立MediaConvert_Default_Role,要不然没办法使用Media Convert 服务。

到IAM 页面,点选Roles

Create Role

直接看下面的services,可以找到MediaConvert

预设会带入S3fullaccess 跟Apigetwayinvokefullaccess 权限,直接下一步直到最后建立好为止。

使用Media Convert

上图是job list,可以看到之前的job 的状态。

Create Job 后,要先选择档案来源。接着增加output group (add output group)

output group 有多种格式,在这边我用apple hls

然后要指定Convert结果要写入到哪边。

output1 就是要指定output格式, bitrate等资料,可以在preset里头选择,也可以手动填写。在这边我用16:9 1280*720 5.0Mbps。如果要多个output也可以,继续按add output group就好。

Job setting里面要记得指定给MediaConvert_Default_Role去执行,要不然果会类似下图。

成功的话就没有error message

切段的video file也可以在s3 bucket 里头看到,而.m3u8档案就是streaming时的play list。

CloudFront CDN

上图为进到cloudfront的页面,可以看到每个distribution状态。要注意的是,因为CDN caching 的关系,所以做了任何修改都不会马上看到修改后的样子。

修改后或者是新建立的distribution都会看到状态是in progress,都要等一阵子

建立新的distribution,用Web,而RTMP已经快要终止服务了。

选择资料来源,除了s3 bucket 之外,也可以用Load balancer 等服务,反正就是后面真的有东西就是。

然后读取bucket 要有read permission (特别是当bucket 在建立的时候就已经关闭public access)。

如果是建立新的access identity,之后也可以查得到。

然后要whitelisting header,特别是CORS 相关的,要不然跨网域什么东西都拿不到。

建立之后可以看到domain name,就可以透过这个domain name 走http/https 来拿资料了。

除此之外,还可以设定signed url/signed cookie来限制存取,当有需要让某些资料只能被有登入的使用者浏览时就可以用到。

HLS.js streaming

最后就是写网页,最常用的应该就是HLS.js 。官网本身提供的范例也很清楚,改写一下即可,类似下面这样。

 <html>

  <head>
    <title>Hls.js demo - basic usage</title>
  </head>

  <body>
      <script src="https://hls-js-latest.netlify.app/dist/hls.js"></script>

      <center>
          <h1>Hls.js demo - basic usage</h1>
          <video height="600" id="video" controls></video>
      </center>

      <script>
        if(Hls.isSupported()) {
          var video = document.getElementById('video');
          var hls = new Hls({
              debug: true
          });
          hls.loadSource('https://YOUR_CLOUDFRONT_DOMAIN_NAME/PATH/TO_PLAY_LIST.m3u8');
          hls.attachMedia(video);
          hls.on(Hls.Events.MEDIA_ATTACHED, function() {
// video.muted = true;
            video.play();
        });
       }
       // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled.
       // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (ie .m3u8 URL) directly to the video element throught the `src` property.
       // This is using the built-in support of the plain video element, without using hls.js.
        else if (video.canPlayType('application/vnd.apple.mpegurl')) {
          video.src = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8';
          video.addEventListener('canplay',function() {
            video.play();
          });
        }
      </script>

  <!-- injected in netlify post processing step -->
<div style="position: absolute; top: 5px; right: 5px;">
  <a rel="noopener" href="https://www.netlify.com" target="_blank"><img src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" /></a>
</div></body>
</html>

Original link: Phanix's Blog

CC BY-NC-ND 2.0 授权

喜欢我的作品吗?别忘了给予支持与赞赏,让我知道在创作的路上有你陪伴,一起延续这份热忱!