LoginSignup
8
4

More than 5 years have passed since last update.

Lambda(Go)でffmpegの出力をS3にアップロード

Last updated at Posted at 2019-02-02

AWS Lambda で Golang がサポートされて早1年*
未だ Go で作った Lambda関数 で ffmpeg を動かしてみたという記事が見当たらなかったので書きました。

今回は ffmpeg で生成した動画サムネイルを S3 にアップロードするサンプルコードを紹介します。

サンプルコード

ディレクトリ構成

作業ディレクトリの構成は以下の通りです。

作業ディレクトリのツリーマップ
.
├── ffmpeg
├── credentials.json
└── main.go

ffmpeg

ffmpeg は以下の公式サイトより取得できます。
https://www.ffmpeg.org

Lambda の OS は Amazon Linux なので、DLページでは Linux のパッケージを入手します。
今回は Lambda 内でローカルに呼び出すので、Linux Static Builds から適当なパッケージを選びます。
(DLしたパッケージファイルを展開すると色々ファイルが入っていますが、今回利用するのはffmpegのみです)

credentials.json

今回は Lambda や S3 の認証情報を外部ファイルにまとめました。

credentials.json
{
    "accessKeyId": "Your Access Key",
    "secretAccessKey": "Your Secret Key",
    "region": "Your Region (ap-northeast-1等)",
    "bucketName": "S3 Bucket Name",
    "keyPath": "S3 Key Path",
}

main.go

ffmpeg で生成した動画サムネイルを S3 にアップロードするサンプルコードです。

main.go
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

var c = readCredentialsJson()
var client = getS3Client()

var videoURL string = "Target Video URL"
var thumbName string = "thumbName.png"
var frameSecond string = "0"

func main() {
    lambda.Start(lambda2s3)
}

func lambda2s3() (string, error) {
    f := createThumb()
    putFileToS3(f)

    return fmt.Sprintf("done!"), nil
}

// ffmpegでサムネイルを生成
func createThumb() *os.File {
    // 環境変数を設定
    os.Setenv("PATH", os.Getenv("PATH")+os.Getenv("LAMBDA_TASK_ROOT"))

    // サムネイルを生成し、/tmpフォルダに一時保存
    err := exec.Command("ffmpeg", "-i", videoURL, "-ss", frameSecond, "-frames:v", "1", "/tmp/"+thumbName).Run()
    if err != nil {
        fmt.Println(err)
    }

    // 一時保存したサムネイルを読み出す
    f, err := os.Open("/tmp/" + thumbName)
    if err != nil {
        fmt.Println(err)
    }
    return f
}

// S3にアップロード
func putFileToS3(f *os.File) {
    client.PutObject(&s3.PutObjectInput{
        ACL:         aws.String("public-read"),
        Bucket:      aws.String(c.BucketName),
        Key:         aws.String("/" + c.KeyPath + thumbName),
        ContentType: aws.String("image/png"),
        Body:        aws.ReadSeekCloser(f),
    })
}

// S3クライアントを作成
func getS3Client() *s3.S3 {
    sess := session.Must(session.NewSession(&aws.Config{
        Credentials: credentials.NewStaticCredentials(c.AccessKeyId, c.SecretAccessKey, ""),
        Region:      aws.String(c.Region),
    }))
    client := s3.New(sess)

    return client
}

// 認証情報の構造体
type Credentials struct {
    AccessKeyId     string `json:"accessKeyId"`
    SecretAccessKey string `json:"secretAccessKey"`
    Region          string `json:"region"`
    BucketName      string `json:"bucketName"`
    KeyPath         string `json:"keyPath"`
}

// 認証情報JSONを読み込む
func readCredentialsJson() Credentials {
    jsonString, err := ioutil.ReadFile("credentials.json")
    if err != nil {
        fmt.Println(err)
    }

    c := new(Credentials)
    json.Unmarshal(jsonString, c)

    return Credentials{
        AccessKeyId:     c.AccessKeyId,
        SecretAccessKey: c.SecretAccessKey,
        Region:          c.Region,
        BucketName:      c.BucketName,
        KeyPath:         c.KeyPath,
    }
}

実行コマンド

念のため、サンプルコードの実行コマンドも掲載しておきます。

$ GOOS=linux go build -o main

でコンパイルして、

$ zip -r myfunc.zip main ffmpeg

で圧縮。出来た圧縮ファイル myfunc.zip を Lambda にアップロードすれば Lambda関数 の完成です。

一部解説

環境変数の設定

// 環境変数を設定
os.Setenv("PATH", os.Getenv("PATH")+os.Getenv("LAMBDA_TASK_ROOT"))

同梱している ffmpeg を呼び出すために、作業ディレクトリにPATHを通す必要があります。
今回のサンプルでは os.Setenv() と os.Getenv() で設定しました。

/tmp ディレクトリの利用

// サムネイルを生成し、/tmpフォルダに一時保存
err := exec.Command("ffmpeg", "-i", videoURL, "-ss", frameSecond, "-frames:v", "1", "/tmp/" + thumbName).Run()
if err != nil {
    fmt.Println(err)
}

Lambda では、/tmp という一時作業ディレクトリが提供されています。
一般に、Lambda を S3 と連携させる際によく利用されます。

今回は、ffmpeg で出力したサムネイルの一時保存先として利用しました。

参考記事

ffmpeg のサムネイル生成コマンド

Golang での外部コマンドの実行

/tmp ディレクトリについて

Node.js で ffmpeg を利用した例

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4