暗号化していない動画(.ts)は、ダウンロードして拡張子を.mpegとかにすれば細切れですが再生出来てしまいます。AESで暗号化すれば、そのままでは再生出来なくなります。
ただ、鍵(.key)で復号しながら再生しているので、ひと手間掛ければ再生できるように出来てしまいます。
コンテンツ保護はDRM使うのがベストですが、コストと再生できる環境が限られるので、要件や、コストとリスクで判断して、AESだけを選択する場合も多いです。
MediaConvertで暗号化(AES)する方法
残念ながら画面には項目がなく、選択するだけでは出来そうにありませんでした。
→ ジョブをインポートすれば出来ますが、鍵を毎回作成したいので、Lambdaを使います。
LambdaでJSONにパラメータを追加してジョブを作るのと、
対応する鍵(.key)をS3に保存してあげれば出来ます。
TODO: CMAFをAESで暗号化してみる
→ S3設置トリガーで自動変換と、MediaConvertでCMAFを暗号化(未解決)してみる
MediaConvertのジョブテンプレート作成
一般設定
ここで設定した名前をジョブ作成で使います。

入力

出力グループ

Apple HLS グループの設定

出力設定
名前修飾子
「_video」と入力。何でも良いけど設定しないと保存できない。
親と子のm3u8のファイル名が同じにならないようにとtsに入る。
Big Buck Bunny.m3u8 Big Buck Bunny_video.m3u8 Big Buck Bunny_video_00001.ts



Lambda関数
https://ap-northeast-1.console.aws.amazon.com/lambda/home?region=ap-northeast-1#/create/function
関数の作成


アクセス権限
鍵を作成するS3への書き込み権限(s3:Put)と、mediaconvert:CreateJob が必要になります。
前者は、MediaConvert_Default_Role_xxxxxxxx ←MediaConvertで変換して、ストリーミング配信を試してみる で作成
後者は、AWSElementalMediaConvertFullAccess を利用

IAM


コード
今回は元素材はベタに指定して、MediaConvertジョブ作成とkeyファイルをS3に保存して、MediaConvertのジョブIDを返却するようにしました。
TODO: S3設置トリガーで自動で変換したい
→ S3設置トリガーで自動変換と、MediaConvertでCMAFを暗号化(未解決)してみる
TODO: MediaInfoを実行して元素材の情報を残したい
→ EventBridgeでMediaConvertの進捗率を取得する
※Job State ChangeのINPUT_INFORMATIONである程度取れる。変換後のはCOMPLETEで取れる。
元素材が存在しなくてもエラーにならず、ジョブ作成は成功しちゃいました。
TODO: 進行状況を通知したい。完了か失敗か知りたい。
→ EventBridgeでMediaConvertの進捗率を取得する
TODO: Labmdaの例外やエラーを通知したい。

最新のコードこちら → https://dev.azure.com/nightonly/_git/lambda-origin?path=/createMediaConvertJob/lambda_function.py
import boto3
import os
import datetime
import secrets
import codecs
s3Client = boto3.client('s3')
OUTPUT_BUCKET = os.environ['OUTPUT_BUCKET']
KEY_BASE_URL = os.environ['KEY_BASE_URL'] ←相対パスに変更した為、削除
MEDIACONVERT_ENDPOINT_URL = os.environ['MEDIACONVERT_ENDPOINT_URL']
MEDIACONVERT_ROLE = os.environ['MEDIACONVERT_ROLE']
MEDIACONVERT_JOB_TEMPLATE = os.environ['MEDIACONVERT_JOB_TEMPLATE']
OUTPUT_SUFFIX_PATH = '_' + datetime.datetime.now().strftime('%Y%m%d%H%M%S')
def lambda_handler(event, context):
input_bucket = 's3://input-media-cdn.nightonly.com/' # 対象動画のバケット
input_file = 'Big Buck Bunny.mp4' # 対象動画のフォルダを含むファイル名
output_path = os.path.splitext(input_file)[0] + OUTPUT_SUFFIX_PATH + '/' ←パスに拡張子も入れる。拡張子違いを別物扱いにする為
output_path = input_file + OUTPUT_SUFFIX_PATH + '/'
key_file = os.path.splitext(os.path.basename(input_file))[0] + '.key'
print({ 'input_bucket': input_bucket, 'input_file': input_file, 'output_path': output_path, 'key_file': key_file })
key_value = secrets.token_hex(16)
settings = {
'Inputs': [
{
'FileInput': input_bucket + input_file
}
],
'OutputGroups': [
{
'OutputGroupSettings': {
'HlsGroupSettings': {
'Destination': 's3://' + OUTPUT_BUCKET + '/' + output_path,
'Encryption': {
'EncryptionMethod': 'AES128',
'StaticKeyProvider': {
'StaticKeyValue': key_value,
'Url': KEY_BASE_URL + output_path + key_file ←相対パスに変更
'Url': os.path.basename(output_path + key_file)
},
'Type': 'STATIC_KEY'
}
}
}
}
]
}
print(settings)
# MediaConvertジョブ作成
mediaconvertClient = boto3.client('mediaconvert', endpoint_url = MEDIACONVERT_ENDPOINT_URL)
result = mediaconvertClient.create_job(
Role = MEDIACONVERT_ROLE,
JobTemplate = MEDIACONVERT_JOB_TEMPLATE,
Settings = settings
)
print(result)
# keyファイル作成
print(s3Client.put_object(
Bucket = OUTPUT_BUCKET,
Key = output_path + key_file,
Body = codecs.decode(key_value, 'hex_codec')
))
return result['Job']['Id']
ClodFrontのキャッシュクリアをしたくないのと、再変換で尺が短くなると不要なtsが残る為、OUTPUT_SUFFIX_PATHに日時(UTC)を入れる事にしました。
再変換した場合は、完了後にm3u8のパスを切り替える想定。切り替えたら元のをS3から削除すると容量削減できますね。
settingsのJSONは、ジョブテンプレート(MEDIACONVERT_JOB_TEMPLATE)のにマージされるので、追加・変更箇所のみ記載すればOK。
内容は「ジョブテンプレートの詳細 → ジョブの JSON を表示」で確認できる。
TODO: 変換に失敗するとkeyファイルが残るので、失敗したら削除したい
→ EventBridgeでMediaConvertの進捗率を取得する
※完了時に保存するように変更
環境変数


OUTPUT_BUCKET: 変換後の動画や鍵を置くバケット
KEY_BASE_URL: 鍵ファイルのURL(CloudFrontでOUTPUT_BUCKETにアクセスできるURL)
↑相対パスに変更した為、設定不要。ドメインやパス変更できる。
MEDIACONVERT_ENDPOINT_URL: MediaConvert > アカウント のAPIエンドポイント(下記)
MEDIACONVERT_ROLE: MediaConvert_Default_Role_xxxxxxxx のポリシーARN(下記)
MEDIACONVERT_JOB_TEMPLATE: 上で作成したジョブテンプレートの名前
https://ap-northeast-1.console.aws.amazon.com/mediaconvert/home?region=ap-northeast-1#/account

https://us-east-1.console.aws.amazon.com/iamv2/home#/policies


テスト
デプロイして、テスト実行!
テンプレートはs3-putにしましたが、今回は何でも良さそう。
ResponseにジョブIDが表示されれはリクエストは成功。

確認
MediaConvert
ジョブが作られている!
しばらく待ってから更新すると、PROGRESSINGからCOMPLETEになる。
https://ap-northeast-1.console.aws.amazon.com/mediaconvert/home?region=ap-northeast-1#/jobs/list

S3
HLSのファイルとkeyファイルが作られている!
https://s3.console.aws.amazon.com/s3/buckets?region=ap-northeast-1


再生してみる
hls.js demo
https://hls-js.netlify.app/demo/
今回は下記(しばらく残しておきます)https://cdn.nightonly.com/Big%20Buck%20Bunny_HLS_AES/Big%20Buck%20Bunny.m3u8https://cdn.nightonly.com/Big%20Buck%20Bunny_20220419235559/Big%20Buck%20Bunny.m3u8


“MediaConvertでHLSをAESで暗号化してみる” に対して4件のコメントがあります。