#はじめに
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
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
{
"OutputGroups": [
{
"Name": "File Group",
"OutputGroupSettings": {
"Type": "FILE_GROUP_SETTINGS",
"FileGroupSettings": {
"Destination": ""
}
}
}
],
"Inputs": [
{
"FileInput": ""
}
]
}