移転しました。

約3秒後に自動的にリダイレクトします。

zencoder ことはじめ

こんにちわ、id:gaoohです。

動画の変換処理にzencoder を導入してそこそこよかったのでまとめます。

Viibarという会社はB2B動画にかかわるトータル業務を請け負っています。 サービスとしてはVyncというクラウド制作管理ツールを提供していますが、基本的にサービスとして動画に関わることが多いので、社内ツール含めて動画ファイルはよく扱います。

viibar.com

動画ファイルと言っても、一般的にYouTubeや各種プラットフォームで再生される動画は mp4 ( h.264 ) であることがほとんどです。 ただしそれ以外の媒体に入稿する場合もありますし、元データは必ずしも mp4 ( h.264 ) ではないこともあります。 なので、エンコード処理は切っても切り離せません。

かと言ってこれらの処理は時間も計算リソースも食うのでなるべくならクラウドサービスにまかせたい。 ffmpeg とかで頑張りたくない!

AWS上にシステム展開している場合は、現状だとAWS Elemental MediaConvert を使うのが一番妥当な選択肢だと思います。ただいろんな事情でVyncではElasticTranscoder を利用してはいますが。 とはいえElasticTranscoderでもよほど特殊な変換をしない限り事足りますし、スケールしたい場合の方法も用意されており、もろもろ安心感もあります。

以前はAWS上にシステムを構築することが多かったのでそれ以外の選択肢を考える必要もなく済んでいたのですが、最近は用途によってGCP上に構築することも多く、GCP上にはお手軽に試せるAWS Elemental MediaConvert相当なフルマネージドなサービスはないので(2019/12月現在)、「動画のエンコードどうしよう」という問題になりました。

もちろんシステムとしてはGCP上に構築して、ファイルはs3上に保存し、トランスコードはAWSでみたいな構成はできなくはないけれど、うーん、もうちょっと楽したい。

ということでいろいろ外部サービスを検討した結果 zencoderの導入をしました。

zencoder.com

GCS との連携

GCP上で連携したいGCSバケットの読み込みと書き込みを許可したサービスアカウントを作成し、Access keyを発行、それをzencoder に設定します。

Google Cloud Storage トリガー を利用して、アップロードされたファイルを変換する

zencoder は node 用のライブラリがあるのでこれを利用します

github.com

sampleコードは筆者がTypeScript推しなので TypeScript です。

import * as Zencoder from 'zencoder';


export const transcode = functions
  .region('asia-northeast1')
  .storage.object()
  .onFinalize(async object => {
      
  // zencode側のAPIキーとCredentialsのNicname、出力バケット名などはfunctions.config()で管理
  const config = functions.config();  
  const outputBucket = config.output.bucket;
  const credential = config.zencoder.credential;
 
   const params = {
      input: `gcs://${this.object.bucket}/${this.object.name}`,
      credentials: credential,
      region: 'asia-tokyo',
      outputs: {
        url: `gcs://${outputBucket}/${this.object.name}`,
        credentials: credential,
        format: 'mp4',
        headers: {
          'Content-Type': 'video/mp4'
        },
        quality: 4,
      }
    };

    const zencoder = Zencoder(config.zencoder.api_key);
    await this.zencoder.Job.create(params)
      .then(({ data }) => {
        logger.info(`zencoder request: ${JSON.stringify(data)}`);
      })
      .catch(err => {
        logger.error(`zencoder request error: ${JSON.stringify(err.errors)}`);
      });
  });

お手軽!

変換エラー時の処理

フルマネージドなAWS Elemental MediaConvert や ElasticTranscoder の場合、処理の開始と完了はSNS経由で通知を受け取ったり、SQSへ貯めるなどの対応可能です。

zencoderの場合は正常にエンコード処理が終了したら、指定した場所にファイルが作られるだけなので、エラー通知やJob管理が必要なら別途作り込む必要があります。APIでJobの進行状況や完了状況は問い合わせ可能なので、仕組み的には対応は可能です。

変換スピード

zencoderは公式でパフォーマンスは数百件の同時ジョブ送信のテストにおいて Amazon Elastic Transcoder の平均 14 倍といっています。 利用しているシステムが違うため、パフォーマスを正しく比較しているわけではないので、同時処理数が多い場合は比較検討の余地があるかと思います。

料金

zencoder側はプランによって違うので比較はしにくですが、一番安い月1000分までで1分あたり4.3円で、用意されている最上位プランまであげると1分あたり2.1円ぐらい。 対してAWS Elemental MediaConvert は出力フォーマットによってかなり値段が違いますが、だいたい1分あたり2.3円ぐらい。 システム全体でいうと、当然ファイルの転送量などを加味されるので、適用するシステムによる部分はありますが、単体の料金的にはどちらも遜色ない感じです