録画映像のエンコード環境

投稿者:arrumis

追記:情報が古くなっておりますので、以下の記事で参考にならない部分が出ていると思いますが、そのあたりは各自で読み替えてくださいませ。

 

引っ越しして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は使ったことが全くないので、習慣的にこうやってる、などは全く無視(というか知らない)しておりますし、プログラムで飯を食ってるわけでも無いので、エラーだったり、何じゃこりゃ、という部分があって当たり前。ということを認識してこれ以降を読んでください。

以下に挙げたスクリプトはエンコードしたいファイルが詰まったフォルダにコピーして実行する事を前提に書いています。

  1. スクリプトの置いてあるフォルダのファイルリストを取得し、該当ファイルを作業フォルダにコピーする
  2. エンコード
  3. 完成したファイルをスクリプトの置いてあるフォルダに作ったmp4filesというフォルダに移動
  4. エンコードした元ファイルを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
    }
}
徒然なる日記|2014年10月31日|5:57 PM|録画映像のエンコード環境 はコメントを受け付けていません。			



コメントは受け付けていません。

« »