概要
AWS CloudFormationを用いて簡単なHLS形式の動画配信環境を構築します。構成は次の通りです。
注意事項
- AWS CloudFormationの使い方に慣れていて、AWS Media Servicesについてもある程度知見をお持ちの方を対象にしていますが、初めての方もチャレンジしてみて下さい!
- PoCのため、各サービスのパラメーターはライブ配信に最適なチューニングはされず、ほぼデフォルトの値になっております。
- AWS CloudFormation テンプレートはYAML形式で記述しています。
- Tokyoリージョン (ap-northeast-1)で構築しています。
- 料金が発生しますので検証が終わりましたらCloudFormationスタックの削除を忘れないで下さい。
利用するAWSサービス
- AWS CloudFormation (以下 CloudFormation)
- AWS Elemental MediaLive (以下 MediaLive)
- AWS Elemental MediaStore (以下 MediaStore)
- Amazon CloudFront (以下 CloudFront)
手順
CloudFormation
今回は下記セッションに分けて記述していきます。リソースセッションに関しては必須なのでテンプレートに含める必要があります。
- 形式バージョン
- Description
- リソース
- 出力
他に記述可能なセッションについては下記をご参照下さい。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-anatomy.html
一気に全てのサービスをテンプレートファイルに書くよりも、まずはCloudFormationのテンプレートに追加する各サービスを分けて設定を見ていきます。
1. MediaStore
MediaLiveのDestinationにMediaStoreのEndpointを指定する必要があるため、先にMediaStoreのリソースを作成します。
- MediaStoreで設定するリソース
- Container
Container
■YAML構文
Type: AWS::MediaStore::Container
Properties:
AccessLoggingEnabled: Boolean
ContainerName: String
CorsPolicy:
- CorsRule
LifecyclePolicy: String
MetricPolicy:
MetricPolicy
Policy: String
Tags:
- Tag
■設定例
MediaStoreContainer:
Type: AWS::MediaStore::Container
Properties:
AccessLoggingEnabled: false
ContainerName: !Ref AWS::StackName
CorsPolicy:
- AllowedOrigins:
- '*'
AllowedMethods:
- GET
- HEAD
AllowedHeaders:
- '*'
MaxAgeSeconds: 3000
LifecyclePolicy:
"{\n \"rules\": [\n {\n \"definition\": {\n \"path\": [\n {\n \"prefix\": \"\"\n }\n ],\n \"days_since_create\": [\n {\n \"numeric\": [\n \">\",\n 1\n ]\n }\n ]\n },\n \"action\": \"EXPIRE\"\n }\n ]\n}"
MetricPolicy:
ContainerLevelMetrics: DISABLED
Policy:
!Sub "{\n \"Version\" : \"2012-10-17\",\n \"Statement\" : [{\n \"Sid\" : \"PublicReadOverHttps\",\n \"Effect\" : \"Allow\",\n \"Principal\" : \"*\",\n \"Action\" : [\n \"mediastore:GetObject\",\n \"mediastore:DescribeObject\"\n ],\n \"Resource\" : \"arn:aws:mediastore:${AWS::Region}:${AWS::AccountId}:container/${AWS::StackName}/*\",\n \"Condition\" : {\"Bool\" : {\n \"aws:SecureTransport\" : \"true\"\n }\n }\n }]\n}\n"
Tags:
- Key: "environment"
Value: "demo"
2.MediaLive
- MediaLiveで設定するリソース
- IAM role
- Input security group
- Input
- Channel
IAM role
■YAML構文
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: Json
Description: String
ManagedPolicyArns:
- String
MaxSessionDuration: Integer
Path: String
PermissionsBoundary: String
Policies:
- Policy
RoleName: String
Tags:
- Tag
■設定例
検証のため、PolicyはMediaStoreとCloudWatch Logsにのみ限定しています。
MediaLiveRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Join ['-', [ Ref: "AWS::StackName", "MediaLive-role", !Select [4, !Split ['-', !Select [2, !Split ['/', Ref: "AWS::StackId"]]]]]]
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- "medialive.amazonaws.com"
Action:
- sts:AssumeRole
Policies:
-
PolicyName: !Sub "${AWS::StackName}-medialive-policy"
PolicyDocument:
Statement:
- Effect: Allow
Action:
- mediastore:ListContainers
- mediastore:PutObject
- mediastore:GetObject
- mediastore:DeleteObject
- mediastore:DescribeObject
Resource: !Join ["", ["arn:aws:mediastore:", Ref: "AWS::Region", ":", Ref: "AWS::AccountId", ":*"]]
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogStreams
- logs:DescribeLogGroups
Resource: arn:aws:logs:*:*:*
Tags:
- Key: "environment"
Value: "demo"
Input security group
■YAML構文
Type: AWS::MediaLive::InputSecurityGroup
Properties:
Tags: Json
WhitelistRules:
- InputWhitelistRuleCidr
■設定例
MediaLiveInputSecurityGroup:
Type: AWS::MediaLive::InputSecurityGroup
Properties:
WhitelistRules:
- Cidr: 0.0.0.0/0
Input
■YAML構文
Type: AWS::MediaLive::Input
Properties:
Destinations:
- InputDestinationRequest
InputDevices:
- InputDeviceSettings
InputSecurityGroups:
- String
MediaConnectFlows:
- MediaConnectFlowRequest
Name: String
RoleArn: String
Sources:
- InputSourceRequest
Tags: Json
Type: String
Vpc:
InputVpcRequest
■設定例
MediaLiveInput:
Type: AWS::MediaLive::Input
Properties:
Destinations:
- StreamName: live/stream
InputSecurityGroups:
- !Ref MediaLiveInputSecurityGroup
Name: !Join ["-", [ Ref: "AWS::StackName", "ml-input"]]
Tags:
environment: demo
Type: RTMP_PUSH
Channel
■YAML構文
Type: AWS::MediaLive::Channel
Properties:
CdiInputSpecification:
CdiInputSpecification
ChannelClass: String
Destinations:
- OutputDestination
EncoderSettings:
EncoderSettings
InputAttachments:
- InputAttachment
InputSpecification:
InputSpecification
LogLevel: String
Name: String
RoleArn: String
Tags: Json
Vpc:
VpcOutputSettings
■設定例
MediaLive Channelの設定プロパティーはとても豊富なので慣れてきたら色々チューニングするのもいいかもしれません!
調整するパラメータ値
- MediaLiveの一般設定
- Channel class : SINGLE_PIPELINE
- Maximum input bitrate : MAX_10_MBPS
- Log level : Error
- Video
- 解像度 : 1280x720
- Codec Settings : H264
- Rate Control Mode : QVBR
- Bitrate : 2000000 bps
- Max Bitrate : 2000000 bps
- Framerate : 30 fps
- ABR : なし
- Audio
- Codec Settings : AAC
- Bitrate : 128000 bps
MediaLiveChannel:
Type: AWS::MediaLive::Channel
Properties:
ChannelClass: "SINGLE_PIPELINE"
Destinations:
- Id: msdest
MediaPackageSettings: []
Settings:
- Url: !Join [ "", [ "mediastoressl://", !Select [1, !Split [ "://", !GetAtt MediaStoreContainer.Endpoint ] ], "/live" ] ]
EncoderSettings:
AudioDescriptions:
- AudioSelectorName: Audio1
AudioTypeControl: FOLLOW_INPUT
CodecSettings:
AacSettings:
Bitrate: 128000
CodingMode: CODING_MODE_2_0
InputType: NORMAL
Profile: LC
RateControlMode: CBR
RawFormat: NONE
SampleRate: 48000
Spec: MPEG4
LanguageCodeControl: FOLLOW_INPUT
Name: audio_720p128k
CaptionDescriptions: []
OutputGroups:
- Name: MediaStore Group
OutputGroupSettings:
HlsGroupSettings:
AdMarkers: []
CaptionLanguageMappings: []
CaptionLanguageSetting: OMIT
ClientCache: ENABLED
CodecSpecification: RFC_4281
Destination:
DestinationRefId: msdest
DirectoryStructure: SINGLE_DIRECTORY
DiscontinuityTags: INSERT
HlsCdnSettings:
HlsMediaStoreSettings:
ConnectionRetryInterval: 1
FilecacheDuration: 300
MediaStoreStorageClass: TEMPORAL
NumRetries: 10
RestartDelay: 15
HlsId3SegmentTagging: DISABLED
IFrameOnlyPlaylists: DISABLED
IncompleteSegmentBehavior: AUTO
IndexNSegments: 10
InputLossAction: EMIT_OUTPUT
IvInManifest: INCLUDE
IvSource: FOLLOWS_SEGMENT_NUMBER
KeepSegments: 21
ManifestCompression: NONE
ManifestDurationFormat: FLOATING_POINT
Mode: LIVE
OutputSelection: MANIFESTS_AND_SEGMENTS
ProgramDateTime: EXCLUDE
ProgramDateTimePeriod: 600
RedundantManifest: DISABLED
SegmentLength: 10
SegmentationMode: USE_SEGMENT_DURATION
SegmentsPerSubdirectory: 10000
StreamInfResolution: INCLUDE
TimedMetadataId3Frame: PRIV
TimedMetadataId3Period: 10
TsFileMode: SEGMENTED_FILES
Outputs:
- AudioDescriptionNames:
- audio_720p128k
CaptionDescriptionNames: []
OutputName: 720p2m
OutputSettings:
HlsOutputSettings:
H265PackagingType: HVC1
HlsSettings:
StandardHlsSettings:
AudioRenditionSets: program_audio
M3u8Settings:
AudioFramesPerPes: 4
AudioPids: 492-498
NielsenId3Behavior: NO_PASSTHROUGH
PcrControl: PCR_EVERY_PES_PACKET
PmtPid: '480'
ProgramNum: 1
Scte35Behavior: NO_PASSTHROUGH
Scte35Pid: '500'
TimedMetadataBehavior: NO_PASSTHROUGH
TimedMetadataPid: '502'
VideoPid: '481'
NameModifier: "_2m"
VideoDescriptionName: video_720p2m
TimecodeConfig:
Source: EMBEDDED
VideoDescriptions:
- CodecSettings:
H264Settings:
AdaptiveQuantization: AUTO
AfdSignaling: NONE
Bitrate: 2000000
ColorMetadata: INSERT
EntropyEncoding: CABAC
FlickerAq: ENABLED
ForceFieldPictures: DISABLED
FramerateControl: SPECIFIED
FramerateDenominator: 996
FramerateNumerator: 30000
GopBReference: DISABLED
GopClosedCadence: 1
GopSize: 90
GopSizeUnits: FRAMES
Level: H264_LEVEL_AUTO
LookAheadRateControl: MEDIUM
MaxBitrate: 2000000
NumRefFrames: 1
ParControl: INITIALIZE_FROM_SOURCE
Profile: MAIN
RateControlMode: QVBR
ScanType: PROGRESSIVE
SceneChangeDetect: ENABLED
SpatialAq: ENABLED
SubgopLength: FIXED
Syntax: DEFAULT
TemporalAq: ENABLED
TimecodeInsertion: DISABLED
Height: 720
Name: video_720p2m
RespondToAfd: NONE
ScalingBehavior: DEFAULT
Sharpness: 100
Width: 1280
InputAttachments:
- InputAttachmentName: !Join ["-", [ Ref: "AWS::StackName", "ml-input"]]
InputId: !Ref MediaLiveInput
InputSettings:
AudioSelectors:
- Name: Audio1
CaptionSelectors: []
DeblockFilter: DISABLED
DenoiseFilter: DISABLED
FilterStrength: 1
InputFilter: AUTO
Smpte2038DataPreference: IGNORE
SourceEndBehavior: CONTINUE
InputSpecification:
Codec: AVC
MaximumBitrate: MAX_10_MBPS
Resolution: HD
LogLevel: ERROR
Name: !Join ["-", [ Ref: "AWS::StackName", "ml-ch"]]
RoleArn: !GetAtt MediaLiveRole.Arn
Tags:
environment: demo
4.CloudFront
- CloudFrontで設定するリソース
- Distribution
調整するパラメータ値
- Protocol : HTTPS only
- Viewer protocol policy : Redirect HTTP to HTTPS
- Allowed HTTP methods : GET, HEAD, OPTIONS
- Headers : Access-Control-Request-Method, Access-Control-Request-Headers, Origin
- Object caching : Minimum TTL, Maximum TTL, Default TTL = 1s
■YAML構文
{
"Type" : "AWS::CloudFront::Distribution",
"Properties" : {
"DistributionConfig" : DistributionConfig,
"Tags" : [ Tag, ... ]
}
}
■設定例
ここでは設定を省きますが、m3u8ファイルとtsファイルをそれぞれ適切なTTLにすることもできます。
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !Join ["-", [ Ref: "AWS::StackName", "ms-ctn"]]
DomainName: !Sub
- ${ENDPOINT}
- { ENDPOINT: !Select [1, !Split [ "://", !GetAtt MediaStoreContainer.Endpoint ]]}
CustomOriginConfig:
OriginProtocolPolicy: https-only
Enabled: true
Comment: "CloudFront for demo livestreaming"
Logging:
IncludeCookies: false
Bucket: ''
Prefix: ''
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
Compress: true
MaxTTL: 1
MinTTL: 1
ViewerProtocolPolicy: "redirect-to-https"
DefaultTTL: 1
TargetOriginId: !Join ["-", [ Ref: "AWS::StackName", "ms-ctn"]]
ForwardedValues:
QueryString: false
Cookies:
Forward: none
Headers:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
PriceClass: PriceClass_All
ViewerCertificate:
CloudFrontDefaultCertificate: true
Metadata:
cfn_nag:
rules_to_suppress:
- id: W70
reason: "CloudFront automatically sets the security policy to TLSv1 when the distribution uses the CloudFront domain name (CloudFrontDefaultCertificate=true)"
最終形態
先程設定した各サービスのリソースセッションをCloudFormationテンプレートに落とし込みます。記述が長いので設定例をクリックしてご確認下さい。
設定例
Description: "Cloudformation for MediaServices - MediaLive, MediaStore, CloudFront"
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MediaStoreContainer:
Type: AWS::MediaStore::Container
Properties:
AccessLoggingEnabled: false
ContainerName: !Ref AWS::StackName
CorsPolicy:
- AllowedOrigins:
- '*'
AllowedMethods:
- GET
- HEAD
AllowedHeaders:
- '*'
MaxAgeSeconds: 3000
LifecyclePolicy:
"{\n \"rules\": [\n {\n \"definition\": {\n \"path\": [\n {\n \"prefix\": \"\"\n }\n ],\n \"days_since_create\": [\n {\n \"numeric\": [\n \">\",\n 1\n ]\n }\n ]\n },\n \"action\": \"EXPIRE\"\n }\n ]\n}"
MetricPolicy:
ContainerLevelMetrics: DISABLED
Policy:
!Sub "{\n \"Version\" : \"2012-10-17\",\n \"Statement\" : [{\n \"Sid\" : \"PublicReadOverHttps\",\n \"Effect\" : \"Allow\",\n \"Principal\" : \"*\",\n \"Action\" : [\n \"mediastore:GetObject\",\n \"mediastore:DescribeObject\"\n ],\n \"Resource\" : \"arn:aws:mediastore:${AWS::Region}:${AWS::AccountId}:container/${AWS::StackName}/*\",\n \"Condition\" : {\"Bool\" : {\n \"aws:SecureTransport\" : \"true\"\n }\n }\n }]\n}\n"
Tags:
- Key: "environment"
Value: "demo"
MediaLiveRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Join ['-', [ Ref: "AWS::StackName", "MediaLive-role", !Select [4, !Split ['-', !Select [2, !Split ['/', Ref: "AWS::StackId"]]]]]]
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- "medialive.amazonaws.com"
Action:
- sts:AssumeRole
Policies:
-
PolicyName: !Sub "${AWS::StackName}-medialive-policy"
PolicyDocument:
Statement:
- Effect: Allow
Action:
- mediastore:ListContainers
- mediastore:PutObject
- mediastore:GetObject
- mediastore:DeleteObject
- mediastore:DescribeObject
Resource: !Join ["", ["arn:aws:mediastore:", Ref: "AWS::Region", ":", Ref: "AWS::AccountId", ":*"]]
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogStreams
- logs:DescribeLogGroups
Resource: arn:aws:logs:*:*:*
Tags:
- Key: "environment"
Value: "demo"
MediaLiveInputSecurityGroup:
Type: AWS::MediaLive::InputSecurityGroup
Properties:
WhitelistRules:
- Cidr: 0.0.0.0/0
MediaLiveInput:
Type: AWS::MediaLive::Input
Properties:
Destinations:
- StreamName: live/stream
InputSecurityGroups:
- !Ref MediaLiveInputSecurityGroup
Name: !Join ["-", [ Ref: "AWS::StackName", "ml-input"]]
Tags:
environment: demo
Type: RTMP_PUSH
MediaLiveChannel:
Type: AWS::MediaLive::Channel
Properties:
ChannelClass: "SINGLE_PIPELINE"
Destinations:
- Id: msdest
MediaPackageSettings: []
Settings:
- Url: !Join [ "", [ "mediastoressl://", !Select [1, !Split [ "://", !GetAtt MediaStoreContainer.Endpoint ] ], "/live" ] ]
EncoderSettings:
AudioDescriptions:
- AudioSelectorName: Audio1
AudioTypeControl: FOLLOW_INPUT
CodecSettings:
AacSettings:
Bitrate: 128000
CodingMode: CODING_MODE_2_0
InputType: NORMAL
Profile: LC
RateControlMode: CBR
RawFormat: NONE
SampleRate: 48000
Spec: MPEG4
LanguageCodeControl: FOLLOW_INPUT
Name: audio_720p128k
CaptionDescriptions: []
OutputGroups:
- Name: MediaStore Group
OutputGroupSettings:
HlsGroupSettings:
AdMarkers: []
CaptionLanguageMappings: []
CaptionLanguageSetting: OMIT
ClientCache: ENABLED
CodecSpecification: RFC_4281
Destination:
DestinationRefId: msdest
DirectoryStructure: SINGLE_DIRECTORY
DiscontinuityTags: INSERT
HlsCdnSettings:
HlsMediaStoreSettings:
ConnectionRetryInterval: 1
FilecacheDuration: 300
MediaStoreStorageClass: TEMPORAL
NumRetries: 10
RestartDelay: 15
HlsId3SegmentTagging: DISABLED
IFrameOnlyPlaylists: DISABLED
IncompleteSegmentBehavior: AUTO
IndexNSegments: 10
InputLossAction: EMIT_OUTPUT
IvInManifest: INCLUDE
IvSource: FOLLOWS_SEGMENT_NUMBER
KeepSegments: 21
ManifestCompression: NONE
ManifestDurationFormat: FLOATING_POINT
Mode: LIVE
OutputSelection: MANIFESTS_AND_SEGMENTS
ProgramDateTime: EXCLUDE
ProgramDateTimePeriod: 600
RedundantManifest: DISABLED
SegmentLength: 10
SegmentationMode: USE_SEGMENT_DURATION
SegmentsPerSubdirectory: 10000
StreamInfResolution: INCLUDE
TimedMetadataId3Frame: PRIV
TimedMetadataId3Period: 10
TsFileMode: SEGMENTED_FILES
Outputs:
- AudioDescriptionNames:
- audio_720p128k
CaptionDescriptionNames: []
OutputName: 720p2m
OutputSettings:
HlsOutputSettings:
H265PackagingType: HVC1
HlsSettings:
StandardHlsSettings:
AudioRenditionSets: program_audio
M3u8Settings:
AudioFramesPerPes: 4
AudioPids: 492-498
NielsenId3Behavior: NO_PASSTHROUGH
PcrControl: PCR_EVERY_PES_PACKET
PmtPid: '480'
ProgramNum: 1
Scte35Behavior: NO_PASSTHROUGH
Scte35Pid: '500'
TimedMetadataBehavior: NO_PASSTHROUGH
TimedMetadataPid: '502'
VideoPid: '481'
NameModifier: "_2m"
VideoDescriptionName: video_720p2m
TimecodeConfig:
Source: EMBEDDED
VideoDescriptions:
- CodecSettings:
H264Settings:
AdaptiveQuantization: AUTO
AfdSignaling: NONE
Bitrate: 2000000
ColorMetadata: INSERT
EntropyEncoding: CABAC
FlickerAq: ENABLED
ForceFieldPictures: DISABLED
FramerateControl: SPECIFIED
FramerateDenominator: 996
FramerateNumerator: 30000
GopBReference: DISABLED
GopClosedCadence: 1
GopSize: 90
GopSizeUnits: FRAMES
Level: H264_LEVEL_AUTO
LookAheadRateControl: MEDIUM
MaxBitrate: 2000000
NumRefFrames: 1
ParControl: INITIALIZE_FROM_SOURCE
Profile: MAIN
RateControlMode: QVBR
ScanType: PROGRESSIVE
SceneChangeDetect: ENABLED
SpatialAq: ENABLED
SubgopLength: FIXED
Syntax: DEFAULT
TemporalAq: ENABLED
TimecodeInsertion: DISABLED
Height: 720
Name: video_720p2m
RespondToAfd: NONE
ScalingBehavior: DEFAULT
Sharpness: 100
Width: 1280
InputAttachments:
- InputAttachmentName: !Join ["-", [ Ref: "AWS::StackName", "ml-input"]]
InputId: !Ref MediaLiveInput
InputSettings:
AudioSelectors:
- Name: Audio1
CaptionSelectors: []
DeblockFilter: DISABLED
DenoiseFilter: DISABLED
FilterStrength: 1
InputFilter: AUTO
Smpte2038DataPreference: IGNORE
SourceEndBehavior: CONTINUE
InputSpecification:
Codec: AVC
MaximumBitrate: MAX_10_MBPS
Resolution: HD
LogLevel: ERROR
Name: !Join ["-", [ Ref: "AWS::StackName", "ml-ch"]]
RoleArn: !GetAtt MediaLiveRole.Arn
Tags:
environment: demo
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: !Join ["-", [ Ref: "AWS::StackName", "ms-ctn"]]
DomainName: !Sub
- ${ENDPOINT}
- { ENDPOINT: !Select [1, !Split [ "://", !GetAtt MediaStoreContainer.Endpoint ]]}
CustomOriginConfig:
OriginProtocolPolicy: https-only
Enabled: true
Comment: "CloudFront for demo livestreaming"
Logging:
IncludeCookies: false
Bucket: ''
Prefix: ''
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
Compress: true
MaxTTL: 1
MinTTL: 1
ViewerProtocolPolicy: "redirect-to-https"
DefaultTTL: 1
TargetOriginId: !Join ["-", [ Ref: "AWS::StackName", "ms-ctn"]]
ForwardedValues:
QueryString: false
Cookies:
Forward: none
Headers:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
PriceClass: PriceClass_All
ViewerCertificate:
CloudFrontDefaultCertificate: true
Metadata:
cfn_nag:
rules_to_suppress:
- id: W70
reason: "CloudFront automatically sets the security policy to TLSv1 when the distribution uses the CloudFront domain name (CloudFrontDefaultCertificate=true)"
Outputs:
LiveCloudFront:
Description: CloudFront Live Playback URL
Value: !Sub "https://${CloudFront.DomainName}/live.m3u8"
MediaLiveChannelConsole:
Description: This is the MediaLive Console. Click the link, then start the new channel.
Value: !Sub "https://console.aws.amazon.com/medialive/home?region=${AWS::Region}#!/channels:"
MediaLiveRTMPDest:
Description: RTMP Destination for MediaLive Input
Value: !Select [ 0, !GetAtt MediaLiveInput.Destinations]
MediaStoreLiveStreamUrl:
Description: MediaStore Playback URL
Value: !Sub "${MediaStoreContainer.Endpoint}/live.m3u8"
スタック作成
1. CloudFormationスタックを作成します。
最初はChange setsで作成予定のリソースを確認した方がいいかもしれません。
2. 作成成功。Resourceタブから作成済みのリソースを確認できました。
配信と視聴テスト
1. MediaLive Channelを起動します。
OutputsのMediaLiveChannelConsoleから移動できます。
2. OBSやffmpegを使ってRTMP PushでMediaLive Inputの送信先にストリームを送ります。
RTMPの送信先はOutputsのMediaLiveRTMPDestで確認できます。
MP4ファイルでテスト配信をする場合のffmpegの実行例 :
ffmpeg -re -stream_loop -1 -i {INPUTFILE} -acodec copy -vcodec copy -f flv {MediaLiveRTMPDest}
3. 配信が出てきていることを確認します。
MediaLiveコンソール -> Alertsでアラートが消えていればMediaLiveにストリームが無事入ってきていることを意味します。
3. CloudFrontの視聴URLでSafariブラウザーかVLC Media Playerから視聴します。
視聴URLはOutputsのLiveCloudFrontから取得できます。
HLS(m3u8)形式での視聴はSafariブラウザーやVLC Media Playerといったメディアプレイヤーが必要です。
スタックの削除
不要な料金が発生するのを防ぐために、動作確認が終わったらスタックを削除することをお勧めします。
- 削除の流れとしては
1. MediaLive Channelを停止
2. MediaStore Containerのオブジェクトを削除
3. CloudFormationのスタックを削除
Channelが起動中、もしくはContainerの中身が空ではない状態でスタックの削除を試みるとエラーが出ます。
まとめ
上記CloudFormationを使ってライブ配信一連のリソースを作成してみました。DVR機能が必要な場合はMediaStoreの代わりにAWS Elemental MediaPackageを利用することも可能です。尚、今回は作成する各リソースは一つのみですが、強力なTransform セクションを使えば複数の同じリソースを同時に構築が出来ます。少しでも参考になれば幸いです。
参考
CloudFormation
- MediaStore
- MediaLive
- Input security group
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-medialive-inputsecuritygroup.html - Input
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-medialive-input.html - Channel
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-medialive-channel.html
- Input security group
- CloudFront