Screencastify で録画した動画を mp4 に変換する #ffmpeg

Screencastify で録画した動画を mp4 に変換する #ffmpeg

Screencastify を使用して録画された動画は webm 形式になるので、これを mp4 に変換するのに FFmpeg を使用しました。その時の手順を備忘録代わりに公開します。

背景

弊社内で打合せや勉強会を行うとき、参加者が複数拠点にまたがっていたりリモートワークだったりということが当たり前なので、そういう時には WebEx や Google Hangouts 等を使って各拠点を結んでいます。

先日社内勉強会を実施した際も Google Hangouts で中継を行ったのですが、時間があわずに参加できないという声も聞かれたので、録画しておくことにしました。Hangouts の録画には Screencastify という Google Chrome の機能拡張を使用したのですが、

  • ローカルに保存する場合は webm 形式になる(Google Drive に連携すると mp4 形式で保存できる)

という制限がありました。

今回は都合上、Google Drive へは連携せずローカルに保存したので webm 形式になるのですが、社内とはいえ公開するなら mp4 形式にしておきたいものです。そこで変換(トランスコード)することにしました。

ffmpeg の準備

FFmpeg はフリーの動画変換ソフトウェアです。対応している動画(映像・音声)形式・コーデックが非常に多く、もちろん今回のターゲットの webm と mp4 にも対応しています。

基本的には CLI で、macOS で HomeBrew を使っている環境であれば下記のコマンドでインストールすることが出来ます。

$ brew install ffmpeg

他の OS については、公式のダウンロードページ からリンクをたどるといいでしょう(ただし Windows については、広告が多量に貼られたサイトに誘導されるので、意図しないところをクリックしないよう気をつけて下さい)。以下は macOS で使用した場合を前提に記載します。

FFmpeg は簡単な動画の編集を行うこともできるので、今回はそれを使って、前後に少し余裕を持たせて録画した動画から必要な部分を切り取ることもしています。

Google Hangouts の録画について

Screencastify 機能拡張をインストールした Google Chrome から Hangouts に参加し、録画するだけです。特に設定するようなこともないのですが、今回は勉強会の同禄が目的であり、資料は別途公開されることから、下記のように設定しました。

  • 動画の解像度(= ブラウザの表示領域のサイズ)... 1280x720
  • 動画のフレームレート ... 30fps

基本的には、声(登壇者・質問者)が聞こえて、その時にどんな資料が映っていたか、が分かれば良いとしています。フレームレートはあとで 15fps に落とすので、この時点で 10fps に制限していてもいいのかもしれません。このあたりは試行錯誤中です。

また、録音する音声として「TAB Audio」にチェックを入れておきます。これをチェックしないと Hangouts の音声が録音されないので要注意です。

録画中は Chrome のタブにアイコンが表示されます。 Hangouts を受信しながらなので、結構負荷があがります。

録画が終わったら Screencastify の「Save to Disk」をクリックし、表示されたメニューから「Save Video to Disk」を選択して動画を保存しておきます。

webm を mp4 に変換

ffmpeg コマンドには非常に多くのオプションがありますが、今回の目的は主に動画形式の変換なので、最低限の指定のみ行いました。

例えば Screencastify からダウンロードした動画ファイルの名前が「captured.webm」、出力したい動画ファイル名が「output.mp4」だとすると、実行するコマンドラインは下記のようになります。

$ ffmpeg -i captured.webm -r 15 output.mp4

説明

-iで、入力する動画ファイル名を指定します。ffmpeg は入力されたファイルを自分で解析して動画形式を認識しますので、特に指定する必要はありません。FFmpeg をインストールすると ffprobe というコマンドも同時にインストールされるのですが、これを使うと、対象の動画がどのような形式か(= ffmpeg にどのような形式で認識されるか)を確認することが可能です。

試してみるとこういう感じです。コンテナ形式が WebM(Matroskaサブセット)、コーデックは映像が VP8、音声は Opus になっていることが分かります。

$ ffprobe captured.webm
ffprobe version 3.4.1 Copyright (c) 2007-2017 the FFmpeg developers
(略)
Input #0, matroska,webm, from 'captured.webm':
  Metadata:
    encoder         : Lavf56.40.101
  Duration: 00:00:31.31, start: -0.007000, bitrate: 1153 kb/s
    Stream #0:0: Video: vp8, yuv420p(progressive), 1280x720, SAR 1:1 DAR 16:9, 1k fps, 1k tbr, 1k tbn, 1k tbc (default)
    Stream #0:1: Audio: opus, 48000 Hz, stereo, fltp (default)
$

...フレームレートが何故か 1,000fps なんてことになっているので、出力時には明示的に指定することにします。それが -r 15 です。

-r[:stream_specifier] fps (input/output,per-stream)
    Set frame rate (Hz value, fraction or abbreviation).

-r 15 の場合は 15fps、つまり 1秒間に 15コマの動画になります。

最初は録画時の設定に合わせて -r 30 と指定していたんですが、そもそも Google Hangouts で送られてくる映像のフレームレートがそこまで高くなく、かつ求められる画質もそこまで高くなく、実際に比べてみて 30 と 15 でほぼ印象に差がなかった(そのわりに変換にかかる時間が短縮された)ので 15 にしました。

なお、この -r 15 は必ず入力ファイル名の後ろ、出力ファイル名の前にしないとなりません。もし入力ファイル名の前に書くと、それは「入力された動画ファイルのフレームレートを 15 とみなす」という指定になり意図とは違う動作になります。

出力するファイル名の拡張子は必ず .mp4 にします。ffmpeg はこれを認識して、良い感じに映像・音声の形式(コーデック)を決定してくれます。

実行

変換にはそこそこの時間がかかります。今回使用した MacBook Pro (Retina, 13-inch, Early 2015) 16GB だと、録画した動画の長さの 1/2 〜 2/5 くらいはかかりました。そしてその間、空冷ファンは回りっぱなしになります。。。

変換したときの出力は下記のような感じになります。

$ ffmpeg -i captured.webm -r 15 output.mp4
ffmpeg version 3.4.1 Copyright (c) 2000-2017 the FFmpeg developers
(略)
Input #0, matroska,webm, from 'captured.webm':
  Metadata:
    encoder         : Lavf56.40.101
  Duration: 01:05:16.65, start: -0.007000, bitrate: 2721 kb/s
    Stream #0:0: Video: vp8, yuv420p(progressive), 1280x720, SAR 1:1 DAR 16:9, 1k fps, 1k tbr, 1k tbn, 1k tbc (default)
    Stream #0:1: Audio: opus, 48000 Hz, stereo, fltp (default)
Stream mapping:
  Stream #0:0 -> #0:0 (vp8 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (opus (native) -> aac (native))
Press [q] to stop, [?] for help
[libx264 @ 0x7ffb46038200] using SAR=1/1
[libx264 @ 0x7ffb46038200] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 AVX2 LZCNT BMI2
[libx264 @ 0x7ffb46038200] profile High, level 3.1
(略)
Output #0, mp4, to 'output.mp4':
  Metadata:
    encoder         : Lavf57.83.100
    Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], q=-1--1, 15 fps, 15360 tbn, 15 tbc (default)
    Metadata:
      encoder         : Lavc57.107.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)
    Metadata:
      encoder         : Lavc57.107.100 aac
More than 1000 frames duplicated  461056kB time=00:56:39.50 bitrate=1111.0kbits/s dup=997 drop=15368 speed=2.72x
frame=58751 fps= 41 q=-1.0 Lsize=  531822kB time=01:05:16.53 bitrate=1112.4kbits/s dup=1208 drop=17381 speed=2.73x
video:468643kB audio:61144kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.384081%
(略)

この例で行くと「speed=2.73x」となっているので、1時間05分の動画の変換には 24分程度かかったということになります(65min ÷ 2.73 ≒ 23.8min)。

できあがった動画のファイルサイズは 520MB ほどでした(Lsize= 531822kB)。元の動画が 1.2GB だったので、半分以下の大きさになっています。

ちなみに試しに -r 10 としてみたところ、ファイルサイズは 480MB ほど、変換にかかった時間は 20分ほどになりました。改善幅が少なめなわりに、できあがった動画はカクカク具合が目立つ感じだったので、15fps 程度がちょうどいいかも知れません。

応用 1

実際に録画する際には、勉強会が始まる少し前から録画を開始して、いろいろ確認したり、話し出す頭が切れないようにしたりと工夫しました。当然できあがった動画には最初に余分な時間が含まれてしまいます。

見るたびにこの部分を飛ばしてもらうのは無駄なので、変換するときに切り詰めてしまいたいと思います。

Screencastify には簡易的に動画を編集する機能があるので、ダウンロードする前にこれを使って切り詰めても良いでしょう。ffmpeg で切り詰める場合には、入力ファイル名の前に -ss 開始時間 と指定します(ss = start time)。

例えば、動画開始後 30秒してから勉強会が始まった場合には、上で書いたコマンドラインを下記のようにします。

$ ffmpeg -ss 00:30 -i captuerd.webm -r 15 output.mp4

webm の動画も Google Chrome にドラッグ&ドロップすれば再生できるので、そこで頭出しの時間を確認すると良いでしょう。もちろん Screencastify の再生画面でも可能です。

動画の後ろを切りたい場合ですが、ffmpeg には終了時間を指定するオプションはないので、「できあがる動画の長さ(-t)」を指定することになります。

例えば「全体の長さが 1時間(01:00:00)の動画で、00:00:30 〜 00:55:00 を切り取りたい」という場合には、下記のような指定になります。

$ ffmpeg -ss 00:30 -t 54:30 -i captuerd.webm -r 15 output.mp4

とはいえ、よっぽど残るとまずいものが映っていない限り、後ろは多少長いままでも「勉強会の同禄」としては十分と思いますので、-ss 指定だけでもいいのかなと思います。

今回は必要なかったのですが、もし「休憩時間が無駄なので動画の途中を切り詰めたい」といった要望がある場合は。。。出来なくはないですが、さすがにそこまでの用途には ffmpeg は向いてないと思うので、iMovie や、市販の動画編集ソフトを購入するのがいいかと。そうでないなら、休憩時間の前と後ろで動画を分けるなら ffmpeg でも難しくないでしょう。

応用 2

また、最初に試し撮りをしていたときに、何故か狙ったサイズ(1280x720)になっていなかったことがありました(ffprobe で確認しました)。サイズも合わせて変換する場合には下記のように -s 横x縦 と指定します(s = size)。

$ ffmpeg -i captuerd.webm -s 1280x720 -r 15 output.mp4

そのぶん変換にかかる時間は増加することになります。画質にも影響があるので、事前に短めの動画で試験しておくことをお勧めします。

所感

Google Hangouts の録画はとても負荷が高くなります。そのために受信する動画の画質も落とされていると思われるので、そういった点や変換の手間を考えると、Hangouts とは別にカメラを用意して撮影した方が良いでしょう。通知さえ気にならなければスマフォという手もあります。

ただその場合、カメラやスマフォを固定する方法を考えないとなりませんし、それに比べたらこの方法は手軽です。同時に Hangouts で参加者に共有できるという点でも無駄が無いようにも思います。一長一短といえるでしょうか。

FFmpeg は数年前に使ったきり最近は使うところがなかったのですが、久しぶりにインストールしてみると、昔と変わらない頼もしさのまま対応コーデックが増えている感じで懐かしかったです。

最後に

一般的にはおそらく Screencastify を Google Drive 連携したり、iMovie などの GUI アプリケーションを使った方が初期導入が楽だと思いますが、今回は半分以上個人的な趣味で FFmpeg を使いました。CLI にも利点があるので、選択肢の一つとしてそろえておくのも良いかと思います。

ちなみに変換の待ち時間に、「これ S3 に動画あげたら変換されて出てくるとかよくね?」って思ったんですけど、アップロードの時間やコストを考えて、思っただけで終わらせました。ただ PoC として考えてみる分には面白そうなので、いずれ調べてみたいと思います。