以前のブログで【便利】コマンドラインツールで超解像処理!静止画も動画も高画質にという内容で書いていました。
PowerShellやcmdの補完機能があるとはいえ、コマンドラインでの実行では打ち込みが多いので結構大変です。こんなときにはバッチファイル(.bat)などを使用することで入力の負担は軽減できるのですが…自分にはバッチファイルを作る知識があまりないので、このときの内容をバッチファイル化を通して作り方を学び直したいと思います。
元になる処理
今回は、以下のような処理を考えます。この処理では低画質mp4動画ファイルをフレーム分割、高画質化の処理を行い、それを結合しつつ、元の動画ファイルの音声を結合するといった処理になっています。
PS> mkdir img PS> mkdir hires PS> .\ffmpeg.exe -i .\640×480_サンプル動画.mp4 -q:v 1 .\img\%06d.png PS> .\realesrgan-ncnn-vulkan.exe -i img -o hires -n realesrgan-x4plus PS> .\ffmpeg.exe -i .\hires\%06d.png -i .\640×480_サンプル動画.mp4 .\output.mp4
このときは各処理の実行ファイルパス上で作業を行っていたのですが、できれば環境変数PATH
に実行ファイルのパスを追加しておくことで、.\ffmpeg.exe
というような表記をffmpeg.exe
にする省力化もできると思います。今回はPATH
に追加したという前提で行います。
大まかな処理は先程説明しましたが、もう少し処理を詳細にしてみます。
- 低画質動画ファイルをフレームごとに分割するためのフォルダを作成します。(フォルダ名は指定する)
- 高画質化したフレーム画像を保存するフォルダを作成します。(フォルダ名は指定する)
- ffmpeg.exeを使用して指定した動画ファイルからフレーム毎の静止画(.pngファイル)を先程のフォルダへ保存を行う(動画ファイルは指定する)
- realesrgan-ncnn-vulkan.exeを使用して、先程の静止画ファイルをそれぞれ高画質化する。※
- ffmpeg.exeを使用して、高画質化したフレーム画像使用して動画を構成する。(出力ファイル名は指定する)
※realesrgan-ncnn-vulkan.exeは作業ファイルをフォルダ指定できるのでかなり簡単に書くことができます。
この処理からバッチファイルで引数として指定する必要があるのは以下の項目となります。
- 入力する動画ファイル名(パス)
- 入力動画のフレーム画像を格納するフォルダ名(パス)
- 高画質処理を行ったフレーム画像を格納するフォルダ名(パス)
- 出力する動画ファイル名(パス)
続いて必要になる機能を考えてみます。
こんなところでしょうか。
加えて基本的な部分となりますが以下も必要になってきます。
- ディスプレイ出力時のechoを非表示にする
- コメント記述する
実行は以下のような想定になるかなと思います。バッチファイルの名前はprocess_video.bat
としています。
PS> process_video.bat "input.mp4" "./img" "./hires" "output.mp4"
注意点ですが、引数で与える値をダブルクォーテーション(")で囲んでいますが、これはPowerShellでもcmdでも動作するようにするためです。ダブルクォーテーションを使用することで、パスの区切り文字を"/"、"\"(¥)のどちらでも使用することができるようになります。また、空白文字を含むパスがあっても対応ができる点でこちらを採用しています。
基本的な記述
ディスプレイ出力時のechoを非表示にする
このあたりは基本ですね。よく出てくるので自分も知っています。ファイルに以下の様にいれれば それ以降でechoを使用して文字列表示を行う場合にコマンド実行としてのechoが画面表示されなくなります。
文字列表記時にechoを出さない
@echo off echo テスト
実行
>sample.bat
テスト
コメント記述
バッチファイル内のコメント表示といえばremになるのですが、実はその他の記載方法もあります。それが::
(コロン2つ)となります。自分もこのことは今回調べて初めてわかりました。remはパット見わかりにくいとは思っていましたが、::
をしようすることでかなり可読性が良くなったように感じます。ただ、バッチファイルのラベルの記述がが`:
(コロン1つ)なのでifやfor内で使用するとバグになる可能性がありそうです。このあたりは注意かもしれません。
REM これはコメントです
:: これもコメントです
メインの処理部分
基本部分はわかってきたので(このあたりはよく知られてますよね~)続いてはメインの処理部分をおさえていくことにします。
バッチファイルに与えるコマンドライン引数をチェック・取得する。
バッチファイルでのコマンドライン引数は以下の様に実行を行うと
ファイル名.bat 引数1 引数2 引数3 ……
この場合、バッチファイル内では%1
、%2
、%3
、……の記述で参照できます。バッチファイル側で%に続く数値が何番目かを表します。ちなみに引数は単純に使用する場合には10個(%9)までの使用になります。(SHIFTを使用すれば使用できるみたいですが、現実的じゃないかも?)
引数の個数はこの何番目の引数の値が空か否かを判別することになるかなと思います。(C言語などにあるargvっぽいものはなさそうでした)
また、後述する変数を使用するのですが、その格納時にダブルクォート(")も同時に格納されると面倒なことになりそうなのでその解決策はないのかなと調べてみると…%~1
、%~2
、%~3
、……の記述でダブルクオーテーションなしの値を参照することができるようです。以下の様にコードをつくって実行すると
@echo off :: %1の参照テスト echo %1 :: %~1の参照テスト echo %~1
実行結果は以下のようになり、~があると引数に与えたダブルクオーテーションが削除されて参照がされます。厳密に言えばパスであれば混在していてもWindows側がよしなに処理を行ってくれるのですが、他の処理を行う際は気にしておいたほうがいいかもしれません。今、気がついたのですが、PowerShellでは%1も%~1の実行結果は同じになるようです。
cmdでの実行
>sample.bat "img" "img" img
PowerShellでの実行
PS>.\sample.bat "img" img img
では元の処理に戻って、今回は4つの引数があるので4つあるかを調べてみる部分を作成してみます。%~4
の文字列が空か調べてます。もし空ならエラー出力をしてプログラムを終了させます。エラー出力では使い方を出力するようにします。
@echo off :: 引数の確認 if "%~4"=="" ( echo 使用法: %0 [入力動画パス] [imgフォルダパス] [hiresフォルダパス] [出力動画パス] goto :eof )
実行結果
# 引数が4つある場合 >sample.bat arg1 arg2 arg3 arg4 # 引数が4つない場合 >sample.bat arg1 arg2 arg3 使用法: sample.bat [入力動画パス] [imgフォルダパス] [hiresフォルダパス] [出力動画パス]
コマンドライン引数の値を変数に格納する
続いてはコマンドライン引数の値を変数に入れておきます。今回はあまり必要ではないのですが、遅延環境変数展開
を入れておこうと思います。変数をセットあとすぐにifやfor内で変数参照を行う際に予想通りの動きになります。このあたりは説明が難しいので以下をご参照ください。使用したら最後にendlocal
を入れておくのも忘れずに。
今回のバッチファイルでは関係ないですけどね。念の為入れておいたほうがいいかなとは思います。 では、これも含めて変数に入れていきます。
変数の格納方法
set "inputVideo=%~1"
変数の参照方法
echo inputVideo=%inputVideo%
変数の参照時には変数を%
で囲みます。
@echo off setlocal enabledelayedexpansion :: 引数の確認 if "%~4"=="" ( echo 使用法: %0 [入力動画パス] [imgフォルダパス] [hiresフォルダパス] [出力動画パス] goto :eof ) :: 引数を変数に格納 set "inputVideo=%~1" set "imgFolder=%~2" set "hiresFolder=%~3" set "outputVideo=%~4" :: 変数の参照 echo inputVideo=%inputVideo% echo imgFolder=%imgFolder% echo hiresFolder=%hiresFolder% echo outputVideo=%outputVideo% endlocal
実行結果
> sample.bat arg1 arg2 arg3 arg4 inputVideo=arg1 imgFolder=arg2 hiresFolder=arg3 outputVideo=arg4
フォルダがない場合のみフォルダの作成する
これは引数に格納したファイルが存在するか否かを確認して、ない場合にはmkdir
をすることになるので以下のような処理を追加していきます。ここまで来るとそこまで難しくはないですね。if not exist フォルダ名
でフォルダがないことを確認できています。
:: フォルダの準備 if not exist "%imgFolder%" mkdir "%imgFolder%" if not exist "%hiresFolder%" mkdir "%hiresFolder%"
各処理で変数値を参照して実行を行う
あとは各プログラムの引数に変数を参照させて行きます。ファイル名も変えておきます。
ffmpeg
の引数に%06d.png
と入れている部分は、バッチファイルでは%
のエスケープ文字が必要となるため%%
とする必要があります。
RealESRGANとffmpegを使用して超解像化した動画を作成するバッチファイル
これで作成しようと思っていたバッチファイルが完成しました!
cmdでの実行例
> process_video.bat "input.mp4" "./img" "./hires" "output.mp4"
PowerShellでの実行例
PS> ./process_video.bat "input.mp4" "./img" "./hires" "output.mp4"
おわりに
これまではコマンドラインからの実行で済ませていましたが、改めてバッチファイルの作り方や、昔の知識がアップデートできたような気がします。特にコメントが::
で記述できたり、引数のダブルクオーテーションの削除方法が%~1
でできるというのは今後もちょっと使えそうだなとも思いました。
普段はsh
やbash
などを使用することも多いのですが、AI関連の作業となるとWindowsを使用することも多いのでバッチファイルの書き方とても勉強になりました。