Goでサーバーレス動画変換

timakin
7 min readNov 6, 2017

概要

よくGoogle App Engineに関する記事を書くのですが、今回はAWSです。

APIサーバーでGoを使うことももちろんありますが、他にもgo-apexでLambdaファンクションを書く場面というのもあると思います。

以前go-apexのdeployについての記事を書いたので、それは下記を別途ご覧ください。

今回はElastic Transcoder(動画のエンコーダ)を例にサーバーレスにGoが役立つ実例を紹介します。

やりたいこと

  1. S3に動画をアップロードする
  2. アップロードの通知を元にlambdaが呼ばれる
  3. ElasticTranscoderを呼ぶ
  4. エンコード結果をS3に保存する

というフローです。今回扱うのは、3の部分です。1,2,4の部分は別途AWSの設定が必要で、個人的にはterraformでやるべきだと思っています。

go-apexでのエンコード処理

まずlambdaの中で真っ先に呼ばれるのは以下。

package main

import (
"log"

apex "github.com/apex/go-apex"
apexS3 "github.com/apex/go-apex/s3"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/elastictranscoder"
"github.com/kelseyhightower/envconfig"
"github.com/pkg/errors"
"github.com/timakin/sample-apex/awsext"
)

func main() {
var s awsext.Specification
err := envconfig.Process("", &s)
if err != nil {
log.Fatal(errors.Wrap(err, "[ERROR] Failed to process specification"))
}

apexS3.HandleFunc(func(event *apexS3.Event, ctx *apex.Context) error {
for _, record := range event.Records {
inputKey := record.S3.Object.Key
sess := session.New(&aws.Config{Region: aws.String(s.AWSRegion)})
svc := elastictranscoder.New(sess)
params := awsext.CreateJobInput(inputKey)
resp, err := svc.CreateJob(params)
if err != nil {
log.Fatal(errors.Wrap(err, "[ERROR] Failed to transcode the video"))
}
}
return nil
})
}

S3の通知イベントを受け取って、inputのKey(エンコード前の動画ファイルのkey)を取得します。

その後、ElasticTranscoderの変換Jobをcreateしている、という流れです。

その変換処理に当たるのが以下です。

package awsext

import (
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elastictranscoder"
"github.com/kelseyhightower/envconfig"
"github.com/pkg/errors"
)

type Specification struct {
PipelineId string `required:"true" envconfig:"PIPELINE_ID"`
PresetId string `required:"true" envconfig:"PRESET_ID"`
AWSRegion string `required:"true" envconfig:"AWS_REGION"`
}

func CreateJobInput(inputS3Key string) *elastictranscoder.CreateJobInput {
videoName := strings.Split(inputS3Key, ".")[0]

var s Specification
err := envconfig.Process("", &s)
if err != nil {
log.Fatal(errors.Wrap(err, "[ERROR] Failed to process specification"))
}

params := &elastictranscoder.CreateJobInput{
PipelineId: aws.String(s.PipelineId), // Required
OutputKeyPrefix: aws.String(videoName + "/"),
Input: &elastictranscoder.JobInput{
Key: aws.String(inputS3Key),
FrameRate: aws.String("auto"),
Resolution: aws.String("auto"),
AspectRatio: aws.String("auto"),
Interlaced: aws.String("auto"),
Container: aws.String("auto"),
},
Output: &elastictranscoder.CreateJobOutput{
Key: aws.String(videoName),
PresetId: aws.String(s.PresetId),
Rotate: aws.String("auto"),
SegmentDuration: aws.String("10"),
ThumbnailPattern: aws.String(videoName + "-{count}"),
},
}

return params
}

わざわざ切り出すほどでもないのと、フレームレートやアス比がautoになっててだいぶ適当なのですが、これで変換ができます。

aws-sdk-goの難点なのですが、ドキュメントが非常に少ないため、testコードを見ながら書きました。SDKのelastictranscoderパッケージを利用して、動画のエンコード前後の設定を渡して、それを元に変換処理を発火します。

まとめ

参考例が少ないElasticTranscoderのgo-apexでの呼び出し例を書いてみました。適切な設定を行えば、サーバーレスの動画変換処理を実現できます。ぜひ動画配信サービスなどを作られる際は、とっかかりに使ってみてください。

--

--