追記:情報が古くなっておりますので、以下の記事で参考にならない部分が出ていると思いますが、そのあたりは各自で読み替えてくださいませ。
引っ越しして3ヶ月ほどになります。今まで使っていた録画serverは前宅で稼働中なので、新居での録画serverをどうしようかなと、考えていた時期に、この記事(【Windows】無料ソフトウェアで手っ取り早くpt2/pt3で作成したTSをH.264エンコードする – UbuntuによるEco Linuxサーバ構築記)を見まして、なるほど、エンコードをWINマシンでやるなら、そこそこのlinux-serverでいいじゃまいか。と気がついたわけで(ぁ
それで、さくっと、こいつ(Amazon.co.jp: HP ProLiant MicroServer データー保存に 500GB マイクロサーバー N54L PROLIANT-500: パソコン・周辺機器)を購入し、録画serverとしたわけ何ですが、、、windows8.1で半自動でゴリゴリとエンコードしてくれるシステムなんぞしらんぞ。ということで、いろいろと調べてみました。aviutlとやらでエンコードできるっぽいけど、エンコード自体は裏でやってもらってかまわないんだけどねぇ、と思っていて、今まで使っているTMPGEnc MPEG Smart Renderer 4を使いたいなと思うと、aviutlを使わないエンコードを。となる。
ということで、ffmpegを動かせるパッチなり、スクリプトを組めばいいじゃん?と言うことになりました。
無謀ですね。馬鹿ですよw私wだって、スクリプト組もうってwindows8.1でどうやってスクリプト組むのか全く知らないのにwww Linuxなら、bashで組めばいいかーと解ってるので気楽に行くんですが。
まぁ、思い立ったので、さくっとbashでひな形を作って、それをwindows8.1で動くスクリプト言語に移植しようと。
そこで、さっきの記事にもどると、どうやらpowershellという機能でスクリプトが組めるらしい。さぁ、始めようw初めてのpowershellだよ。
ってなことで、作りました。丸一日かかったよ。。。
先に断っておきます。この記事は筆者のメモとしての機能が第一です。他のことは知りませんw。
powershellは使ったことが全くないので、習慣的にこうやってる、などは全く無視(というか知らない)しておりますし、プログラムで飯を食ってるわけでも無いので、エラーだったり、何じゃこりゃ、という部分があって当たり前。ということを認識してこれ以降を読んでください。
以下に挙げたスクリプトはエンコードしたいファイルが詰まったフォルダにコピーして実行する事を前提に書いています。
- スクリプトの置いてあるフォルダのファイルリストを取得し、該当ファイルを作業フォルダにコピーする
- エンコード
- 完成したファイルをスクリプトの置いてあるフォルダに作ったmp4filesというフォルダに移動
- エンコードした元ファイルをencodedフォルダに移動
という流れです。
なぜに、作業フォルダに移動するかというのは、以下の二つの理由から。
- 特殊文字([、]、*、など)が付いてないファイル名に変換して作業をしたかった。
- ネットワークドライブ上にあるファイルのエンコードは通信速度が問題になるかも?
あ、多重起動の処理を書いてないですね。まぁ、大丈夫か、書いていないことを覚えてればw
## 環境に合わせて下記の環境変数は修正してください。 # ffmpegの実行ファイル $FFMPEG="D:\EncodeTools\ffmpeg\bin\ffmpeg.exe" # 作業フォルダ $PATH=Split-Path $FFMPEG -Parent $TMP_DIR=Join-Path $PATH "..\tmp" #\tmpフォルダが存在するかどうかを判定する。 if (Test-Path $TMP_DIR){ #存在するので何もしない。 }else{ #存在しないので、フォルダを作る。 New-Item "$TMP_DIR" -type directory } # TSファイルが置かれているディレクトリ $TARGET_DIR=Split-Path $script:myInvocation.MyCommand.path -parent # ffpresetの選択 $PATH=Split-Path $FFMPEG -Parent $FFPRESET=Join-Path $PATH "..\presets\libx264-hq-ver2.ffpreset" -Resolve #入力ファイルの拡張子 $IN_EXT=".m2t" # エンコードオプション(ビデオ回り) #$FFMPEG_OPT_VIDEO="-s 1280x720 -r 30000/1001 -vcodec libx264" $FFMPEG_OPT_VIDEO="-r 60000/1001 -vcodec libx264" #解像度(録画時の解像度をそのままつかうなら、「-1」と書く) #$SIZE="-s 1280x720" $SIZE="-1" # エンコードオプション(音声回り) $FFMPEG_OPT_AUDIO="-acodec copy -absf aac_adtstoasc" # スレッド数。CPUのコア数と同じにすればいいと思います。 $FFMPEG_OPT_THREADS="12" # ファンクション定義 function h264enc { if ($args.count -ge 1) { $arg="-y -i $TMP_DIR\'$args'$IN_EXT -f mp4 -movflags faststart $SIZE $FFMPEG_OPT_VIDEO -fpre $FFPRESET $FFMPEG_OPT_AUDIO -threads $FFMPEG_OPT_THREADS -pass 1 $TMP_DIR\'$args.mp4'" powershell -Command "$FFMPEG $arg" $arg="-y -i $TMP_DIR\'$args'$IN_EXT -f mp4 -movflags faststart $SIZE $FFMPEG_OPT_VIDEO -fpre $FFPRESET $FFMPEG_OPT_AUDIO -threads $FFMPEG_OPT_THREADS -pass 2 $TMP_DIR\'$args.mp4'" powershell -Command "$FFMPEG $arg" } else { "エンコード対象のファイルを指定してください。" } } cd $TARGET_DIR Get-ChildItem | ForEach-Object { $FNAME=$_.name $OUTNAME=$_.Basename #拡張子を除いたファイル名を取得 $EXTENSION=$_.extension #拡張子を取得。 #\encodedフォルダが存在するかどうかを判定する。 if (Test-Path encoded){ #存在するので何もしない。 }else{ New-Item "encoded" -type directory #存在しないので、フォルダを作る。 } #\mp4filesフォルダが存在するかどうかを判定する。 if (Test-Path mp4files){ #存在するので何もしない。 }else{ New-Item "mp4files" -type directory #存在しないので、フォルダを作る。 } #拡張子に.m2tがあれば、エンコード実行 if ($EXTENSION -eq $IN_EXT){ $TMPNAME=Get-Date -Format "yyyyMMddHHmmss" #作業用一時ファイル名に使う日時を取得 #write-output $FNAME Copy-Item -LiteralPath "$FNAME" "$TMP_DIR\$TMPNAME$IN_EXT" #m2tファイルを一時フォルダにコピーする #録画ファイルの解像度を使う場合 if($SIZE -eq "-1"){ #ffprobeを使ってstreamのjsonデータを取得し、その中のwidthとheightから解像度を拾う write-output "$PATH\ffprobe.exe -show_streams -print_format json $TMP_DIR\$TMPNAME$IN_EXT 2>`$null" [string]$TMPJSONDATA=PowerShell -Command "$PATH\ffprobe.exe -show_streams -print_format json $TMP_DIR\$TMPNAME$IN_EXT 2>`$null" $JSONDATA=($TMPJSONDATA | ConvertFrom-Json) [string]$W=$JSONDATA.streams.width [string]$H=$JSONDATA.streams.height $SIZE="-s " + $W.trim() + "x" + $H.trim() } h264enc $TMPNAME #エンコード Move-Item -LiteralPath "$FNAME" "$TARGET_DIR\encoded\" #エンコード終了フォルダに移動する。 Move-Item -LiteralPath "$TMP_DIR\$TMPNAME.mp4" "$TARGET_DIR\mp4files\$OUTNAME.mp4" #mp4ファイルを作業フォルダから出力フォルダへ移動 Remove-Item "$TMP_DIR\$TMPNAME$IN_EXT" #掃除 Remove-Item "ffmpeg2pass-0.log" #掃除 Remove-Item "ffmpeg2pass-0.log.mbtree" #掃除 #write-output $fname }else{ #存在しない #write-output $fname } }
(追記 2014/12/02)
コメントでjson動かないよ?って事を気がつかされまして,win7で上記のスクリプトを動かしたところ,ConvertFrom-Jsonの所でエラーが出て止まりました.
win8では動いてるんだけどな.なんでだろう.
ということで,jsonではなく,win版grep,sedで書き直したのが以下.他にもちょっと書き足した部分もあるけどね
こちらのビデオ周りのところで「-vcodec libx264」ってのが無くなってるのですが,ここは,ffpresetファイルの一行目に「video=libx264」と付け加えることで補っています.
## 環境に合わせて下記の環境変数は修正してください。 #入力ファイルの拡張子 $IN_EXT=".m2t" # ffmpegの実行ファイル $FFMPEG="D:\EncodeTools\ffmpeg\bin\ffmpeg.exe" # 作業フォルダ $PATH=Split-Path $FFMPEG -Parent $TMP_DIR=Join-Path $PATH "..\tmp" #\tmpフォルダが存在するかどうかを判定する。 if (Test-Path $TMP_DIR){ #存在するので何もしない。 }else{ #存在しないので、フォルダを作る。 New-Item "$TMP_DIR" -type directory } # TSファイルが置かれているディレクトリ $TARGET_DIR=Split-Path $script:myInvocation.MyCommand.path -parent # ffpresetの選択 $PATH=Split-Path $FFMPEG -Parent $FFPRESET=Join-Path $PATH "..\presets\libx264-hq-ver2.ffpreset" -Resolve #$FFPRESET="-preset medium -b:v 1280k" # エンコードオプション(ビデオ回り) #$FFMPEG_OPT_VIDEO="-s 1280x720 -r 30000/1001 -vcodec libx264" $FFMPEG_OPT_VIDEO="-r 60000/1001" #解像度(録画時の解像度をそのままつかうなら、「-1」と書く) #$SIZE="-s 1280x720" $SIZE="-1" # エンコードオプション(音声回り) $FFMPEG_OPT_AUDIO="-acodec copy -absf aac_adtstoasc" # スレッド数。CPUのコア数と同じにすればいいと思います。 $FFMPEG_OPT_THREADS="0" # ファンクション定義 function h264enc { if ($args.count -ge 1) { $arg="-y -i $TMP_DIR\'$args'$IN_EXT -f mp4 -movflags faststart $SIZE $FFMPEG_OPT_VIDEO -fpre $FFPRESET $FFMPEG_OPT_AUDIO -threads $FFMPEG_OPT_THREADS -pass 1 $TMP_DIR\'$args.mp4'" powershell -Command "$FFMPEG $arg" $arg="-y -i $TMP_DIR\'$args'$IN_EXT -f mp4 -movflags faststart $SIZE $FFMPEG_OPT_VIDEO -fpre $FFPRESET $FFMPEG_OPT_AUDIO -threads $FFMPEG_OPT_THREADS -pass 2 $TMP_DIR\'$args.mp4'" powershell -Command "$FFMPEG $arg" } else { "エンコード対象のファイルを指定してください。" } } cd $TARGET_DIR Get-ChildItem | ForEach-Object { $FNAME=$_.name $OUTNAME=$_.Basename #拡張子を除いたファイル名を取得 $EXTENSION=$_.extension #拡張子を取得。 #\encodedフォルダが存在するかどうかを判定する。 if (Test-Path encoded){ #存在するので何もしない。 }else{ New-Item "encoded" -type directory #存在しないので、フォルダを作る。 } #\mp4filesフォルダが存在するかどうかを判定する。 if (Test-Path mp4files){ #存在するので何もしない。 }else{ New-Item "mp4files" -type directory #存在しないので、フォルダを作る。 } #拡張子に.m2tがあれば、エンコード実行 if ($EXTENSION -eq $IN_EXT){ $TMPNAME=Get-Date -Format "yyyyMMddHHmmss" #作業用一時ファイル名に使う日時を取得 #write-output $FNAME Copy-Item -LiteralPath "$FNAME" "$TMP_DIR\$TMPNAME$IN_EXT" #m2tファイルを一時フォルダにコピーする #録画ファイルの解像度を使う場合 if($SIZE -eq "-1"){ $bar=powershell -Command "$PATH\ffprobe.exe -i $TMP_DIR\$TMPNAME$IN_EXT 2>&1" $pat="[0-9]{3,4}x[0-9]{3,4}" $regex=[regex]$pat $xy=$regex.Matches($bar) | foreach { $_.Value } $SIZE="-s " + $xy #ffprobeを使ってstreamのjsonデータを取得し、その中のwidthとheightから解像度を拾う # write-output "$PATH\ffprobe.exe -show_streams -print_format json $TMP_DIR\$TMPNAME$IN_EXT 2>`$null" # [string]$TMPJSONDATA=PowerShell -Command "$PATH\ffprobe.exe -show_streams -print_format json $TMP_DIR\$TMPNAME$IN_EXT 2>`$null" # $JSONDATA=($TMPJSONDATA | ConvertFrom-Json) # [string]$W=$JSONDATA.streams.width # [string]$H=$JSONDATA.streams.height # $SIZE="-s " + $W.trim() + "x" + $H.trim() } #処理時間測定 $sw = New-Object System.Diagnostics.StopWatch $sw.Start() h264enc $TMPNAME #エンコード Move-Item -LiteralPath "$FNAME" "$TARGET_DIR\encoded\" #エンコード終了フォルダに移動する。 Move-Item -LiteralPath "$TMP_DIR\$TMPNAME.mp4" "$TARGET_DIR\mp4files\$OUTNAME.mp4" #mp4ファイルを作業フォルダから出力フォルダへ移動 echo "EncodeFile=$OUTNAME.mp4" >> Encodelist.txt #処理時間計測停止 $sw.Stop() echo "所要時間:`t" $sw.Elapsed.ToString() >> Encodelist.txt Remove-Item "$TMP_DIR\$TMPNAME$IN_EXT" #掃除 Remove-Item "ffmpeg2pass-0.log" #掃除 Remove-Item "ffmpeg2pass-0.log.mbtree" #掃除 "******************************************" "*************Finish Encodeing*************" "******************************************" #write-output $fname }else{ #存在しない #write-output $fname } }