はじめに
MediaLiveでライブ配信を行う際、アーカイブを残しておくことがあるかと思います。
2020年1月現在では、MediaLiveのアーカイブ出力はtsファイル形式のみ対応しています。
tsファイルはVLCなどの動画プレイヤーを使わないと再生することができないため、
利用しやすいmp4ファイルに変換する必要があるという機会に何度か遭遇しました。
そのときに構築した自動でmp4に変換する仕組みを簡単に記載しておきます。
ざっくり構成図
MediaLive -> S3 -> Lambda -> MediaConvert -> S3
MediaLive
Output Groupで「Archive」を選択します。
S3
tsファイルを置くフォルダと
mp4ファイルを置くフォルダを用意します。
IAM
IAMロールを2つ作成します。
MediaConvert用 IAMロール
Policyはロール作成時に自動でアタッチされます。
- AmazonS3FullAccess
- AmazonAPIGatewayInvokeFullAccess
Lambda用 IAMロール
AWSデフォルトのPolicyを使用する場合はこのPolicyがあれば動作します。
(本番環境で構築する際は権限を絞りましょう)
- AWSElementalMediaConvertFullAccess
MediaConvert
mp4に変換させるジョブテンプレートを作成します。
(参考までに、JSONを貼っておきます)
{ "Queue": "arn:aws:mediaconvert:ap-northeast-1:<account-id>:queues/<キューの名前>", "Name": "<ジョブテンプレートの名前>", "Settings": { "OutputGroups": [ { "Name": "File Group", "Outputs": [ { "ContainerSettings": { "Container": "MP4", "Mp4Settings": { "CslgAtom": "INCLUDE", "CttsVersion": 0, "FreeSpaceBox": "EXCLUDE", "MoovPlacement": "PROGRESSIVE_DOWNLOAD" } }, "VideoDescription": { "Width": 1280, "ScalingBehavior": "DEFAULT", "Height": 720, "TimecodeInsertion": "DISABLED", "AntiAlias": "ENABLED", "Sharpness": 50, "CodecSettings": { "Codec": "H_264", "H264Settings": { "InterlaceMode": "PROGRESSIVE", "NumberReferenceFrames": 3, "Syntax": "DEFAULT", "Softness": 0, "GopClosedCadence": 1, "GopSize": 90, "Slices": 1, "GopBReference": "DISABLED", "SlowPal": "DISABLED", "SpatialAdaptiveQuantization": "ENABLED", "TemporalAdaptiveQuantization": "ENABLED", "FlickerAdaptiveQuantization": "DISABLED", "EntropyEncoding": "CABAC", "Bitrate": 1000000, "FramerateControl": "INITIALIZE_FROM_SOURCE", "RateControlMode": "CBR", "CodecProfile": "MAIN", "Telecine": "NONE", "MinIInterval": 0, "AdaptiveQuantization": "HIGH", "CodecLevel": "AUTO", "FieldEncoding": "PAFF", "SceneChangeDetect": "ENABLED", "QualityTuningLevel": "SINGLE_PASS", "FramerateConversionAlgorithm": "DUPLICATE_DROP", "UnregisteredSeiTimecode": "DISABLED", "GopSizeUnits": "FRAMES", "ParControl": "INITIALIZE_FROM_SOURCE", "NumberBFramesBetweenReferenceFrames": 2, "RepeatPps": "DISABLED", "DynamicSubGop": "STATIC" } }, "AfdSignaling": "NONE", "DropFrameTimecode": "ENABLED", "RespondToAfd": "NONE", "ColorMetadata": "INSERT" }, "AudioDescriptions": [ { "AudioTypeControl": "FOLLOW_INPUT", "AudioSourceName": "Audio Selector 1", "CodecSettings": { "Codec": "AAC", "AacSettings": { "AudioDescriptionBroadcasterMix": "NORMAL", "Bitrate": 96000, "RateControlMode": "CBR", "CodecProfile": "LC", "CodingMode": "CODING_MODE_2_0", "RawFormat": "NONE", "SampleRate": 48000, "Specification": "MPEG4" } }, "LanguageCodeControl": "FOLLOW_INPUT" } ], "Extension": ".mp4" } ], "OutputGroupSettings": { "Type": "FILE_GROUP_SETTINGS", "FileGroupSettings": { "Destination": "s3://<任意のS3バケット>/" } } } ], "AdAvailOffset": 0, "Inputs": [ { "AudioSelectors": { "Audio Selector 1": { "Offset": 0, "DefaultSelection": "DEFAULT", "ProgramSelection": 1 } }, "VideoSelector": { "ColorSpace": "FOLLOW", "Rotate": "DEGREE_0", "AlphaBehavior": "DISCARD" }, "FilterEnable": "AUTO", "PsiControl": "USE_PSI", "FilterStrength": 0, "DeblockFilter": "DISABLED", "DenoiseFilter": "DISABLED", "TimecodeSource": "EMBEDDED" } ] }, "AccelerationSettings": { "Mode": "DISABLED" }, "StatusUpdateInterval": "SECONDS_60", "Priority": 0 }
Lambda
S3にtsファイルが作成されたら発火するLambda関数を作成します。
S3トリガー
- イベントタイプ:ObjectCreated
- サフィックス:.ts
- プレフィックス:<任意のS3バケット>
関数
- ランタイム:Python 3.8
lambda_function.py
from __future__ import print_function import json import urllib.parse import boto3 import os print('Loading function') mediaconvert = boto3.client('mediaconvert', region_name='ap-northeast-1', endpoint_url='https://xxxxxxxx.mediaconvert.ap-northeast-1.amazonaws.com') s3 = boto3.client('s3') def lambda_handler(event, context): # Get the object from the event and show its content type bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8') inputFile = "s3://" + bucket + "/" + key outputKey = "s3://<任意のS3バケット>/" try: # Load job.json from disk and store as Python object: job_object with open("job.json", "r") as jsonfile: job_object = json.load(jsonfile) # Input/Output Setting job_object["Inputs"][0]["FileInput"] = inputFile job_object["OutputGroups"][0]["OutputGroupSettings"]["FileGroupSettings"]["Destination"] = outputKey # Exec MediaConvert's job response = mediaconvert.create_job( JobTemplate='arn:aws:mediaconvert:ap-northeast-1:<account-id>:jobTemplates/<ジョブテンプレートの名前>', Queue='arn:aws:mediaconvert:ap-northeast-1:<account-id>:queues/<キューの名前>', Role='arn:aws:iam::<account-id>:role/<ロールの名前>', Settings=job_object ) except Exception as e: print(e) raise e
job.json
{ "OutputGroups": [ { "Name": "File Group", "OutputGroupSettings": { "Type": "FILE_GROUP_SETTINGS", "FileGroupSettings": { "Destination": "" } } } ], "Inputs": [ { "FileInput": "" } ] }