[小ネタ] CDK で MediaLive を作成するときにちょっと楽をする方法
こんにちは、大前です。
最近 CDK への入門がてら MediaLive を CDK で作っていたりするのですが、MediaLive はパラメータ数が膨大でなかなか大変です。
そこで、MediaLive のカスタムテンプレートのダウンロード機能を利用し、CDK で MediaLive を構築するためのソースコードをちょっと楽して作ってみました。今回は CDK を例に挙げていますが、CloudFormation などでも活用できるかと思います。
MediaLive のパラメータの多さに心挫ける
MediaLive を構成する要素は Input
、InputSecurityGroup
、Channel
の 3つですが、このうち Channel
のパラメータ数が膨大で、「MediaLive もいっちょ IaC しちゃいますか〜〜」とか思いながらドキュメントを覗くと心を打ち砕かれます。以下に CDK の公式ドキュメントに乗っている MediaLive Channel 作成のサンプルコードを載せておきます。開いてみるとこの気持ちが伝わると思います。
Example - class CfnChannel (construct)
// The code below shows an example of how to instantiate this type. // The values are placeholders you should change. import { aws_medialive as medialive } from 'aws-cdk-lib'; declare const tags: any; const cfnChannel = new medialive.CfnChannel(this, 'MyCfnChannel', /* all optional props */ { cdiInputSpecification: { resolution: 'resolution', }, channelClass: 'channelClass', destinations: [{ id: 'id', mediaPackageSettings: [{ channelId: 'channelId', }], multiplexSettings: { multiplexId: 'multiplexId', programName: 'programName', }, settings: [{ passwordParam: 'passwordParam', streamName: 'streamName', url: 'url', username: 'username', }], }], encoderSettings: { audioDescriptions: [{ audioNormalizationSettings: { algorithm: 'algorithm', algorithmControl: 'algorithmControl', targetLkfs: 123, }, audioSelectorName: 'audioSelectorName', audioType: 'audioType', audioTypeControl: 'audioTypeControl', audioWatermarkingSettings: { nielsenWatermarksSettings: { nielsenCbetSettings: { cbetCheckDigitString: 'cbetCheckDigitString', cbetStepaside: 'cbetStepaside', csid: 'csid', }, nielsenDistributionType: 'nielsenDistributionType', nielsenNaesIiNwSettings: { checkDigitString: 'checkDigitString', sid: 123, }, }, }, codecSettings: { aacSettings: { bitrate: 123, codingMode: 'codingMode', inputType: 'inputType', profile: 'profile', rateControlMode: 'rateControlMode', rawFormat: 'rawFormat', sampleRate: 123, spec: 'spec', vbrQuality: 'vbrQuality', }, ac3Settings: { bitrate: 123, bitstreamMode: 'bitstreamMode', codingMode: 'codingMode', dialnorm: 123, drcProfile: 'drcProfile', lfeFilter: 'lfeFilter', metadataControl: 'metadataControl', }, eac3Settings: { attenuationControl: 'attenuationControl', bitrate: 123, bitstreamMode: 'bitstreamMode', codingMode: 'codingMode', dcFilter: 'dcFilter', dialnorm: 123, drcLine: 'drcLine', drcRf: 'drcRf', lfeControl: 'lfeControl', lfeFilter: 'lfeFilter', loRoCenterMixLevel: 123, loRoSurroundMixLevel: 123, ltRtCenterMixLevel: 123, ltRtSurroundMixLevel: 123, metadataControl: 'metadataControl', passthroughControl: 'passthroughControl', phaseControl: 'phaseControl', stereoDownmix: 'stereoDownmix', surroundExMode: 'surroundExMode', surroundMode: 'surroundMode', }, mp2Settings: { bitrate: 123, codingMode: 'codingMode', sampleRate: 123, }, passThroughSettings: { }, wavSettings: { bitDepth: 123, codingMode: 'codingMode', sampleRate: 123, }, }, languageCode: 'languageCode', languageCodeControl: 'languageCodeControl', name: 'name', remixSettings: { channelMappings: [{ inputChannelLevels: [{ gain: 123, inputChannel: 123, }], outputChannel: 123, }], channelsIn: 123, channelsOut: 123, }, streamName: 'streamName', }], availBlanking: { availBlankingImage: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, state: 'state', }, availConfiguration: { availSettings: { scte35SpliceInsert: { adAvailOffset: 123, noRegionalBlackoutFlag: 'noRegionalBlackoutFlag', webDeliveryAllowedFlag: 'webDeliveryAllowedFlag', }, scte35TimeSignalApos: { adAvailOffset: 123, noRegionalBlackoutFlag: 'noRegionalBlackoutFlag', webDeliveryAllowedFlag: 'webDeliveryAllowedFlag', }, }, }, blackoutSlate: { blackoutSlateImage: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, networkEndBlackout: 'networkEndBlackout', networkEndBlackoutImage: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, networkId: 'networkId', state: 'state', }, captionDescriptions: [{ captionSelectorName: 'captionSelectorName', destinationSettings: { aribDestinationSettings: { }, burnInDestinationSettings: { alignment: 'alignment', backgroundColor: 'backgroundColor', backgroundOpacity: 123, font: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, fontColor: 'fontColor', fontOpacity: 123, fontResolution: 123, fontSize: 'fontSize', outlineColor: 'outlineColor', outlineSize: 123, shadowColor: 'shadowColor', shadowOpacity: 123, shadowXOffset: 123, shadowYOffset: 123, teletextGridControl: 'teletextGridControl', xPosition: 123, yPosition: 123, }, dvbSubDestinationSettings: { alignment: 'alignment', backgroundColor: 'backgroundColor', backgroundOpacity: 123, font: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, fontColor: 'fontColor', fontOpacity: 123, fontResolution: 123, fontSize: 'fontSize', outlineColor: 'outlineColor', outlineSize: 123, shadowColor: 'shadowColor', shadowOpacity: 123, shadowXOffset: 123, shadowYOffset: 123, teletextGridControl: 'teletextGridControl', xPosition: 123, yPosition: 123, }, ebuTtDDestinationSettings: { copyrightHolder: 'copyrightHolder', fillLineGap: 'fillLineGap', fontFamily: 'fontFamily', styleControl: 'styleControl', }, embeddedDestinationSettings: { }, embeddedPlusScte20DestinationSettings: { }, rtmpCaptionInfoDestinationSettings: { }, scte20PlusEmbeddedDestinationSettings: { }, scte27DestinationSettings: { }, smpteTtDestinationSettings: { }, teletextDestinationSettings: { }, ttmlDestinationSettings: { styleControl: 'styleControl', }, webvttDestinationSettings: { styleControl: 'styleControl', }, }, languageCode: 'languageCode', languageDescription: 'languageDescription', name: 'name', }], featureActivations: { inputPrepareScheduleActions: 'inputPrepareScheduleActions', }, globalConfiguration: { initialAudioGain: 123, inputEndAction: 'inputEndAction', inputLossBehavior: { blackFrameMsec: 123, inputLossImageColor: 'inputLossImageColor', inputLossImageSlate: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, inputLossImageType: 'inputLossImageType', repeatFrameMsec: 123, }, outputLockingMode: 'outputLockingMode', outputTimingSource: 'outputTimingSource', supportLowFramerateInputs: 'supportLowFramerateInputs', }, motionGraphicsConfiguration: { motionGraphicsInsertion: 'motionGraphicsInsertion', motionGraphicsSettings: { htmlMotionGraphicsSettings: { }, }, }, nielsenConfiguration: { distributorId: 'distributorId', nielsenPcmToId3Tagging: 'nielsenPcmToId3Tagging', }, outputGroups: [{ name: 'name', outputGroupSettings: { archiveGroupSettings: { archiveCdnSettings: { archiveS3Settings: { cannedAcl: 'cannedAcl', }, }, destination: { destinationRefId: 'destinationRefId', }, rolloverInterval: 123, }, frameCaptureGroupSettings: { destination: { destinationRefId: 'destinationRefId', }, frameCaptureCdnSettings: { frameCaptureS3Settings: { cannedAcl: 'cannedAcl', }, }, }, hlsGroupSettings: { adMarkers: ['adMarkers'], baseUrlContent: 'baseUrlContent', baseUrlContent1: 'baseUrlContent1', baseUrlManifest: 'baseUrlManifest', baseUrlManifest1: 'baseUrlManifest1', captionLanguageMappings: [{ captionChannel: 123, languageCode: 'languageCode', languageDescription: 'languageDescription', }], captionLanguageSetting: 'captionLanguageSetting', clientCache: 'clientCache', codecSpecification: 'codecSpecification', constantIv: 'constantIv', destination: { destinationRefId: 'destinationRefId', }, directoryStructure: 'directoryStructure', discontinuityTags: 'discontinuityTags', encryptionType: 'encryptionType', hlsCdnSettings: { hlsAkamaiSettings: { connectionRetryInterval: 123, filecacheDuration: 123, httpTransferMode: 'httpTransferMode', numRetries: 123, restartDelay: 123, salt: 'salt', token: 'token', }, hlsBasicPutSettings: { connectionRetryInterval: 123, filecacheDuration: 123, numRetries: 123, restartDelay: 123, }, hlsMediaStoreSettings: { connectionRetryInterval: 123, filecacheDuration: 123, mediaStoreStorageClass: 'mediaStoreStorageClass', numRetries: 123, restartDelay: 123, }, hlsS3Settings: { cannedAcl: 'cannedAcl', }, hlsWebdavSettings: { connectionRetryInterval: 123, filecacheDuration: 123, httpTransferMode: 'httpTransferMode', numRetries: 123, restartDelay: 123, }, }, hlsId3SegmentTagging: 'hlsId3SegmentTagging', iFrameOnlyPlaylists: 'iFrameOnlyPlaylists', incompleteSegmentBehavior: 'incompleteSegmentBehavior', indexNSegments: 123, inputLossAction: 'inputLossAction', ivInManifest: 'ivInManifest', ivSource: 'ivSource', keepSegments: 123, keyFormat: 'keyFormat', keyFormatVersions: 'keyFormatVersions', keyProviderSettings: { staticKeySettings: { keyProviderServer: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, staticKeyValue: 'staticKeyValue', }, }, manifestCompression: 'manifestCompression', manifestDurationFormat: 'manifestDurationFormat', minSegmentLength: 123, mode: 'mode', outputSelection: 'outputSelection', programDateTime: 'programDateTime', programDateTimeClock: 'programDateTimeClock', programDateTimePeriod: 123, redundantManifest: 'redundantManifest', segmentationMode: 'segmentationMode', segmentLength: 123, segmentsPerSubdirectory: 123, streamInfResolution: 'streamInfResolution', timedMetadataId3Frame: 'timedMetadataId3Frame', timedMetadataId3Period: 123, timestampDeltaMilliseconds: 123, tsFileMode: 'tsFileMode', }, mediaPackageGroupSettings: { destination: { destinationRefId: 'destinationRefId', }, }, msSmoothGroupSettings: { acquisitionPointId: 'acquisitionPointId', audioOnlyTimecodeControl: 'audioOnlyTimecodeControl', certificateMode: 'certificateMode', connectionRetryInterval: 123, destination: { destinationRefId: 'destinationRefId', }, eventId: 'eventId', eventIdMode: 'eventIdMode', eventStopBehavior: 'eventStopBehavior', filecacheDuration: 123, fragmentLength: 123, inputLossAction: 'inputLossAction', numRetries: 123, restartDelay: 123, segmentationMode: 'segmentationMode', sendDelayMs: 123, sparseTrackType: 'sparseTrackType', streamManifestBehavior: 'streamManifestBehavior', timestampOffset: 'timestampOffset', timestampOffsetMode: 'timestampOffsetMode', }, multiplexGroupSettings: { }, rtmpGroupSettings: { adMarkers: ['adMarkers'], authenticationScheme: 'authenticationScheme', cacheFullBehavior: 'cacheFullBehavior', cacheLength: 123, captionData: 'captionData', inputLossAction: 'inputLossAction', restartDelay: 123, }, udpGroupSettings: { inputLossAction: 'inputLossAction', timedMetadataId3Frame: 'timedMetadataId3Frame', timedMetadataId3Period: 123, }, }, outputs: [{ audioDescriptionNames: ['audioDescriptionNames'], captionDescriptionNames: ['captionDescriptionNames'], outputName: 'outputName', outputSettings: { archiveOutputSettings: { containerSettings: { m2TsSettings: { absentInputAudioBehavior: 'absentInputAudioBehavior', arib: 'arib', aribCaptionsPid: 'aribCaptionsPid', aribCaptionsPidControl: 'aribCaptionsPidControl', audioBufferModel: 'audioBufferModel', audioFramesPerPes: 123, audioPids: 'audioPids', audioStreamType: 'audioStreamType', bitrate: 123, bufferModel: 'bufferModel', ccDescriptor: 'ccDescriptor', dvbNitSettings: { networkId: 123, networkName: 'networkName', repInterval: 123, }, dvbSdtSettings: { outputSdt: 'outputSdt', repInterval: 123, serviceName: 'serviceName', serviceProviderName: 'serviceProviderName', }, dvbSubPids: 'dvbSubPids', dvbTdtSettings: { repInterval: 123, }, dvbTeletextPid: 'dvbTeletextPid', ebif: 'ebif', ebpAudioInterval: 'ebpAudioInterval', ebpLookaheadMs: 123, ebpPlacement: 'ebpPlacement', ecmPid: 'ecmPid', esRateInPes: 'esRateInPes', etvPlatformPid: 'etvPlatformPid', etvSignalPid: 'etvSignalPid', fragmentTime: 123, klv: 'klv', klvDataPids: 'klvDataPids', nielsenId3Behavior: 'nielsenId3Behavior', nullPacketBitrate: 123, patInterval: 123, pcrControl: 'pcrControl', pcrPeriod: 123, pcrPid: 'pcrPid', pmtInterval: 123, pmtPid: 'pmtPid', programNum: 123, rateMode: 'rateMode', scte27Pids: 'scte27Pids', scte35Control: 'scte35Control', scte35Pid: 'scte35Pid', segmentationMarkers: 'segmentationMarkers', segmentationStyle: 'segmentationStyle', segmentationTime: 123, timedMetadataBehavior: 'timedMetadataBehavior', timedMetadataPid: 'timedMetadataPid', transportStreamId: 123, videoPid: 'videoPid', }, rawSettings: { }, }, extension: 'extension', nameModifier: 'nameModifier', }, frameCaptureOutputSettings: { nameModifier: 'nameModifier', }, hlsOutputSettings: { h265PackagingType: 'h265PackagingType', hlsSettings: { audioOnlyHlsSettings: { audioGroupId: 'audioGroupId', audioOnlyImage: { passwordParam: 'passwordParam', uri: 'uri', username: 'username', }, audioTrackType: 'audioTrackType', segmentType: 'segmentType', }, fmp4HlsSettings: { audioRenditionSets: 'audioRenditionSets', nielsenId3Behavior: 'nielsenId3Behavior', timedMetadataBehavior: 'timedMetadataBehavior', }, frameCaptureHlsSettings: { }, standardHlsSettings: { audioRenditionSets: 'audioRenditionSets', m3U8Settings: { audioFramesPerPes: 123, audioPids: 'audioPids', ecmPid: 'ecmPid', nielsenId3Behavior: 'nielsenId3Behavior', patInterval: 123, pcrControl: 'pcrControl', pcrPeriod: 123, pcrPid: 'pcrPid', pmtInterval: 123, pmtPid: 'pmtPid', programNum: 123, scte35Behavior: 'scte35Behavior', scte35Pid: 'scte35Pid', timedMetadataBehavior: 'timedMetadataBehavior', timedMetadataPid: 'timedMetadataPid', transportStreamId: 123, videoPid: 'videoPid', }, }, }, nameModifier: 'nameModifier', segmentModifier: 'segmentModifier', }, mediaPackageOutputSettings: { }, msSmoothOutputSettings: { h265PackagingType: 'h265PackagingType', nameModifier: 'nameModifier', }, multiplexOutputSettings: { destination: { destinationRefId: 'destinationRefId', }, }, rtmpOutputSettings: { certificateMode: 'certificateMode', connectionRetryInterval: 123, destination: { destinationRefId: 'destinationRefId', }, numRetries: 123, }, udpOutputSettings: { bufferMsec: 123, containerSettings: { m2TsSettings: { absentInputAudioBehavior: 'absentInputAudioBehavior', arib: 'arib', aribCaptionsPid: 'aribCaptionsPid', aribCaptionsPidControl: 'aribCaptionsPidControl', audioBufferModel: 'audioBufferModel', audioFramesPerPes: 123, audioPids: 'audioPids', audioStreamType: 'audioStreamType', bitrate: 123, bufferModel: 'bufferModel', ccDescriptor: 'ccDescriptor', dvbNitSettings: { networkId: 123, networkName: 'networkName', repInterval: 123, }, dvbSdtSettings: { outputSdt: 'outputSdt', repInterval: 123, serviceName: 'serviceName', serviceProviderName: 'serviceProviderName', }, dvbSubPids: 'dvbSubPids', dvbTdtSettings: { repInterval: 123, }, dvbTeletextPid: 'dvbTeletextPid', ebif: 'ebif', ebpAudioInterval: 'ebpAudioInterval', ebpLookaheadMs: 123, ebpPlacement: 'ebpPlacement', ecmPid: 'ecmPid', esRateInPes: 'esRateInPes', etvPlatformPid: 'etvPlatformPid', etvSignalPid: 'etvSignalPid', fragmentTime: 123, klv: 'klv', klvDataPids: 'klvDataPids', nielsenId3Behavior: 'nielsenId3Behavior', nullPacketBitrate: 123, patInterval: 123, pcrControl: 'pcrControl', pcrPeriod: 123, pcrPid: 'pcrPid', pmtInterval: 123, pmtPid: 'pmtPid', programNum: 123, rateMode: 'rateMode', scte27Pids: 'scte27Pids', scte35Control: 'scte35Control', scte35Pid: 'scte35Pid', segmentationMarkers: 'segmentationMarkers', segmentationStyle: 'segmentationStyle', segmentationTime: 123, timedMetadataBehavior: 'timedMetadataBehavior', timedMetadataPid: 'timedMetadataPid', transportStreamId: 123, videoPid: 'videoPid', }, }, destination: { destinationRefId: 'destinationRefId', }, fecOutputSettings: { columnDepth: 123, includeFec: 'includeFec', rowLength: 123, }, }, }, videoDescriptionName: 'videoDescriptionName', }], }], timecodeConfig: { source: 'source', syncThreshold: 123, }, videoDescriptions: [{ codecSettings: { frameCaptureSettings: { captureInterval: 123, captureIntervalUnits: 'captureIntervalUnits', }, h264Settings: { adaptiveQuantization: 'adaptiveQuantization', afdSignaling: 'afdSignaling', bitrate: 123, bufFillPct: 123, bufSize: 123, colorMetadata: 'colorMetadata', colorSpaceSettings: { colorSpacePassthroughSettings: { }, rec601Settings: { }, rec709Settings: { }, }, entropyEncoding: 'entropyEncoding', filterSettings: { temporalFilterSettings: { postFilterSharpening: 'postFilterSharpening', strength: 'strength', }, }, fixedAfd: 'fixedAfd', flickerAq: 'flickerAq', forceFieldPictures: 'forceFieldPictures', framerateControl: 'framerateControl', framerateDenominator: 123, framerateNumerator: 123, gopBReference: 'gopBReference', gopClosedCadence: 123, gopNumBFrames: 123, gopSize: 123, gopSizeUnits: 'gopSizeUnits', level: 'level', lookAheadRateControl: 'lookAheadRateControl', maxBitrate: 123, minIInterval: 123, numRefFrames: 123, parControl: 'parControl', parDenominator: 123, parNumerator: 123, profile: 'profile', qualityLevel: 'qualityLevel', qvbrQualityLevel: 123, rateControlMode: 'rateControlMode', scanType: 'scanType', sceneChangeDetect: 'sceneChangeDetect', slices: 123, softness: 123, spatialAq: 'spatialAq', subgopLength: 'subgopLength', syntax: 'syntax', temporalAq: 'temporalAq', timecodeInsertion: 'timecodeInsertion', }, h265Settings: { adaptiveQuantization: 'adaptiveQuantization', afdSignaling: 'afdSignaling', alternativeTransferFunction: 'alternativeTransferFunction', bitrate: 123, bufSize: 123, colorMetadata: 'colorMetadata', colorSpaceSettings: { colorSpacePassthroughSettings: { }, hdr10Settings: { maxCll: 123, maxFall: 123, }, rec601Settings: { }, rec709Settings: { }, }, filterSettings: { temporalFilterSettings: { postFilterSharpening: 'postFilterSharpening', strength: 'strength', }, }, fixedAfd: 'fixedAfd', flickerAq: 'flickerAq', framerateDenominator: 123, framerateNumerator: 123, gopClosedCadence: 123, gopSize: 123, gopSizeUnits: 'gopSizeUnits', level: 'level', lookAheadRateControl: 'lookAheadRateControl', maxBitrate: 123, minIInterval: 123, parDenominator: 123, parNumerator: 123, profile: 'profile', qvbrQualityLevel: 123, rateControlMode: 'rateControlMode', scanType: 'scanType', sceneChangeDetect: 'sceneChangeDetect', slices: 123, tier: 'tier', timecodeInsertion: 'timecodeInsertion', }, mpeg2Settings: { adaptiveQuantization: 'adaptiveQuantization', afdSignaling: 'afdSignaling', colorMetadata: 'colorMetadata', colorSpace: 'colorSpace', displayAspectRatio: 'displayAspectRatio', filterSettings: { temporalFilterSettings: { postFilterSharpening: 'postFilterSharpening', strength: 'strength', }, }, fixedAfd: 'fixedAfd', framerateDenominator: 123, framerateNumerator: 123, gopClosedCadence: 123, gopNumBFrames: 123, gopSize: 123, gopSizeUnits: 'gopSizeUnits', scanType: 'scanType', subgopLength: 'subgopLength', timecodeInsertion: 'timecodeInsertion', }, }, height: 123, name: 'name', respondToAfd: 'respondToAfd', scalingBehavior: 'scalingBehavior', sharpness: 123, width: 123, }], }, inputAttachments: [{ automaticInputFailoverSettings: { errorClearTimeMsec: 123, failoverConditions: [{ failoverConditionSettings: { audioSilenceSettings: { audioSelectorName: 'audioSelectorName', audioSilenceThresholdMsec: 123, }, inputLossSettings: { inputLossThresholdMsec: 123, }, videoBlackSettings: { blackDetectThreshold: 123, videoBlackThresholdMsec: 123, }, }, }], inputPreference: 'inputPreference', secondaryInputId: 'secondaryInputId', }, inputAttachmentName: 'inputAttachmentName', inputId: 'inputId', inputSettings: { audioSelectors: [{ name: 'name', selectorSettings: { audioHlsRenditionSelection: { groupId: 'groupId', name: 'name', }, audioLanguageSelection: { languageCode: 'languageCode', languageSelectionPolicy: 'languageSelectionPolicy', }, audioPidSelection: { pid: 123, }, audioTrackSelection: { tracks: [{ track: 123, }], }, }, }], captionSelectors: [{ languageCode: 'languageCode', name: 'name', selectorSettings: { ancillarySourceSettings: { sourceAncillaryChannelNumber: 123, }, aribSourceSettings: { }, dvbSubSourceSettings: { ocrLanguage: 'ocrLanguage', pid: 123, }, embeddedSourceSettings: { convert608To708: 'convert608To708', scte20Detection: 'scte20Detection', source608ChannelNumber: 123, source608TrackNumber: 123, }, scte20SourceSettings: { convert608To708: 'convert608To708', source608ChannelNumber: 123, }, scte27SourceSettings: { ocrLanguage: 'ocrLanguage', pid: 123, }, teletextSourceSettings: { outputRectangle: { height: 123, leftOffset: 123, topOffset: 123, width: 123, }, pageNumber: 'pageNumber', }, }, }], deblockFilter: 'deblockFilter', denoiseFilter: 'denoiseFilter', filterStrength: 123, inputFilter: 'inputFilter', networkInputSettings: { hlsInputSettings: { bandwidth: 123, bufferSegments: 123, retries: 123, retryInterval: 123, scte35Source: 'scte35Source', }, serverValidation: 'serverValidation', }, scte35Pid: 123, smpte2038DataPreference: 'smpte2038DataPreference', sourceEndBehavior: 'sourceEndBehavior', videoSelector: { colorSpace: 'colorSpace', colorSpaceSettings: { hdr10Settings: { maxCll: 123, maxFall: 123, }, }, colorSpaceUsage: 'colorSpaceUsage', selectorSettings: { videoSelectorPid: { pid: 123, }, videoSelectorProgramId: { programId: 123, }, }, }, }, }], inputSpecification: { codec: 'codec', maximumBitrate: 'maximumBitrate', resolution: 'resolution', }, logLevel: 'logLevel', name: 'name', roleArn: 'roleArn', tags: tags, vpc: { publicAddressAllocationIds: ['publicAddressAllocationIds'], securityGroupIds: ['securityGroupIds'], subnetIds: ['subnetIds'], }, });
MediaLive Channel のパラメータを楽して埋めたい
膨大なパラメータをひとつひとつ調べて埋めて、リソース作成にトライして、失敗して、、、を繰り返していたらいくら時間があっても足りませんのでちょっと楽をして MediaLive Channel のパラメータを埋めてみます。
MediaLive には カスタムテンプレート という機能があり、これを利用することで、作成されている MediaLive Channel のパラメータをダウンロードすることができます。今回はこれを使って、MediaLive Channel を生成するソースコードを効率的に作成していきます。
やってみた
今回は以下の流れで進めます。
- MediaLive Input、MediaLive InputSecurityGroup を CDK で作成
- MediaLive Channel をコンソール上で作成
- 作成した MediaLive Channel のカスタムテンプレートをダウンロード
- MediaLive Channel を作成するための CDK ソースを作成
- CDK で MediaLive をデプロイ
1. MediaLive Input、MediaLive InputSecurityGroup を CDK で作成
まず、MediaLive の Input
と InputSecurityGroup
を CDK で作成します。次の手順で MediaLive Channel を作成するために、この 2つのリソースが必要です。
各種ドキュメントを参考に、RTMP PUSH を受け取るための Input を作成する以下のソースコードを作成しました。今回は同一ファイルに全てのリソースを含めていますが、必要に応じてファイル分割などを行ってください。
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as medialive from 'aws-cdk-lib/aws-medialive'; export class MediaworkloadStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // MediaLive Input SecurityGroup const cfnInputSecurityGroup = new medialive.CfnInputSecurityGroup(this, 'MediaLiveInputSecurityGroup', { tags: { Name: 'MediaWL-SG' }, whitelistRules: [ { cidr: '10.0.0.0/16' } ], }); // MediaLive Input const cfnInput = new medialive.CfnInput(this, 'MediaLiveInput', { destinations: [ { streamName: 'mediawl/stream-a', }, { streamName: 'mediawl/stream-b', } ], inputSecurityGroups: [ cfnInputSecurityGroup.ref ], name: 'MediaWL-Input', tags: { Name: 'MediaWL-Input' }, type: 'RTMP_PUSH', }) } }
この状態でデプロイを行います。
cdk deploy
下記画像の様に、MediaLive の Input と、Input Security Group が作成されていれば OK です。
2. MediaLive Channel をコンソール上で作成
続いて、コンソール上で MediaLive Channel を作成します。
MediaLive →「チャネルの作成」で下記の様な画面が開きますので、任意のチャネル名を入力します。
チャネル名を入力した後、そのまま少し下にスクロールすると「チャネルテンプレート」という設定項目があります。ここから Live event HLS
を選択します。選択後、「出力グループ」にいくつか設定が追加されるかと思います。
続いて、「入力アタッチメント」の横にある「追加」をクリックし、「入力」にて先ほど作成した Media Live Input リソースを選択し、「確認」をクリック。
最後に、「出力グループ」内の一番上にある文字列(今回は "1.HD(HLS)")をクリックし、「HLS グループ送信先」という項目をそれぞれ埋めます。本来は出力先のサービス等を示す URL を指定する必要がありますが、今回は検証目的であることと、後から変更も可能であることもあり適当な値を入れています。
一通り設定したら、画面下の「チャネルの作成」をクリックします。エラーなくチャネルが作成されたら、OK です。
3. 作成した MediaLive Channel のカスタムテンプレートをダウンロード
MediaLive Channel が作成されたら、作成された Channel の詳細画面を開き、右上の「アクション」→ 「カスタムテンプレートのダウンロード」をクリックします。
ダウンロードされた JSON ファイルの中身を確認すると、以下の様な構成になっていることがわかります。MediaLive Channel の CDK ドキュメント と見比べると、使いまわせそうなパラメータが沢山ありそうなことがわかるかと思います。
{ "name": "HTTP live streaming - clone", "id": "1234567", "arn": "arn:aws:medialive:ap-northeast-1:111122223333:channel:1234567", "inputAttachments": [(省略)], "state": "IDLE", "pipelinesRunningCount": 0, "destinations": [(省略)], "egressEndpoints": [(省略)], "encoderSettings": {(省略)}, "roleArn": "", "inputSpecification": {(省略)}, "logLevel": "DISABLED", "tags": {}, "channelClass": "STANDARD", "pipelineDetails": [], "maintenanceWindow": "FRIDAY_0400", "maintenanceStatus": "", "maintenance": {(省略)} }
CDK のパラメータとして使える様に、上記 JSON に対して幾つかの処理をします。m3u8Settings
だけ、カスタムテンプレート内の表現が CDK 側で定義されている値とずれていたため、変換をかけています。
cat <ダウンロードしたJSONファイル> | sed -E "s/\"([a-zA-Z0-1]*)\":/\1:/g" > tmp.json cat tmp.json | sed -E "s/\"/\'/g" > tmp.json cat tmp.json | sed -E "s/m3u8Settings/m3U8Settings/g" > output.json
上記コマンドを実行すると、下記の様に CDK のソースコードにパラメータとしてそのまま使える形式になります。
{ name: 'HTTP live streaming - clone', id: '1234567', arn: 'arn:aws:medialive:ap-northeast-1:111122223333:channel:1234567', inputAttachments: [(省略)], state: 'IDLE', pipelinesRunningCount: 0, destinations: [(省略)], egressEndpoints: [(省略)], encoderSettings: {(省略)}, roleArn: '', inputSpecification: {(省略)}, logLevel: 'DISABLED', tags: {}, channelClass: 'STANDARD', pipelineDetails: [], maintenanceWindow: 'FRIDAY_0400', maintenanceStatus: '', maintenance: {(省略)} }
4. MediaLive Channel を作成するための CDK ソースを作成
上記で取得したパラメータ一覧を CDK の CfnChannel パラメータに当てはめたものが下記のソースコードです。(長いので折りたたんでいます)
以下パラメータについて、上記で取得した値をそのままコピペで使っています。
- channelClass
- destinations
- encoderSettings
- inputSpecification
- logLevel
- name
- tags
- roleArn
一方で、ダウンロードしたカスタムテンプレートには入力(inputAttachments)に関する情報は含まれない形になるため、以下の記述だけ追加しています。
inputAttachments: [{ inputAttachmentName: 'MediaWL-Input', inputId: cfnInput.ref, }]
作成したスタックファイルはこちら
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as medialive from 'aws-cdk-lib/aws-medialive'; export class MediaworkloadStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // MediaLive Input SecurityGroup const cfnInputSecurityGroup = new medialive.CfnInputSecurityGroup(this, 'MediaLiveInputSecurityGroup', { tags: { Name: 'MediaWL-SG' }, whitelistRules: [ { cidr: '10.0.0.0/16' } ], }); // MediaLive Input const cfnInput = new medialive.CfnInput(this, 'MediaLiveInput', { destinations: [ { streamName: 'mediawl/stream-a', }, { streamName: 'mediawl/stream-b', } ], inputSecurityGroups: [ cfnInputSecurityGroup.ref ], name: 'MediaWL-Input', tags: { Name: 'MediaWL-Input' }, type: 'RTMP_PUSH', }) // MediaLive Channel const cfnChannel = new medialive.CfnChannel(this, 'MediaLiveChannel', { channelClass: 'STANDARD', destinations: [ { id: 'destination1', settings: [ { url: 'http://example.com/main' }, { url: 'http://example.com/sby' } ], mediaPackageSettings: [] } ], encoderSettings: { audioDescriptions: [ { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 64000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_1_aac64' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 64000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_2_aac64' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 64000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_3_aac64' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 96000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_1_aac96' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 96000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_2_aac96' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 96000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_3_aac96' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 128000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_1_aac128' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 128000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_2_aac128' }, { audioSelectorName: 'default', codecSettings: { aacSettings: { bitrate: 128000, rawFormat: 'NONE', spec: 'MPEG4' } }, audioTypeControl: 'FOLLOW_INPUT', languageCodeControl: 'FOLLOW_INPUT', name: 'audio_3_aac128' } ], outputGroups: [ { outputGroupSettings: { hlsGroupSettings: { incompleteSegmentBehavior: 'AUTO', discontinuityTags: 'INSERT', adMarkers: [], captionLanguageSetting: 'OMIT', captionLanguageMappings: [], hlsCdnSettings: { hlsBasicPutSettings: { numRetries: 5, connectionRetryInterval: 30, restartDelay: 5, filecacheDuration: 300 } }, inputLossAction: 'EMIT_OUTPUT', manifestCompression: 'NONE', destination: { destinationRefId: 'destination1' }, ivInManifest: 'INCLUDE', ivSource: 'FOLLOWS_SEGMENT_NUMBER', clientCache: 'ENABLED', tsFileMode: 'SEGMENTED_FILES', manifestDurationFormat: 'FLOATING_POINT', segmentationMode: 'USE_SEGMENT_DURATION', redundantManifest: 'DISABLED', outputSelection: 'MANIFESTS_AND_SEGMENTS', streamInfResolution: 'INCLUDE', iFrameOnlyPlaylists: 'DISABLED', indexNSegments: 10, programDateTime: 'INCLUDE', programDateTimePeriod: 600, keepSegments: 21, segmentLength: 6, timedMetadataId3Frame: 'PRIV', timedMetadataId3Period: 10, hlsId3SegmentTagging: 'DISABLED', codecSpecification: 'RFC_4281', directoryStructure: 'SINGLE_DIRECTORY', segmentsPerSubdirectory: 10000, mode: 'LIVE', programDateTimeClock: 'INITIALIZE_FROM_OUTPUT_TIMECODE' } }, name: 'TN2224', outputs: [ { outputSettings: { hlsOutputSettings: { nameModifier: '_960x540_2000k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_960_540', audioDescriptionNames: [ 'audio_2_aac96' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_1280x720_3300k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_1280_720_1', audioDescriptionNames: [ 'audio_3_aac96' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_1280x720_5000k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_1280_720_2', audioDescriptionNames: [ 'audio_1_aac128' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_1280x720_6500k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_1280_720_3', audioDescriptionNames: [ 'audio_2_aac128' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_1920x1080_8000k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_1920_1080', audioDescriptionNames: [ 'audio_3_aac128' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_416x234_200k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_416_234', audioDescriptionNames: [ 'audio_1_aac64' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_480x270_400k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_480_270', audioDescriptionNames: [ 'audio_2_aac64' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_640x360_800k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_640_360', audioDescriptionNames: [ 'audio_3_aac64' ], captionDescriptionNames: [] }, { outputSettings: { hlsOutputSettings: { nameModifier: '_768x432_1200k', hlsSettings: { standardHlsSettings: { m3U8Settings: { audioPids: '492-498', ecmPid: '8182', pcrControl: 'PCR_EVERY_PES_PACKET', pmtPid: '480', scte35Pid: '500', scte35Behavior: 'NO_PASSTHROUGH', timedMetadataPid: '502', timedMetadataBehavior: 'NO_PASSTHROUGH', videoPid: '481' }, audioRenditionSets: 'program_audio' } } } }, videoDescriptionName: 'video_768_432', audioDescriptionNames: [ 'audio_1_aac96' ], captionDescriptionNames: [] } ] } ], timecodeConfig: { source: 'SYSTEMCLOCK' }, videoDescriptions: [ { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 200000, entropyEncoding: 'CAVLC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 15000, framerateDenominator: 1001, gopBReference: 'DISABLED', gopNumBFrames: 0, gopSize: 30, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_3', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'BASELINE', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 236, name: 'video_416_234', scalingBehavior: 'DEFAULT', width: 416 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 400000, entropyEncoding: 'CAVLC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 15000, framerateDenominator: 1001, gopBReference: 'DISABLED', gopNumBFrames: 0, gopSize: 30, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_3', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'BASELINE', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 272, name: 'video_480_270', scalingBehavior: 'DEFAULT', width: 480 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 800000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'ENABLED', gopNumBFrames: 3, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_3', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'MAIN', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 360, name: 'video_640_360', scalingBehavior: 'DEFAULT', width: 640 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 1200000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'ENABLED', gopNumBFrames: 3, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_4_1', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'MAIN', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 432, name: 'video_768_432', scalingBehavior: 'DEFAULT', width: 768 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 2200000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'ENABLED', gopNumBFrames: 3, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_4_1', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'HIGH', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 540, name: 'video_960_540', scalingBehavior: 'DEFAULT', width: 960 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 3300000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'ENABLED', gopNumBFrames: 3, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_4_1', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'HIGH', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 720, name: 'video_1280_720_1', scalingBehavior: 'DEFAULT', width: 1280 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 4700000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'ENABLED', gopNumBFrames: 3, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_4_1', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'HIGH', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 720, name: 'video_1280_720_2', scalingBehavior: 'DEFAULT', width: 1280 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 6200000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'ENABLED', gopNumBFrames: 3, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_4_1', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'HIGH', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 720, name: 'video_1280_720_3', scalingBehavior: 'DEFAULT', width: 1280 }, { codecSettings: { h264Settings: { colorMetadata: 'INSERT', adaptiveQuantization: 'HIGH', bitrate: 8000000, entropyEncoding: 'CABAC', flickerAq: 'ENABLED', framerateControl: 'SPECIFIED', framerateNumerator: 30000, framerateDenominator: 1001, gopBReference: 'DISABLED', gopNumBFrames: 1, gopSize: 60, gopSizeUnits: 'FRAMES', level: 'H264_LEVEL_4_1', lookAheadRateControl: 'HIGH', parControl: 'INITIALIZE_FROM_SOURCE', profile: 'HIGH', rateControlMode: 'CBR', syntax: 'DEFAULT', sceneChangeDetect: 'ENABLED', spatialAq: 'ENABLED', temporalAq: 'ENABLED' } }, height: 1080, name: 'video_1920_1080', scalingBehavior: 'DEFAULT', width: 1920 } ] }, inputAttachments: [{ inputAttachmentName: 'MediaWL-Input', inputId: cfnInput.ref, }], inputSpecification: { codec: 'AVC', resolution: 'HD', maximumBitrate: 'MAX_20_MBPS' }, logLevel: 'DISABLED', name: 'HTTP live streaming - clone', roleArn: '', tags: {}, }); } }
5. CDK で MediaLive をデプロイ
最後に、作成したソースコードで MediaLive がデプロイできるか確認します。
先に、先ほど作成した MediaLive Channel は削除しておきましょう。
CDK で作成したリソースも削除します。
cdk destroy
リソースの削除が完了したら、デプロイをかけます。
cdk deploy
無事にリソースが作成できれば OK です。カスタムテンプレートをダウンロードすることで、パラメータをうまく流用することができました。
おわりに
パラメータの多い MediaLive Channel を IaC(今回は CDK)で管理しようとした際に、一つずつパラメータを調べていくのは大変です。今回紹介したカスタムテンプレートのダウンロード機能を利用すれば、コンソールで作成した MediaLive Channel の設定をそのまま持って来れます。
また、一度 MediaLive Channel を作成できる状態になってしまえば、細かいパラメータの調整やファイルの分割などは如何様にもできると思います。
MediaLive の IaC 管理でお困りの方のお役に立てれば幸いです。
以上、AWS 事業本部の大前でした。