暗号化していない動画(.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件のコメントがあります。