関連記事(5月26日)Chromeで正常再生させる後処理について

FFmpegでパソコン操作画面の動画キャプチャを行う件、
前ブログで書いた手順を自分なりに改善したのでメモ。今回はまず無劣化でMKV形式に録画、続いてWebM形式にエンコードします。前の方法は録画と同時にMP4保存していて画質が余り綺麗でなく、それをスマートフォンのFirefoxで見れるようにWebMに変換することで、さらに劣化していました。

今回は無劣化の動画からエンコードし、圧縮率も良いので画質やファイルサイズを基本的に気にしなくて済みます。WebMは一部のブラウザがまだ対応していませんが、Firefox最新版ならPC・スマホともに問題なく再生でき、ブラウザで駄目でもダウンロードしてもらえば各種動画プレーヤで見れるので、このブログではWebMに一本化する予定。

無劣化録画については、
Arch Linux Japan - FFmpeg のスクリーンキャストの項に「ロスレスエンコード」コマンド例があって知りました。m(_)m下は、今回の方法でキャプチャし 2015/05/032015/05/09 に載せた動画の再掲です。(526日追記:Chromeで正常再生できる動画に差し替えました)
≫ Link : example_loop_pg_ctl.bat.webm

≫ Link : demo_autohotkey_tut.webm

準備
以下Windows 7 32bitで行った例です。まず http://ffmpeg.zeranoe.com/builds/ からコンパイル済みのFFmpegを入手。これを書いている時点の最新版はffmpeg-20150428-git-b410c69-win32-static.7zでした。このうち今回必要なのはbinフォルダ内にある ↓ffmpeg.exeだけで、適当な作業用フォルダに解凍します。

↓ 解凍したffmpegと同じ場所にバッチファイル二つと、場所はどこでもいいですが録画範囲確認用のHTMLを置きます。後者は
先月作ったものと同じで、JavaScriptでブラウザの左上位置とサイズを表示するもの。これを目安にFFmpegの録画範囲オプションを設定します。Firefox 37, Chromium 42, IE10で動作確認しました。
check_size.htmlSelectRawtextBitbucket
<html><head><script type="text/javascript"><!--

get_loc = function() {
    var b = document.getElementsByTagName('body')[0];
    var t = '-video_size ' + window.outerWidth;
    t += 'x' + window.outerHeight;
    t += ' -offset_x ' + window.screenX;
    t += ' -offset_y ' + window.screenY;
    b.textContent = t;
    b.style.fontFamily = 'monospace';
}

window.onload = function() {
    var tid = setInterval(get_loc, 100);
}

//--></script></head><body></body></html>

↓ 一つ目のバッチがスクリーンの無劣化録画で、やり直しし易いよう一実行ごとにpress [s] to start, [q] for quitのプロンプトを出して待機します。この待機中にファイル内のオプション設定を変えて保存すれば、次の実行時に即反映されます(自分自身を再帰呼び出しするから)。
example_ffmpeg_1.batSelectRawtextBitbucket
@echo off
:start

set outfile=test.mkv
set opt1=-show_region 0 -framerate 30 -draw_mouse 1
set opt2=-video_size 460x320 -offset_x 70 -offset_y 5
set opt3=-loglevel quiet -i desktop -c:v ffvhuff

setlocal EnableDelayedExpansion

if not "%mod%" equ "1" (
    cls
    set /p inp="press [s] to start, [q] for quit : "
    if not "!inp!" equ "s" goto :eof
    set mod=1
    "%~0" %*
)
ffmpeg -f gdigrab %opt1% %opt2% %opt3% %outfile%
set mod=0
goto :start

↓ 二つ目のバッチがエンコード用。多少時間かかりますが二パスにしました。
example_ffmpeg_2.batSelectRawtextBitbucket
@echo off
ffmpeg -loglevel quiet -i test.mkv -pass 1 tmp.webm
ffmpeg -loglevel quiet -i test.mkv -pass 2 output.webm
del tmp.webm
del ffmpeg2pass-0.log

使用例
まず録画範囲確認用HTMLをブラウザで読み込むと、下のようにFFmpegに渡すオプションの形式で表示されます。今回のJavaScriptは単純に0.1秒ごとに再実行するので、テキスト選択してもすぐ解除され、コピペに使えません。まぁ目安用なのでいいかなと。

↓ 録画用バッチを起動した様子。これが待機状態で、s打鍵で開始、qで終了します。終了したらコンソールが自動的にクリアされ、再び同じプロンプトに戻ります。FFmpegのオプションで-loglevel quietになっているため、録画中は一切表示が出ません。loglevelを変更すれば録画中の情報をいろいろ表示できます。

↓ 保存先に指定したファイルが既にあると、s打鍵で録画開始を指示した後、FFmpegがそれを検知して「上書きしますか」と聞いてきます。この時点で録画自体は始まっており、上書きを指示すると、既存の動画の後方につなげて保存する意外な挙動でした(文字通りの上書きではない)。環境によって違うかもしれません。混乱を避けるためには、常に新規ファイルへの保存がいいかも。

↓ 録画結果のファイル例。無劣化なので、わずか14秒の動画が62MB、1分超えただけで数百MBになります。

WebMへのエンコードバッチを起動し、保存先ファイルが既存だった場合。未存ならメッセージは一切なく自動的に開始し、終わり次第コンソールが消えます。

↓ エンコード結果の一例。圧縮率は動画の内容によって変わりますが、先ほどの14秒・62MBから241KBになりました。1分でも約1MB程度で済み、画質も良好です。

録画したうち先頭や末尾に不要部分があれば、エンコード時のオプション指定でカット可能。「-ss秒数」が開始時間なので先頭スキップ、「-t hh:mm:ss」がエンコード時間指定なので末尾スキップに使えます。(情報源:
それマグで!- ffmpegで指定時間だけエンコード