2014年1月4日土曜日

「あの処理」までのVBScript (その9)FFmpegを使用した高速エンコード

「あの処理」までのVBScript (その7の1)no8 指定フォルダからアイテムを再帰的に検索して、"ビデオ"と不明ファイルの指定プロパティを出力する。

 ここまでは実は「あの処理」までの下地作り。 ようやく「あの処理」方向から進めていきます。

FFmpegを使用した高速エンコード「あの処理」への経緯

 自分はテレビ番組とかキャプチャ&エンコードで残してまして、実写系は720pなのですが、最近作成されるアニメは1080pフルハイビジョンサイズで残しています。 Aviutl 拡張x246の高画質2Passエンコードで残しているため、画質の割にはサイズは一話300MBと、さほど大きく無い、、、、とは思います。
 がチリも積もればナントやら。 この趣味を始めて10年以上の経過した今、新旧大小合わせて二万ファイルが以上6TBにも迫る勢いで、、、、自宅で見る分にはいいんですが外で見るにはねー
 見たい番組をマイクロSDカードにコピーしたり整理したり、クラウドサーバに保存してみたり、Pogoplugで自宅パソコンをサーバ化してAndroidスマホやタブレットで外から見れるようにしてみたり、他の同様に映像サーバ化できる製品をいろいろ試してみました使いづらい。
 クラウドや端末の内部ストレージは準備や一杯になったら整理しないといかんし、第一毎日のエンコードと整理に手いっぱいでそんな手間すらかけたくない。
 自宅映像サーバやクラウドは無線環境の状態に左右されやすい。 結局今までは内部ストレージとPogoplugの併用でダマシダマシ使っていたんだが、ここで去年末に
 内ポケットに2TBっすよ奥さん! でも2TB足らないっ、今動画は5TB超えている。 見たいファイルをどんどん2TBHDDに入れていったら、またいつかは一杯になり整理に追われる日々が復活してしまう、そしてクラッシュが訪れることに。。。。。。。(かなり被害妄想が入ってるけど、過去ストレージクラッシュなインパクトを二回経験してるからなーサードインパクトがいつ訪れるやら)

 ならエンコード済みファイルを、再エンコードしてファイルサイズを小さくしてやれば沢山入ってファイル整理の手間省けるんじゃね? 携帯端末での視聴と割り切れば、フルHD画質落としてもサホド違和感ないだろうしと割り切るしかないか。 第一フルHDで保管してる理由が二次使用に耐えうる画質にするためだし。
 そして色々方法を物色していく中で「NVIDIAのCUDA」とか「AMD Video Converter」を搭載したのとか果ては「SpursEngine」H.264エンコーダとかも試したんだけど、画質とファイルサイズとエンコード速度の妥協点が結局見つからなかった。
 「携帯動画変換君」はかなり良かったんだけど、足らないところが多く、使用しなくなりました(-_-;)

 画質とファイルサイズとエンコードの速度、この三つバランスが取れたエンコードを求めて行くと、結局「携帯動画変換君」や各種動画サーバがエンコーダーとして使用している「ffmpeg.exe」のDOS実行に行き着いた。 
 が、これを使うには問題があった。そのままで使うには手間がかかりすぎる。 DOSバッチの引数渡しとか二バイト文字でエラーなるし。
 Dirコマンドでファイル一覧取得してテキストエディタでバッチ組んで実行とかも考えてみたけど、そのままだとファイルの縦横サイズとか判らんから、ファイル毎のエンコード設定が問題となる。

 バッチ実行する方法を模索する中で、VBスクリプトのテストプログラムが良い感じで動いてくれた。 上のSSはそれでリサイズして再エンコードした動画ファイルとなる。中の情報も見れるし上々。

 VBスクリプトなら昔取った杵柄、下手でも組めるし今は解らない機能もインターネットで調べながらでもなんとかなるだろう。
 年末大掃除しつつ「VBスクリプトでFFmpegエンコード」。 所謂「あの処理」計画を妄想していった。
 リストアップした機能は

 ①指定フォルダ以下の動画ファイルをエンコードしつつ、指定フォルダの構造を再現しつつ転送する。
 ②動画の縦横サイズや実写系(30fps)・アニメ(24fps)などの品質によってエンコード品質を調整する。
 ③処理中断後、再度実行した場合は、正常終了したファイルはそのままに、途中のファイルか処理を再開する。 将来的には、元ファイルとエンコードファイルの作成日時を見て、元が新しくなっていたら再エンコードして差し替える。とかも視野に入れる。
 ④ ①~③は一度実行開始したら、実行停止まで全て自動で行なう。

 エンコードの自動化が今回のキモだな。そしてVBスクリプトならそれが出来ると判断した。なら正月休み中に一気にヤッチマエーーーー というわけで、「あの処理」シリーズ作成開始。
 ブログにアップしていった理由は、ブログに上げたら要所のコードの保存になるし、作成履歴にもなるし、見られる場所に上げることでコードの整理も進むかな~な思惑が。まぁ最後はあまり効果なさそうだけど。

 と言うわけでVBScript (その7の1)no8、を作成するまでで、指定フォルダ以下を再帰検索して動画ファイルを探すと同時に、ヒットした動画プロパティにアクセスして、情報を集計してエンコードの設定を詰め、エンコードパラメータのしきい値を詰めていった。
 エンコードの実行を制御する部分が出来たことで、ようやく「VBスクリプトでFFmpegエンコード」のエンコードを実行部分の作成に着手出来るようになった。
 自動化部分に合わせるようにエンコード部分作れば良いわけだからな。 

「VBスクリプトでFFmpegエンコード(あの処理)
・実行環境作成

【1】動作環境
 このVBScript & ffmpeg の実行環境はwindows8.1 Pro Preview 64bitです。その他の環境では実行はしていないのでご注意ください。

【2】FFmpeg のダウンロードと設置
 Zeranoe FFmpeg  とかからffmpegゲット。(自分は64-bit Static)。中のffmpeg.exeをvbsスクリプトと同じフォルダに置く。 FFmpegは各種環境でコンパイルしたバージョンが存在するため、気に入ったのを使用してもいいかも。

【3】ffmpeg設定ファイルの作成と設置
ffmpeg.exeと同じフォルダに"ffpresets"フォルダを作り、"main.ffpreset"ファイルを作成、ファイルを編集して以下を記述する。 ※改行のみで区切る。タブやスペースは正常認識しない可能性あり
coder=1
refs=1
flags=+loop
partitions=+parti4x4
me_method=hex
subq=1
psy=0
trellis=0
8x8dct=0
fast-pskip=1
bf=3
b-pyramid=2
b_strategy=1
direct-pred=1
weightp=1
weightb=1
g=150
keyint_min=1
sc_threshold=40
mbtree=0
qcomp=1

【4】ここまでで、同じフォルダにファイルが図の様に出来ている。
 FfmpegConv009.vbs
 ffmpeg.exe 
 ffpresets\main.ffpreset




処理について:
 FFmpeg.exeを用いてH.264変換する。すべてMainプロファイル (0-4)5パターンの高速1Pass出力。 音声は 元ファイルをそのまま引用(つまりMPxのみ有効)

実行例:
 Cscript 
FfmpegConv009.vbs 変換モード(0-4) 動画ファイルパス 出力フォルダパス"
 Cscript FfmpegConv009.vbs 3 C:\Doga\009\ATXCM20140102.mp4 C:\Doga\009\$



'以下、末尾までスクリプト


'################################################
'
'実行例:Cscript FfmpegConv009.vbs 変換モード(0-4) 動画ファイルパス 出力フォルダパス"
'
'
'処理概要
'FFmpeg.exeを用いてH.264変換する。すべてMainプロファイル (0-4)5パターンの高速1Pass出力。
' 音声は 元ファイルをそのまま引用(つまりMPxのみ有効)
'
'IN
' 変換モード(0-4)
' 0 品質 26 
' 1 品質 29
' 2 品質 32 
' 3 品質 32 1280x720 
' 4 品質 32  960x720
'
'動画ファイルパス
' 動画ファイルのパスを記述
'
'出力フォルダパス
' 変換出力先パスを記述。
'
'追記事項
' 元ファイルと 先ファイルが同一ファイル名になった場合、先ファイルの末尾に.mp4追加する。
'################################################
'
'以下スクリプト
Option Explicit

'WScript.Object

Dim oWSFso, oWArgu , WSShel 


Dim iMODE_ITEM0
Dim sFILE_ITEM1 
Dim sPATH_ITEM2
Dim sRun

Set WSShel = WScript.CreateObject("WScript.Shell")

'フォルダ・ファイル操作
Set oWSFso = WScript.CreateObject("Scripting.FileSystemObject")

'パラメータ確認用
Set oWArgu = WScript.Arguments

Select case oWArgu.count
Case 3 '元パス⇒先パスへ ファイルの縮小エンコード

'置換用に元パス名保持
iMODE_ITEM0 = oWArgu.item(0)
sFILE_ITEM1 = oWArgu.item(1)
sPATH_ITEM2 = oWArgu.item(2)

'FFmpeg処理実行
sRun = sRun_FFmpeg(iMODE_ITEM0, sFILE_ITEM1 , sPATH_ITEM2) 

'変換完了
If Len(sRun)>0 Then
WScript.Echo "bRun_FFmpegは【" & sRun & "】を作成しました。"

Else
WScript.Echo "bRun_FFmpegは【" & sFILE_ITEM1 & "】を変換できませんでした。"

End if

Case Else
    Wscript.Echo "引数が不正です。実行例:Cscript FfmpegConv009.vbs 変換モード(0-4) 動画ファイルパス 出力フォルダパス"

End Select

'終了処理
Set oWArgu = Nothing
Set oWSFso = Nothing
Set WSShel = Nothing
Wscript.Quit 


'
'#######################################
'メインルーチン
'#######################################
'パラメータ
'in
' 0  >>> ffmpeg -i %1 -vcodec libx264 -vpre main -crf 26 -vsync 2 -acodec copy -y %2
' 1  >>> ffmpeg -i %1 -vcodec libx264 -vpre main -crf 29 -vsync 2 -acodec copy -y %2
' 2  >>> ffmpeg -i %1 -vcodec libx264 -vpre main -crf 32 -vsync 2 -acodec copy -y %2
' 3  >>> ffmpeg -i %1 -vcodec libx264 -vpre main -crf 32 -s 1280x720 -vsync 2 -acodec copy -y %2
' 4  >>> ffmpeg -i %1 -vcodec libx264 -vpre main -crf 32 -s 960x720 -vsync 2 -acodec copy -y %2
'
's1Doga
' 変換元の動画ファイルパス
'
's2Folder
' 出力先パス
'
'Out
' 成功:True
' 失敗:False
'
Function sRun_FFmpeg(iMODE , s1Doga , s2Folder )
WScript.Echo  "bRun_FFmpeg(" & vbTab  & iMODE & vbTab & s1Doga  & vbTab & s2Folder

Const cFFMPEG_EXE = "ffmpeg.exe"
Const cFFMPEG_SET = "ffpresets\main.ffpreset"
Const sFFMPEG_2FG = ".mp4"
Const c26f = 0
Const c29f = 1
Const c32f = 2
Const c32w = 3
Const c32q = 4

Dim o1Doga
Dim s2File

Dim cDC
cDC = Chr(34)

'実行vbsファイルのパス
Dim iPathLen , sExePath 
Dim sReturn 

'Return初期値
sReturn = ""

Dim sFFmpegExe ,sFFmpegPSet , sFFmpegRun ,sFFmpeg1 , sFFmpeg2 , sFFmpeg3

'実行vbsファイルのパス取得
iPathLen= Len(WScript.Scriptfullname) - Len(WScript.Scriptname)
sExePath = Left(Wscript.Scriptfullname, iPathLen)


If IsNumeric(iMODE) Then
iMODE = Clng(iMODE)
'実行モード、元パス、先パス の確認
If (iMODE <= c32q)  Then 
With oWSFso
'ffmpegの実行パスファイル取得
sFFmpegExe = .BuildPath(sExePath , cFFMPEG_EXE)
sFFmpegPSet = .BuildPath(sExePath , cFFMPEG_SET)

'sFFmpegExe , sFFmpegPSet , s1Doga , s2Folder の存在確認
If .FileExists(sFFmpegExe) and .FileExists(sFFmpegPSet) and .FileExists(s1Doga) and .FolderExists(s2Folder) Then

'元ファイルオブジェクト取得
Set o1Doga = .GetFile(s1Doga)
'出力名取得
s2File = .BuildPath(s2Folder , o1Doga.name) 

'元と先が一致したら、末尾に追加
If Lcase(s1Doga) = Lcase(s2File) Then
s2File = s2File  & sFFMPEG_2FG
Else
'拡張子.mp4ではなかったら末尾に付加
If Lcase( Right( s1Doga , Len(sFFMPEG_2FG))) <> sFFMPEG_2FG then
s2File = s2File  & sFFMPEG_2FG
End if
End if


'FFmpeg 実行文作成
sFFmpegRun = sFFmpegExe & " -i " & cDC & s1Doga & cDC 
Select case iMODE
Case c26f
sFFmpegRun = sFFmpegRun & " -vcodec libx264 -vpre main -crf 26"

Case c29f
sFFmpegRun = sFFmpegRun & " -vcodec libx264 -vpre main -crf 29"

Case c32f
sFFmpegRun = sFFmpegRun & " -vcodec libx264 -vpre main -crf 32"

Case c32w
sFFmpegRun = sFFmpegRun & " -vcodec libx264 -vpre main -crf 32 -s 1280x720"

Case c32q
sFFmpegRun = sFFmpegRun & " -vcodec libx264 -vpre main -crf 32 -s 960x720"

End Select
sFFmpegRun = sFFmpegRun & " -vsync 2 -acodec copy -y " & cDC & s2File & cDC

'同期実行
WScript.Echo "bRun_FFmpeg(WSShel.Run(" & sFFmpegRun 
Call WSShel.Run(sFFmpegRun , 1, true)

'出来たか確認
If .FileExists(s2File) Then
sReturn = s2File
End if
Else
'パラメータ不正
WScript.Echo  "bRun_FFmpeg(引数が不正です。ERRERR"
End if
End with

Else
'パラメータ不正
WScript.Echo "bRun_FFmpeg(引数が不正です。iMODE:" & iMODE
End if
Else
'パラメータ不正
WScript.Echo "bRun_FFmpeg(引数が不正です。iMODE:" & iMODE
End if

sRun_FFmpeg = sReturn
End Function


0 件のコメント:

コメントを投稿