この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
こんにちは、中村です。
AWS Elemental MediaConvertではファイルベースで簡単に動画変換をすることができます。中でもHLSは特殊な設備が不要になっており、Webサーバーでも配信ができます。 今回は動画変換から配信までをAWS上で構築してみました。これは少しの修正とCloudformationのスタック作成作業のみで完成します。
作成してみた
コード
全てのコードはgithubに置いてあります。ローカルにPullして利用してください。 cm-nakamura-yuki/play-movie-using-aws
構成
Lambda
Lambdaを作成するにあたり、S3にソースコードをアップロードします。コード用のバケット名を決定し作成しましょう。 cfn/step1.ymlの45行目とcfn/step2.ymlの44行目にあるYOUR_CODE_BUCKET_NAMEを作成したバケット名にします。
start-movie-convert/index.tsの2行目にあるYOUR_MEDIA_CONVERT_ENDPOINTをMediaConvertのアカウントページに記載されているエンドポイントに、8行目のYOUR_AWS_ACCOUNT_IDを使用するAWSアカウントのアカウントIDに修正します。 lambda/put-dynamo/index.ts, lambda/start-movie-convert/index.tsもコンパイルし、zip化します。 zipファイル名は、cfn/step1.ymlの46行目, cfn/step2.ymlの45行目と同じにしてください。
$ zip -r NAME.zip index.ts
Cloudformationのスタックを作成
cfn/step1.yml, cfn/step2.yml, cfn/step3.ymlの順番でスタックを作成していきます。step3のYOUR_AWS_ACCOUNT_IDをスタックを作成するアカウントIDに修正してください。step3ではCloudfrontの作成も行うので時間がかかります。
HTMLのアップロード
index.htmlの14行目にあるYOUR_COGNITO_ARNにstep3で出力されているCognitoのARNに修正してください。 client配下のhtmlファイルをアップロードします。アップロード先は、dist-から始まるバケット(変換された動画が格納されるバケット)です。
MediaConvert
MediaConvertにてmp4tohlsというジョブテンプレートを作成します。S3に動画がPutされたタイミングでこのテンプレートを使ってJobを作成します。
{
"Category": "HLS",
"Name": "mp4tohls",
"Settings": {
"OutputGroups": [
{
"Name": "Apple HLS",
"Outputs": [
{
"ContainerSettings": {
"Container": "M3U8",
"M3u8Settings": {
"AudioFramesPerPes": 4,
"PcrControl": "PCR_EVERY_PES_PACKET",
"PmtPid": 480,
"PrivateMetadataPid": 503,
"ProgramNumber": 1,
"PatInterval": 0,
"PmtInterval": 0,
"Scte35Source": "NONE",
"NielsenId3": "NONE",
"TimedMetadata": "NONE",
"VideoPid": 481,
"AudioPids": [
482,
483,
484,
485,
486,
487,
488,
489,
490,
491,
492
]
}
},
"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,
"FramerateDenominator": 1,
"GopClosedCadence": 1,
"GopSize": 90,
"Slices": 1,
"GopBReference": "DISABLED",
"SlowPal": "DISABLED",
"SpatialAdaptiveQuantization": "ENABLED",
"TemporalAdaptiveQuantization": "ENABLED",
"FlickerAdaptiveQuantization": "DISABLED",
"EntropyEncoding": "CABAC",
"Bitrate": 5000000,
"FramerateControl": "SPECIFIED",
"RateControlMode": "CBR",
"CodecProfile": "MAIN",
"Telecine": "NONE",
"FramerateNumerator": 30,
"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",
"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"
}
],
"OutputSettings": {
"HlsSettings": {
"AudioGroupId": "program_audio",
"IFrameOnlyManifest": "EXCLUDE"
}
},
"NameModifier": "_hls"
}
],
"OutputGroupSettings": {
"Type": "HLS_GROUP_SETTINGS",
"HlsGroupSettings": {
"ManifestDurationFormat": "INTEGER",
"SegmentLength": 10,
"TimedMetadataId3Period": 10,
"CaptionLanguageSetting": "OMIT",
"Destination": "s3://dist-movie-source-645332194441/",
"TimedMetadataId3Frame": "PRIV",
"CodecSpecification": "RFC_4281",
"OutputSelection": "MANIFESTS_AND_SEGMENTS",
"ProgramDateTimePeriod": 600,
"MinSegmentLength": 0,
"MinFinalSegmentLength": 0,
"DirectoryStructure": "SINGLE_DIRECTORY",
"ProgramDateTime": "EXCLUDE",
"SegmentControl": "SEGMENTED_FILES",
"ManifestCompression": "NONE",
"ClientCache": "ENABLED",
"StreamInfResolution": "INCLUDE"
}
}
}
],
"AdAvailOffset": 0,
"Inputs": [
{
"AudioSelectors": {
"Audio Selector 1": {
"Offset": 0,
"DefaultSelection": "DEFAULT",
"ProgramSelection": 1
}
},
"VideoSelector": {
"ColorSpace": "FOLLOW"
},
"FilterEnable": "AUTO",
"PsiControl": "USE_PSI",
"FilterStrength": 0,
"DeblockFilter": "DISABLED",
"DenoiseFilter": "DISABLED",
"TimecodeSource": "EMBEDDED"
}
]
}
}
テスト
ここまで完成したらsrc-から始まるS3バケットに動画をアップロードしてみます。S3のPutを検知しLambdaがジョブを作成します。
ジョブが完了すると、dist-から始まるバケットへ変換された動画が作成されます。またdist-から始まるバケットに_hls.m3u8のファイルがPutされたのをトリガーにDynamoDBに書き込みます。
ブラウザから確認してみる
Cloudfrontのドメインにアクセスします。index.htmlはDynamoDBに格納されているデータを取得しリスト表示にします。
リンクをクリックするとview.htmlに遷移します。hls再生のためにhls.jsを利用しています。hls.jsは簡単に実装できサポート領域も広いです。(と思っています。)
hls.jsのサポート範囲
- Chrome for Android 34+
- Chrome for Desktop 34+
- Firefox for Android 41+
- Firefox for Desktop 42+
- IE11+ for Windows 8.1+
- Edge for Windows 10+
- Opera for Desktop
- Vivaldi for Desktop
- Safari for Mac 8+ (beta)
iOSのSafariは、残念ながら対象外(hls.jsを使わずにHLSが見れる)のため別の実装方法をしています。詳しくはclient/view.htmlを参照ください。
Playerが表示され動画もロードされているのを確認できました。
まとめ
初めてMediaConvertを使ってみました。 Elastic Transcoderもありますが、標準的な変換はこちらで十分かなと思います。
弊社では、「Amazon Connect」のキャンペーンを開催しています。
また音声を中心とした各種ソリューションの開発支援も行なっております。