Yappli Tech Blog

株式会社ヤプリの開発メンバーによるブログです。最新の技術情報からチーム・働き方に関するテーマまで、日々の熱い想いを持って発信していきます。

AWS EventBridgeを使ってAWS MediaConvertを自動で実行する

こんにちは、サーバサイドエンジニアの中川です。
この記事を執筆している2022年9月はちょうどスプラトゥーン3が発売された時期ですね。自分は今作から本格的に遊んでいるのですがすぐやられてしまうので、塗っている時間よりも塗る場所に移動している時間が多いことが最近の悩みです。

さて、今回は業務の中で初めてAWSのMediaConvertを触り、色々と試行錯誤した部分があったので振り返りも含めて詰まった点をまとめていきます。
同じようなことで悩んでいる方の参考になれば幸いです。

やったこと

  1. S3に動画をアップロード
  2. S3へのアップロードをトリガーとして、EventBridgeが発火
  3. EventBridgeからGoで実装した自作APIを呼び出す
  4. 自作APIからMediaConvertのジョブ作成リクエストを送信
  5. MediaConvertのジョブ実行

S3へのアップロードをトリガーとしたEventBridgeの設定

S3へのアップロードをトリガーとして発火するEventBridgeの設定を行なっていきます。 AWSコンソール上でEventBridgeの設定画面へ行き、ルール名を設定します。 次にトリガーとなるイベントを指定します。今回はS3へのアップロードがトリガーなのでイベントソース、イベントパターンは下記のように指定します。
今回対象バケットは全てのバケットを指定していますが、特定のバケットに絞りたい場合はバケット名を適宜選択してください。

EventBridge設定内容1

イベントパターンの選択ができたらターゲットを選択します。 今回は自作APIを叩きたいのでターゲットタイプは「EventBridge API の宛先」を、API送信先名やエンドポイントはご自身で任意の名前とエンドポイントを設定してください。
接続項目は叩くAPIの認証方法に合わせて認証情報を入力してください。 認証情報は空で登録することはできない点に注意が必要です。空で登録しようとした場合最後の作成フェーズでエラーが返ってきます。
実行ロールはEventBridgeがAPIを実行するためのロールが必要です。ここは適宜権限を付与してください。よくわからない場合は「この特定のリソースについて新しいロールを作成」を選択するとAWSがよしなにやってくれます。

EventBridge設定内容2

ここまで設定すると、あとは画面上で選択していけばルールが作成できるはずです。

EventBridgeから呼ばれるMediaConvertのジョブ作成APIの実装

EventBridgeの設定ができたので、次は叩かれるAPIを実装します。 コードは下記です。例ではmain関数に全て記載しているので適宜ご自身の環境に合わせてください。

package main

import (
    "fmt"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/endpoints"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/mediaconvert"
)

func main() {
    mySession := session.Must(session.NewSession(&aws.Config{
        Region:   aws.String(endpoints.ApNortheast1RegionID), // リクエスト送信先のリージョン
        Endpoint: aws.String("実行環境に合わせたAPIエンドポイント"),          // 後述するMediaConvertのAPIエンドポイント
    }))

    svc := mediaconvert.New(mySession)

    res, err := svc.CreateJob(&mediaconvert.CreateJobInput{
        Role: aws.String("実行環境に合わせたIAMロール"), // 必須、MediaConvertが実行できるIAMロール
        Settings: &mediaconvert.JobSettings{ // ジョブの設定
            Inputs: []*mediaconvert.Input{ // 変換元動画ファイルの設定
                {
                    AudioSelectors: map[string]*mediaconvert.AudioSelector{ // 動画ファイルからオーディオを抽出する場合に必要な設定
                        "Audio Selector 1": {
                            DefaultSelection: aws.String("DEFAULT"), // ジョブのデフォルトの設定、指定しない場合出力に音声が含まれない
                        },
                    },
                    TimecodeSource: aws.String("ZEROBASED"), // 変換を動画のどこから始めるかを指定する。ZEROBASEDだと動画の最初から変換する
                    FileInput:      aws.String("入力ファイルのパス"), // 入力ファイルのパス、S3オブジェクトであればS3URLを指定する
                },
            },

            OutputGroups: []*mediaconvert.OutputGroup{ // 変換後動画ファイルの設定
                {
                    Name: aws.String("Apple HLS"), // 出力ファイルの変換形式
                    OutputGroupSettings: &mediaconvert.OutputGroupSettings{
                        HlsGroupSettings: &mediaconvert.HlsGroupSettings{ // HLS出力パッケージに関する設定
                            Destination:      aws.String("出力ファイルのパス"), // S3の出力場所と出力ファイル名のベースを指定するための設定
                            MinSegmentLength: aws.Int64(0),            // 通信時の最小セグメントサイズ
                            SegmentLength:    aws.Int64(10),           // セグメントサイズの長さ
                        },
                        Type: aws.String("HLS_GROUP_SETTINGS"), // 出力グループの種類(File group, Apple HLS, DASH ISO, Microsoft Smooth Streaming, CMAF)
                    },
                    Outputs: []*mediaconvert.Output{ // 出力ファイルをどのようにエンコードするかの設定
                        {
                            ContainerSettings: &mediaconvert.ContainerSettings{
                                Container:    aws.String("M3U8"),           // コンテナの設定
                                M3u8Settings: &mediaconvert.M3u8Settings{}, // HLS 出力の MPEG-2トランスポートストリーム (MPEG2-TS) コンテナに関する設定
                            },
                            VideoDescription: &mediaconvert.VideoDescription{ // 出力のビデオエンコードに関連する設定
                                CodecSettings: &mediaconvert.VideoCodecSettings{ // ビデオコーデックに関する設定
                                    Codec: aws.String("H_264"), // ビデオコーデックの設定、設定値はVideoCodecSettingsで定義されている値を指定する
                                    H264Settings: &mediaconvert.H264Settings{ // CodecをH_264に指定した際の必須設定
                                        MaxBitrate:        aws.Int64(5000000),                 // ビットレートの最大値
                                        RateControlMode:   aws.String("QVBR"),                 // ビットレートの種類
                                        SceneChangeDetect: aws.String("TRANSITION_DETECTION"), // 映像品質を向上させるためのシーンチェンジの設定
                                    },
                                },
                            },
                            AudioDescriptions: []*mediaconvert.AudioDescription{ // 動画ファイルからオーディオを抽出する場合に必要な設定
                                {
                                    CodecSettings: &mediaconvert.AudioCodecSettings{ // オーディオエンコードに関する設定
                                        Codec: aws.String("AAC"), // オーディオコーデックの設定、設定値はAudioCodecSettingsで定義されている値を指定する
                                        AacSettings: &mediaconvert.AacSettings{ // CodecをAACに指定した時の必須設定
                                            Bitrate:    aws.Int64(96000),              // ビットレート
                                            CodingMode: aws.String("CODING_MODE_2_0"), // 変換方式
                                            SampleRate: aws.Int64(48000),              // サンプリング周波数
                                        },
                                    },
                                },
                            },
                            NameModifier: aws.String("_split"), // 出力ファイル群に指定する識別用の名前
                        },
                    },
                },
            },
        },
    })
}

なかなか設定項目が多くて難しいと思います。私もリクエスト値が不正であるというエラーを修正するために項目を足したり引いたりしながら実行しました。 もしかしたら不要な項目もあるかもしれませんが、一旦私の環境で動いた設定は上記です。
コンソール上でジョブを作成するとジョブの内容をjsonで表示できるため、最初にそちらを参考にするのもいいかもしれません。

詰まったところ

aws.Config.Endpoint

Endpointの値は最初何を指定すればいいかわからず適当な値を指定していましたが、該当部でずっとエラーが出ていました。色々調べてみると、コンソール上のMediaConvertのアカウント内に記載されているURLを指定する必要があるとのことでした。自作のAPIから指定する場合はこちらの値をいれるようにしてください。

APIエンドポイント

mediaconvert.CreateJobInput.Role

こちらはMediaConvertの実行権限があるロールを指定する必要があります。私は最初ずっとAWS SDK for Goを実行するためのロールのことと勘違いしていました。こちらはご自身の環境に合わせて適宜作成してください。

まとめ

EventBridgeやMediaConvertの記事は調べていくつか見つかりましたが、それらを使ってEventBridge経由でGoのAPIを叩いてMediaConvertを実行している記事は見たことがなかったので記事にしてみました。 特にEventBridgeとの疎通確認とCreateJob()に渡す項目の多さに苦労しました。ただ、一度作成してしまえばジョブテンプレートに作成して使い回すことができますし、私は今までAPIの実行をLambdaなどで行なっていたのですが、EventBridge経由で実行できるとAPI実行用のLambdaが不要になるのでリソース管理が楽だと感じました。同じような点で悩んでいる人たちの参考になれば幸いです。

最後に

ヤプリでは一緒に働く仲間を募集しています!「興味をもった!」という方や、「もう少し具体的な話が聞いてみたい」と思った方はぜひカジュアル面談にお越しください。

参考

AWS Elemental MediaConvert
Amazon EventBridge
APIリファレンス