LoginSignup
25

More than 5 years have passed since last update.

[WIP]S3に置いた動画(.mp4)をLambdaとElasticTranscoderでHLSストリーミング動画(.ts)へ変換してcloudfrontのワンタイムURLで見るよ機構

Last updated at Posted at 2016-03-11

※動画変換できるわぁい で作っちゃうと痛い目見るかもしれませんのでご注意を。。

ざっくり流れ(適当)

スクリーンショット 2016-04-23 13.41.13.png

1. S3

準備

  • 適当なS3バケットを作ります 例:hoge001.fuga002.com
  • バケット内にmoviesというフォルダを作ります(作らなくても可)
  • バケットの設定(後でも可)
    • hoge001.fuga002.comバケットのプロパティ > イベント
      • イベント:Put, CompleteMultiPartUpload (←アップロードと、分割アップロード)
      • プレフィックス:movies/ (←moviesフォルダ配下)
      • サフィックス:.mp4
      • 送信先:Lambda関数
      • Lambda関数名:mp4_transcoder (←2で作るLambdaの関数名にします)

2. Lambda

?Lambdaてなんや?

“AWS Lambda は、コードを AWS Lambda にアップロードすると
サービスが AWS インフラストラクチャを使用してコードの実行を代行するコンピューティングサービスです。”

手順

  1. [Create a Lambda function] します
  2. [Skip] します(例文をもとに自分の好きなLambdaを書くのもいいと思います)
  3. [Name]はお好きなようにします
  4. [Description]もお好きなように説明書きします
  5. [Runtime]はNode.jsです
  6. Lambda function codeに下記のようなコードを入れます。(一部要編集)

NodeJSコード

console.log('Loading function');

var aws = require('aws-sdk');
var s3 = new aws.S3({ apiVersion: '2006-03-01' });
var s3tokyo = new aws.S3({apiVersion: '2006-03-01', endpoint: 'https://s3-ap-northeast-1.amazonaws.com'});
var ets = new aws.ElasticTranscoder({apiVersion: '2012-09-25', region: 'ap-northeast-1'});

exports.handler = function(event, context) {
  console.log('Received event:', JSON.stringify(event, null, "  "));
  var bucket = event.Records[0].s3.bucket.name;
  var key = event.Records[0].s3.object.key;
  var uploadFolderName = key.split('/')[0];
  var fileName = key.split('/')[1].split('.')[0];
  var extenSion = key.split('.')[1];
  var filePathAndName = key.split('.')[0];

  s3tokyo.getObject({Bucket:bucket, Key:key}, function(err, data){
    if (err){
    //getObject failed
      console.log(err);
      var message = 'Error getting object ' + key + ' from bucket ' + bucket +
        '. Make sure they exist and your bucket is in the same region as this function.';
      console.log(message);
      context.fail(message);
    }
    else {
    //getObject complete
      console.log('data:', data);
      console.log('bucket:', bucket);
      console.log('key:', key);
      console.log('uploadFolderName:', uploadFolderName);
      console.log('fileName:', fileName);
      console.log('extenSion:', extenSion);
      console.log('filePathAndName:', filePathAndName);
      console.log('ContentType:', data.ContentType);

      var isNotMp4file = (extenSion != 'mp4');
      if (isNotMp4file) {
      //context fail message if it isn't mp4 file.
        console.log('not mp4 file! process.exit!');
        context.fail(message);
        process.exit();
      }
      else {
        //Check the ContentType
        var isNotCorrectContentType = (data.ContentType != 'video/mp4');
        if (isNotCorrectContentType) {
          //if ContentType not equal "video/mp4", export the console.log
          console.log('[must conversion] data.ContentType != video/mp4');
        }
        var type = 'video/mp4';
        var params = {
          Bucket: bucket,
          CopySource: bucket + '/' + key,
          Key: key,
          ContentType: type,
          MetadataDirective: 'REPLACE'
        };
        console.log('PARAMS is :', params);
        console.log('To params set -> video/mp4');

        //Rewrite the ContentType
        s3tokyo.copyObject(params, function(err2, data2){
          if (err2){
            console.log('replace false...');
            context.done('error','error2 getting file '+ String(err2));
          }
          else {
            //Transcode to HLS
            ets.createJob(
                {
                  PipelineId: '*******************',
                  Input:
                  {
                    Key: key,
                    FrameRate: 'auto',
                    Resolution: 'auto',
                    AspectRatio: 'auto',
                    Interlaced: 'auto',
                    Container: 'auto',
                  },
                  Output:
                  {
                    Key: filePathAndName,
                    ThumbnailPattern: filePathAndName + '-thumbs-{count}',
                    SegmentDuration:'60',
                    PresetId: '1351620000001-200050',
                    Rotate: 'auto'
                  }
                }, function(error, data) {
                  if(error)
                  {
                    console.log(error);
                    context.done('Job error...',error);
                  }
                  else {
                    console.log('Job submitted');
                    context.done(null,'');
                  }
                }
            );
            //Transcode to mp3
            ets.createJob(
                {
                  PipelineId: '*******************',
                  Input:
                  {
                    Key: key,
                    FrameRate: 'auto',
                    Resolution: 'auto',
                    AspectRatio: 'auto',
                    Interlaced: 'auto',
                    Container: 'auto',
                  },
                  Output:
                  {
                    Key: filePathAndName + ".mp3",
                    PresetId: '1351620000001-300040',
                  }
                },
                function(error, data)
                {
                  if(error)
                  {
                    console.log(error);
                    context.done('Job error...',error);
                  }
                  else
                  {
                    console.log('Job submitted');
                    context.done(null,'');
                  }
                }
            );
          }
        });
      }
    }
  });
};
上記コードが主に行っていることは
1. S3にput, CompleteMultiPartUploadされた際にイベント発生
2. 対象のオブジェクト情報を取得
3. 拡張子がmp4でない場合はexit
コンソールログ出力「`not mp4 file! process.exit!`」
4. content-typeが"video/mp4"でない場合はexitコンソールログ出力「`[must conversion] data.ContentType != video/mp4`」
5. それ以外であればElastic TranscoderへJOB出力

6.Roleは、管理者権限があればlambda_basic_executionというRoleをその場で作り、後ほどにでもIAMの当該Roleに対して、S3へのアクセスポリシーと、ElasticTranscoderへのアクセスポリシーを付与します。(重要)
7.メモリやタイムアウト値は大きめがよいです。ただし…その分…お金が…
8.VPCは任意といった感じでしょうか..?(最近追加されたので詳しくは知らず。。)

その他備考

  • console.logはCloudWatchへ出力されるデバッグ用です。ログの出力先は AWS CloudWatch > ロググループ /aws/lambda/mp4_transcoder
  • フォルダ構成を深く掘る場合は、splitをうまく使ってください
  • PipelineId: '**********'にはElastic Transcoderで作成したパイプラインIDを入力します
  • Elastic Transcoderのジョブ作成の各パラメータ(.tsとか.flvとか.mp3に変換する際の)は下記を参考にしました
    http://docs.aws.amazon.com/ja_jp/elastictranscoder/latest/developerguide/create-job.html

  • 料金:https://aws.amazon.com/jp/lambda/pricing/
    0.20 USD/1,000,000 件のリクエスト(0.0000002 USD/秒)

3. Elastic Transcoder

?Elastic Transcoderてなんや?

“Amazon Elastic Transcoder はクラウドのメディア変換サービスです。
高度なスケーラビリティ、使いやすさ、高い費用効率性を実現する設計で、開発者や企業は、メディアファイルをその元のソース形式から
スマートフォン、タブレット、PC などのデバイスで再生可能できるバージョンに変換(または「トランスコード」)できます。”

パイプライン(←変換元と先の道路的な)のおもなの設定

  • 概要
    • Name: mp4-transcoder-pipeline
    • Status: Active
    • Input Bucket: hoge001.fuga002.com
  • トランスコード先、サムネイル保存先
    • Bucket: hoge001.fuga002.com
    • Storage Class: Standard
  • IAM Role
    • Elastic_Transcoder_Default_Role (←先ほどと同様にその場で作成)
  • Notifications
    • On Completion Event: Create a New SNS Topicから成功時のトピック名を適当に作成しておきます。
    • On Error Event: 同様にCreate a New SNS Topicから失敗時のトピック名を適当に作成しておきます。(後述するAWS SNSへ通知が飛ぶようになります。)

動き

  • LambdaがpipelineIDを指定し、Jobを作成する。 (jobは各動画ファイルの変換命令書)
  • Jobsのページで、pipelineIDを指定し、[search]を押すとエンコード履歴が確認できます。
  • JobのStatusは確認したものは以下
    • 成功:Complete
    • 実行中:Proccessing
    • 失敗:Error
    • 待機中:Submitted
  • Errorの場合は、JobのIDの左側にある虫眼鏡のアイコンをクリックし、"Status Details"のエラー内容を確認すること。

  • 料金:https://aws.amazon.com/jp/elastictranscoder/pricing/

4. SNS(Simple Notification Service)

?Simple Notification Serviceてなんや?

“Amazon SNS は、高速で、柔軟性に優れ、完全マネージド型の pub-sub メッセージングサービスです。
Amazon SNS は、通知、メール、SMS メッセージをプッシュするクラウドベースのモバイルアプリケーション通知サービスとして、
またはエンタープライズメッセージングインフラストラクチャとして使用できます。”
  1. Amazon SNSのページの、左メニュー"Topics"から、先ほどElastic Transcoderで設定したTopicを表示します。
  2. CompleteかErrorどちらかのトピックのARN名をクリックします。
  3. Create Subscriptionを押下し、好きなProtocolとEndpointを指定すれば、そのEndpoint宛へ購読可否が飛びます。
    (例:
    Protocol → Email
    Endpoint → 自分のメールアドレス)

  4. 届いたメール内のConfirm subscriptionのリンクへ飛べば購読手続き完了です。

5. CloudFront

?CloudFrontてなんや?

“Amazon CloudFront はコンテンツ配信ウェブサービスです。
他のアマゾン ウェブ サービス製品と統合されたこのサービスを利用すると、開発者や事業主は、
低レイテンシーと高速なデータ転送速度で簡単にエンドユーザーにコンテンツを配信できます。最低利用量の条件はありません。”

おもな設定

coming soon...

所感

そのうちcloudfrontの連携内容も書きます。

参考にしましたURL様

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25