【初心者向け】AWS ELEMENTAL MEDIACONVERTでのスムーズな動画変換ガイド

この記事では、MediaConvertとLambdaを利用して動画ファイルをMP4形式に変換し、完了またはエラーのステータスに関する通知を電子メールで受け取る方法を共有します。開発フレームワークはAWS Amplifyです。  

## 動画ファイルの変換と配信の効率化

動画ファイルのサイズを圧縮し、ストリーミング速度を向上させ、データ転送のコストを削減するためには、Amazon Elastic TranscoderまたはAWS Elemental MediaConvertなどの動画変換サービスを利用することができます。

## AWS Elemental MediaConvertの概要
### [AWS Elemental MediaConvert]​​って何？
AWS Elemental MediaConvertは、ファイルベースの動画変換サービスであり、放送レベルの機能を備えています。これにより、オンデマンド（VOD）の動画コンテンツを容易に作成し、大規模な多画面配信が可能となります。

### AWS Elemental MediaConvertの主な機能は、以下のとおりです。
- 高度なビデオおよびオーディオ機能による高品質な動画変換
- 使用量に応じた課金によるコスト効率の向上
- 自動化による運用の簡素化
- セキュリティ機能の提供
- AWS Elemental MediaConvertのメリット

### AWS Elemental MediaConvertのメリット
AWS Elemental MediaConvertは、Amazon Elastic Transcoderと比較して、以下のメリットがあります。

- コストが安価
- 高度なセキュリティ機能（DRM）が組み込まれている
- AWS Elemental MediaConvertによる動画変換ガイド

ここでは、AWS Elemental MediaConvertを使用して動画ファイルをMP4形式に変換する手順を、AWS Amplifyを活用して紹介します。

## AWSアーキテクチャ概要
![WSアーキテクチャ概要](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/77f530d9-68d1-ebe0-4d0b-c103795c320d.png)

## 動画変換の処理流れ
- 管理者は、S3バケットの「/video/」フォルダーに動画ファイルをアップロードします。
- Event Bridgeは、S3バケットの「/video/」フォルダーに新しいファイルがアップロードされると、イベントをトリガーします。
- イベントがトリガーされると、[AWS Lambda](https://onetech.jp/blog/aws-lambda-the-service-for-building-serverless-on-aws-12682)関数が実行されます。
- Lambda関数は、アップロードされた動画ファイルの情報を取得し、動画変換の初期設定を行います。
- Lambda関数は、Lambda Layer FFProbeを使用して、ビデオファイルのサイズ情報を取得します。
- Lambda関数は、MediaConvertでジョブの作成を起動します。
- MediaConvertは、ジョブ情報を基にして動画変換処理を実行します。
- 処理が成功した場合、結果はS3バケットの「/video-convert/」フォルダーにアップロードされます。
- Event Bridgeは、「Completed」または「Error」のイベントを監視します。
- イベントが発生すると、Event BridgeはAWS SNSサービスを介してユーザーに通知のメールを送信します。
- ユーザーは、[CloudFront](https://onetech.jp/blog/what-is-amazon-cloudfront-13039)経由でS3バケットの「/video-convert/」フォルダー内の変換した動画ファイルを確認できます。

## AWS開発開始
コマンド実行：amplify init

名前: env

AWSプロフィールを入力する

他のパラメーターはデフォルトにしても結構です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/123abc18-9f8f-9d44-9d40-9d9a67fc9c3e.png)

コマンド実行：amplify add function

初期作成：Lambda 関数(serverless function) 

機能名：videoConvertを入力する

開発言語：nodeJS

Do you want to configure advanced settings > No

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/ad8fb2ff-3f75-6515-4ac4-9fbdd640c825.png)

### mediaconvertのため、下記の２URLが必要です。

- Url MediaConvert endpoint（Endpoint）
- Default queue（ARN）
 
**MediaConvertのURLを取得方法**

AWS Console→リージョンを選択→MediaConvert→メニュー→アカウントを選択すると下記のイメージ画像が表示される。

Endpoint:https://xxxxxxxx.mediaconvert.ap-southeast-1.amazonaws.com

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/aab47b87-726d-9c74-b08b-ad54117b21a7.png)

**Default queueのURLを取得方法**

AWS Console→リージョンを選択→MediaConvert→Queue→Defaultを押下すると下記の画面が表示されます。

ARN:　arn:aws:mediaconvert:ap-southeast-1:573580132305:queues/Default  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/b0e06496-4682-707a-8eb5-8651f2212271.png)

### S3 バケット内に動画の保存場所を作成
AWS Console→リージョンを選択→S3→Create bucket→Bucket name

名前：onetech-demo-mediaconvert
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/e5683080-6124-b6ea-e305-6e0fde6e2e97.png)

**S3バケットへのアクセス権限とオブジェクトへのアクセス権限の設定を行います。**

Bucket→onetech-demo-mediaconvert→Permissions→Bock public access→Edit→Uncheck Block all public access

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/a1068ea6-5b04-7392-6fb1-b5f48b729089.png)

Bucket → onetech-demo-mediaconvert → Permissions → Object Ownership → Edit

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/ad7e2f06-400a-a900-0a1d-7d597c95853f.png)

**Event BridgeはS3バケットへのアクセス許可設定**

onetech-demo-mediaconvertバケットをクリックする。

下記の画面に沿って設定を行う。

Properties → Event notifications → Amazon EventBridge → Edit → Turn ON → Save Changes

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/b6b012bd-5eec-eb43-8108-662993f5da76.png)

### node JSを使って開発プログラム開始

node JSライブラリをインストールする。
```json:Packaged.json
"devDependencies": {
 "aws-sdk": "^2.1416.0",
 "fluent-ffmpeg": "^2.1.2",
 "fs": "^0.0.1-security",
 "path": "^0.12.7"
}
```
cd amplify/backend/function/videoConvert/src 

npm install -D aws-sdk fluent-ffmpeg fs path ↓ Develop node_modules　※モック作成のため、サーバへアップロードすると情報が消えてします。

インストールが完了したらVisual studio codeでrootフォルダを開く 新しいファイルを作成：config/resize.json

下記のデータを入力する

```Json:resize.json
{
 "Queue": "xxxxxx",
 "UserMetadata": {
   "input": "s3://xxxxxx/videos/Video400mb.mp4",
   "environment": "dev"
 },
 "Role": "xxxxxxxx",
 "Settings": {
   "TimecodeConfig": {
     "Source": "ZEROBASED"
   },
   "OutputGroups": [
     {
       "CustomName": "MP4",
       "Name": "File Group",
       "Outputs": [
         {
           "ContainerSettings": {
             "Container": "MP4",
             "Mp4Settings": {}
           },
           "VideoDescription": {
             "Width": 3840,
             "Height": 2160,
             "CodecSettings": {
               "Codec": "H_264",
               "H264Settings": {
                 "GopClosedCadence": 1,
                 "GopSize": 90,
                 "GopBReference": "DISABLED",
                 "MaxBitrate": 3000000,
                 "SpatialAdaptiveQuantization": "ENABLED",
                 "TemporalAdaptiveQuantization": "ENABLED",
                 "FlickerAdaptiveQuantization": "DISABLED",
                 "RateControlMode": "QVBR",
                 "QvbrSettings": {
                   "QvbrQualityLevel": 7
                 },
                 "CodecProfile": "MAIN",
                 "MinIInterval": 0,
                 "AdaptiveQuantization": "HIGH",
                 "SceneChangeDetect": "DISABLED",
                 "QualityTuningLevel": "SINGLE_PASS",
                 "GopSizeUnits": "FRAMES",
                 "NumberBFramesBetweenReferenceFrames": 2
               }
             }
           },
           "AudioDescriptions": [
             {
               "CodecSettings": {
                 "Codec": "AAC",
                 "AacSettings": {
                   "Bitrate": 96000,
                   "CodingMode": "CODING_MODE_2_0",
                   "SampleRate": 48000
                 }
               }
             }
           ],
           "NameModifier": "Resize"
         }
       ],
       "OutputGroupSettings": {
         "Type": "FILE_GROUP_SETTINGS",
         "FileGroupSettings": {
           "Destination": "s3://xxxxxx/convert-video/",
           "DestinationSettings": {
             "S3Settings": {
               "AccessControl": {
                 "CannedAcl": "PUBLIC_READ"
               }
             }
           }
         }
       }
     }
   ],
   "Inputs": [
     {
       "AudioSelectors": {
         "Audio Selector 1": {
           "DefaultSelection": "DEFAULT"
         }
       },
       "VideoSelector": {
         "Rotate": "AUTO"
       },
       "TimecodeSource": "ZEROBASED",
       "FileInput": "s3://xxxxxx/videos/IMG_0961.MOV"
     }
   ]
 },
 "AccelerationSettings": {
   "Mode": "DISABLED"
 },
 "StatusUpdateInterval": "SECONDS_60",
 "Priority": 0,
 "Tags": {
   "MediaConvert": "DemoMediaConvert"
 }
}
```
**index.jsファイルを開いて動画設定などを行います。**

今回は下記の動画サイズを固定にします。

1920×1080、1080×1920

要求により変更設定をおこなってください。

黄色ところは上記の値を修正する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/b266cd63-3208-41aa-915a-16a1bb71f3e9.png)

```Javascript:index.js
const AWS = require('aws-sdk');
AWS.config.update({
 region: process.env.REGION,
});
const S3 = new AWS.S3({
 signatureVersion: 'v4'
});
//Chỗ này cần update lại endpoint mediaconvert
const MediaConvert = new AWS.MediaConvert({
 apiVersion: '2017-08-29',
 endpoint: 'https://xxxxx.mediaconvert.ap-southeast-1.amazonaws.com',
});
//Read file from local
const fs = require('fs');
//Get info video
const ffmpeg = require('fluent-ffmpeg');
exports.handler = async (event) => {
 try {
   if(!event.detail) {
     return false;
   }
   //Chỗ này cần update lại s3 bucket name
   const bucket = 'onetech-demo-mediaconvert';
   let convertWidth = 1920;
   let convertHeight = 1080;
   const objectKey = event.detail.object.key;
   const regex = /\/[^/]*$/;
   let convertFolder = objectKey.replace(regex, '/');
   convertFolder = convertFolder.replace('video/', 'convert-video/');
   console.log('convertFolder:::', convertFolder);
   console.log('objectKey:::', objectKey);
   //Check video vertical or horizontal
   try {
     const s3Params = {
       Bucket: bucket,
       Key: objectKey
     };
     const s3Stream = S3.getObject(s3Params).createReadStream();
     const info = await new Promise((resolve, reject) => {
       ffmpeg(s3Stream).ffprobe((err, info) => {
         if (err) {
           console.error(err);
           reject(err);
           return;
         }
         resolve(info);
       });
     });
     console.log('Video Information:', info);
     for (const stream of info.streams) {
       if (!stream.width) {
         continue;
       }
       console.log('Video INFO Steam', stream);
       if(+stream.width < +stream.height) {
         convertWidth = 1080;
         convertHeight = 1920;
       }
       if(stream.rotation && stream.rotation === '-90') {
         convertWidth = 1080;
         convertHeight = 1920;
       }
       break;
     }
   } catch (error) {
     console.error(error);
   }
   console.log('convertWidth', convertWidth);
   console.log('convertHeight', convertHeight);
   //End check video vertical or horizontal
   const jsonData = fs.readFileSync('./config/resize.json', 'utf8');
   let convertData = JSON.parse(jsonData);
   //Update queue
   convertData.Queue = 'arn:aws:mediaconvert:ap-southeast-1:111111111111:queues/Default';
   //Update role
   convertData.Role = process.env.MEDIA_CONVERT_ROLE;
   //Update input file
   const inputSource = `s3://${bucket}/${objectKey}`;
   const outSource = `s3://${bucket}/${convertFolder}`;
   convertData.Settings.Inputs[0].FileInput = inputSource;
   //Update output folder
   convertData.Settings.OutputGroups[0].OutputGroupSettings.FileGroupSettings.Destination = outSource;
   //Update video width and height
   convertData.Settings.OutputGroups[0].Outputs[0].VideoDescription.Width = convertWidth;
   convertData.Settings.OutputGroups[0].Outputs[0].VideoDescription.Height = convertHeight;
   //Update UserMetadata
   convertData.UserMetadata.input = objectKey;
   convertData.UserMetadata.environment = process.env.ENV;
   convertData.UserMetadata.output = convertFolder;
   convertData.UserMetadata.s3_bucket = bucket;
   console.log('JSON MEDIACONVERT DATA', convertData);
   const response = await MediaConvert.createJob(convertData).promise();
   console.log('MediaConvert Job created:', response.Job);
   return true;
 } catch (error) {
   console.error(error);
   return false;
 }
};
```
### プログラムが一旦完了します。これからインフラ構成を基づいてcloudformationを設定する
編集ファイル: amplify/backend/function/videoConvert/videoConvert-cloudformation-template.json

**説明:**
- LambdaFunction: Lambda function ビルド
- DemoVideoConvertEventBridgeS3TriggerRule: Event bridge trigger をビルドしてファイルが指定したフォルダへアップロードできるか

- MyLambdaPermission: Event bridgeからイベントを受け取り

- DemoVideoConvertEventBridgeProcessRule:MediaConvert処理が成功または失敗した場合にEvent Bridgeトリガーを構築するために使用されます

- DemoVideoConvertSNSProcessTopic: Event Bridgeからmediaconvert処理が成功か失敗か通知メールする

- DemoVideoConvertSNSProcessTopicPolicy: Event BridgeからのイベントをSNSが受け取るように許可します

- MyEmailSubscription:成功または失敗したMediaConvertの通知を受信するためのメール設定をします。

- MediaConvertExecutionRole: role Lambda function

- MediaConvertExecutionPolicy: Lambda functionで実行権限ポリシー

```Javascript:videoConvert-cloudformation-template.json
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Lambda Function resource stack creation using Amplify CLI",
  "Parameters": {
    "CloudWatchRule": {
      "Type": "String",
      "Default": "NONE",
      "Description": " Schedule Expression"
    },
    "deploymentBucketName": {
      "Type": "String"
    },
    "env": {
      "Type": "String"
    },
    "s3Key": {
      "Type": "String"
    }
  },
  "Conditions": {
    "ShouldNotCreateEnvResources": {
      "Fn::Equals": [
        {
          "Ref": "env"
        },
        "NONE"
      ]
    }
  },
  "Resources": {
    "LambdaFunction": {
      "Type": "AWS::Lambda::Function",
      "Metadata": {
        "aws:asset:path": "./src",
        "aws:asset:property": "Code"
      },
      "Properties": {
        "Code": {
          "S3Bucket": {
            "Ref": "deploymentBucketName"
          },
          "S3Key": {
            "Ref": "s3Key"
          }
        },
        "Handler": "index.handler",
        "FunctionName": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "demoVideoConvert",
            {
              "Fn::Join": [
                "",
                [
                  "demoVideoConvert",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "Environment": {
          "Variables": {
            "ENV": {
              "Ref": "env"
            },
            "REGION": {
              "Ref": "AWS::Region"
            },
            "MEDIA_CONVERT_ROLE": {
              "Fn::GetAtt": [
                "MediaConvertExecutionRole",
                "Arn"
              ]
            }
          }
        },
        "Role": {
          "Fn::GetAtt": [
            "LambdaExecutionRole",
            "Arn"
          ]
        },
        "Runtime": "nodejs18.x",
        "Layers": [],
        "MemorySize": 2048,
        "EphemeralStorage": {
          "Size": 2048
        },
        "Timeout": 300
      }
    },
    "DemoVideoConvertEventBridgeS3TriggerRule": {
      "DependsOn": [
        "LambdaFunction"
      ],
      "Type": "AWS::Events::Rule",
      "Properties": {
        "Name": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "DemoVideoConvertEventBridgeS3TriggerRule",
            {
              "Fn::Join": [
                "",
                [
                  "DemoVideoConvertEventBridgeS3TriggerRule",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "Description": "Trigger Lambda from S3 events",
        "EventPattern": {
          "source": [
            "aws.s3"
          ],
          "detail-type": [
            "Object Created"
          ],
          "detail": {
            "bucket": {
              "name": [
                "onetech-demo-mediaconvert"
              ]
            },
            "object": {
              "key": [
                {
                  "prefix": "video/"
                }
              ]
            }
          }
        },
        "Targets": [
          {
            "Arn": {
              "Fn::GetAtt": [
                "LambdaFunction",
                "Arn"
              ]
            },
            "Id": {
              "Fn::If": [
                "ShouldNotCreateEnvResources",
                "VideoAppEventBridgeRuleTargetId",
                {
                  "Fn::Join": [
                    "",
                    [
                      "VideoAppEventBridgeRuleTargetId",
                      "-",
                      {
                        "Ref": "env"
                      }
                    ]
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    "MyLambdaPermission": {
      "DependsOn": [
        "DemoVideoConvertEventBridgeS3TriggerRule"
      ],
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Fn::GetAtt": [
            "LambdaFunction",
            "Arn"
          ]
        },
        "Principal": "events.amazonaws.com",
        "SourceArn": {
          "Fn::GetAtt": [
            "DemoVideoConvertEventBridgeS3TriggerRule",
            "Arn"
          ]
        }
      }
    },
    "DemoVideoConvertEventBridgeProcessRule": {
      "DependsOn": [
        "DemoVideoConvertSNSProcessTopic"
      ],
      "Type": "AWS::Events::Rule",
      "Properties": {
        "Name": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "DemoVideoConvertEventBridgeProcessRule",
            {
              "Fn::Join": [
                "",
                [
                  "DemoVideoConvertEventBridgeProcessRule",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "Description": "Trigger mediaconvert process",
        "EventPattern": {
          "source": [
            "aws.mediaconvert"
          ],
          "detail": {
            "status": [
              "COMPLETE",
              "ERROR"
            ],
            "userMetadata": {
              "environment": [
                {
                  "Ref": "env"
                }
              ]
            }
          }
        },
        "Targets": [
          {
            "Arn": {
              "Ref": "DemoVideoConvertSNSProcessTopic"
            },
            "Id": {
              "Fn::If": [
                "ShouldNotCreateEnvResources",
                "VideoAppEventBridgeMediaconvertProcessRule",
                {
                  "Fn::Join": [
                    "",
                    [
                      "VideoAppEventBridgeMediaconvertProcessRule",
                      "-",
                      {
                        "Ref": "env"
                      }
                    ]
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    "DemoVideoConvertSNSProcessTopic": {
      "DependsOn": [],
      "Type": "AWS::SNS::Topic",
      "Properties": {
        "DisplayName": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "VideoAppSNSMediaconvertProcessTopic",
            {
              "Fn::Join": [
                "",
                [
                  "VideoAppSNSMediaconvertProcessTopic",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        }
      }
    },
    "DemoVideoConvertSNSProcessTopicPolicy": {
      "DependsOn": [
        "DemoVideoConvertSNSProcessTopic"
      ],
      "Type": "AWS::SNS::TopicPolicy",
      "Properties": {
        "Topics": [
          {
            "Ref": "DemoVideoConvertSNSProcessTopic"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "AllowEventBridgePublish",
              "Effect": "Allow",
              "Principal": {
                "Service": "events.amazonaws.com"
              },
              "Action": "sns:Publish",
              "Resource": {
                "Ref": "DemoVideoConvertSNSProcessTopic"
              }
            }
          ]
        }
      }
    },
    "MyEmailSubscription": {
      "DependsOn": [
        "DemoVideoConvertSNSProcessTopic"
      ],
      "Type": "AWS::SNS::Subscription",
      "Properties": {
        "Protocol": "email",
        "Endpoint": "duy@onetech.vn",
        "TopicArn": {
          "Ref": "DemoVideoConvertSNSProcessTopic"
        }
      }
    },
    "MediaConvertExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "videoAppMediaConvertRole",
            {
              "Fn::Join": [
                "",
                [
                  "videoAppMediaConvertRole",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "mediaconvert.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        }
      }
    },
    "MediaConvertExecutionPolicy": {
      "DependsOn": [
        "MediaConvertExecutionRole"
      ],
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "media-convert-execution-policy",
        "Roles": [
          {
            "Ref": "MediaConvertExecutionRole"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "s3:*",
                "s3-object-lambda:*"
              ],
              "Resource": "*"
            },
            {
              "Effect": "Allow",
              "Action": [
                "execute-api:Invoke",
                "execute-api:ManageConnections"
              ],
              "Resource": "arn:aws:execute-api:*:*:*"
            }
          ]
        }
      }
    },
    "LambdaExecutionRole": {
      "DependsOn": [
        "MediaConvertExecutionRole",
        "MediaConvertExecutionPolicy"
      ],
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "videoappconvertLambdaRole30cacecd",
            {
              "Fn::Join": [
                "",
                [
                  "videoappconvertLambdaRole30cacecd",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "lambda.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        }
      }
    },
    "LambdaExecutionPolicy": {
      "DependsOn": [
        "LambdaExecutionRole"
      ],
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "lambda-execution-policy",
        "Roles": [
          {
            "Ref": "LambdaExecutionRole"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
              ],
              "Resource": [
                {
                  "Fn::Sub": [
                    "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*",
                    {
                      "region": {
                        "Ref": "AWS::Region"
                      },
                      "account": {
                        "Ref": "AWS::AccountId"
                      },
                      "lambda": {
                        "Ref": "LambdaFunction"
                      }
                    }
                  ]
                }
              ]
            },
            {
              "Action": [
                "iam:PassRole"
              ],
              "Resource": [
                {
                  "Fn::GetAtt": [
                    "MediaConvertExecutionRole",
                    "Arn"
                  ]
                }
              ],
              "Effect": "Allow",
              "Sid": "PassRole"
            },
            {
              "Action": [
                "mediaconvert:*"
              ],
              "Resource": [
                "*"
              ],
              "Effect": "Allow",
              "Sid": "MediaConvertService"
            },
            {
              "Sid": "AllowS3Access",
              "Effect": "Allow",
              "Action": [
                "s3:PutObject",
                "s3:GetObject"
              ],
              "Resource": "*"
            }
          ]
        }
      }
    }
  },
  "Outputs": {
    "Name": {
      "Value": {
        "Ref": "LambdaFunction"
      }
    },
    "Arn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaFunction",
          "Arn"
        ]
      }
    },
    "Region": {
      "Value": {
        "Ref": "AWS::Region"
      }
    },
    "LambdaExecutionRole": {
      "Value": {
        "Ref": "LambdaExecutionRole"
      }
    }
  }
}
```

### ffmpegライブラリを実行するためのLambdaレイヤーをビルドします
コマンド実行：amplify add function
↓
Lambda layerを選択
↓
名前：videoConvertLayer
↓
Node JS
↓
Enter
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/742edd51-1182-cb14-d1f3-5586943d3a72.png)
↓
https://github.com/phuocduy1988/ffmpeg　からffmpegライブラリをダウンロードする。
↓
bin/　へコピー
↓
amplify/backend/function/lambdamediaconvertvideoConvertLayer/opt/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/e16c50c6-81d8-fd09-337e-3825c54e8e13.png)

↓

Node JSライブラリをインストールする
```javascript:Package.json
“devDependencies”: {
 “aws-sdk”: “^2.1416.0”,
 “fluent-ffmpeg”: “^2.1.2”,
 “fs”: “^0.0.1-security”,
 “path”: “^0.12.7”
}
```

cd amplify/backend/function/lambdamediaconvertvideoConvertLayer/lib/nodejs 

npm install aws-sdk fluent-ffmpeg fs path
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/bc3c259d-10f6-71f6-30f3-be9108903b0a.png)

このライブラリをインストールする目的は、Lambda関数のコードが共通ライブラリとして使用できるようにすることです。

### Lambda MediaConvertにLambdaレイヤーを追加します。
コマンド実行：amplify update function

Lambda function

videoConvert

→　Lambda layers configuration → Yes

スペースを押下

lambdamediaconvertvideoConvertLayerを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/012abc9a-781c-2b38-4613-7b5d864c1b4a.png)

### Amplify MediaConvertのソースをAWS Cloudにデプロイします。
コマンド実行：amplify push → YES
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/b693c66f-0d1e-f74f-4db7-79ae1bfaa6c0.png)
### MediaConvertの機能テスト
AWS Console → リージョン → S3 → onetech-demo-mediaconvert → videoフォルダ作成　→　動画をアップロード

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/4a212a21-f042-4ca4-5bc0-f6806a4b600f.png)

### Cloudwatch logを確認
[CloudWatch](https://onetech.jp/blog/introduction-about-aws-and-amazon-cloud-watch-9154) → Log groups → /aws/lambda/demoVideoConvert-dev
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/c6e8e466-83f0-2946-ba16-2076c20bcf91.png)

convert-videoフォルダで確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/6ed005d3-ffe7-7771-b8ce-4922fce281e1.png)
元々動画ファイルは128MBから9MBになりました。

### この検証のために作成したAWSリソースを削除します。
AWS Console →リージョン→ AWS Amplify → lambdamediaconvert → Delete appを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/0c847458-fc3d-8d2d-2d8c-f720311cd835.png)
### S3 バケット内に削除する
Amazon S3 → Buckets → onetech-demo-mediaconvert → Empty bucket
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387054/cc5323d8-b72b-b1ca-1c84-562240980d38.png)

## まとめ
AWS Elemental MediaConvertを使用して動画をMP4形式に変換してAWSの開発者にとって欠かせないスキルです。

最新技術を使いこなして、ユーザーにとって魅力的な動画配信体験を提供しましょう。

この記事が、効果的な動画変換ソリューションをお探しの皆様にとって有益であることを願っています。

Source: [https://onetech.jp/blog/aws-elemental-mediaconvertでのスムーズな動画変換ガイド-17623](https://onetech.jp/blog/aws-elemental-mediaconvertでのスムーズな動画変換ガイド-17623)