LoginSignup
2
0

More than 3 years have passed since last update.

[ActiveStorage] s3上のファイルをffmpegで処理して再アップロードする

Last updated at Posted at 2021-04-06

すでにs3上にアップロードされているファイルをffmpegで処理したい場面があったのでまとめます。

aws上で処理する場合はs3からlambdaでffmpegを動かしたり、elastic transcoderを使う方法があるかと思いますが、今回はただメタデータを付与したいだけの軽い処理なので、rails上で処理する方法にしました。

次のようなモデルを想定しています。

class Post < ActiveRecord
  has_one_attached :movie
end

gem

  • sidekiq
  • streamio-ffmpeg

実装

class TranscodeWorker
  include Sidekiq::Worker

  def perform(post_id)
    post = Post.find(post_id)

    # Rails内での一時保存ファイルの作成
    local = Tempfile.open
    local.binmode

    # s3からダウンロード
    post.movie.download do |data|
      local.write(data)
    end

    # FFMPEGのインスタンスで処理
    movie = FFMPEG::Movie.new(local.path)
    output_path = "#{Rails.root}/path/to/output.mp4"
    movie.transcode(output_path, %w(-metadata:s:v rotate=180 -c copy))

    # 再アップロード
    post.movie.attach(
      io: File.open(output_path),
      filename: "rotated_#{Time.current.strftime("%F_%T")}.mp4",
      content_type: "video/mp4"
    )
    post.save!

    local.close
  end

ActiveStorage::Blob#downloadはバイナリーを返すので、tempfileはbinmodeでバイナリモードにしておく必要があります。ちなみにrewindでポインタをファイルの先頭に戻せるので、ダウンロードしたファイルを先頭から読み込む場合はコールしておくと良いと思います。

streamio-ffmpegはffmpegとほぼ同じことができます。transcodeは第2引数に配列で、ffmpegのオプションを指定できます。第1引数のpathに出力してくれます。%w()%W()にすれば文字列の時と同様に変数展開できます。

再アップロードはActiveStorage::Attached::One#attachをコールすればOKです。HTTPリクエスト経由ではないファイルをアタッチする場合は、ioとfilenameの指定が必須です。content_typeは必須ではないですが、指定した方が無難かと思います。

動画処理に関する機能なので、非同期での実装例でした。

2
0
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
2
0