PT2の地デジ1440x1080tsファイルを自動CMカットして 1280x720にインターレースを保持したままリサイズしエッジ強調フィルタとWarpsharpフィルタを適用する。

  • TSファイルはmp4にしたい。
  • どうせするなら、サイズを小さく、500MB前後に納めたい
  • 1280x720のソースと同じサイズにリサイズしたい。
  • どうせエンコするなら、フィルタを適用したい
  • VFRと自動フィールドシフトを試したけど、Braviaでの再生でつっかかる部分がかなりある。自動でインタレ解除+FPSVFRするなんてムリと判断
    • インターレース保持派になりました。
    • Braviaのインタレ除去+再生時フィルタは超優秀。640x480のPCで見るとつぶれてるような動画が1.5mの場所でかなりくっきり見える。
      • 近づくとやっぱり補完してるなーっていうのはよくわかるんだけどね。
  • CMカットもしたい。
  • ロゴも除去したい。
  • 毎日これらの操作をやるなんてまっぴらごめん。完全自動化したい。

これらのことを全部やりたい。PT2で深夜アニメを録画できるものをすべて録画するのが目標。
朝起きると、CMカットされて圧縮されたMP4が生成されている、という状態が理想。




ようやく目的とする自動エンコシステムが完成したのでメモっておく。
誰か参照してくれるとうれしいな。

tsから目的とするStreamをDemuxする。

衛星放送でも特にスカパーe2なんかは複数の放送が一つのtsで送られてきて、とんでもないサイズのtsができることが多々ある。
それを自動エンコするためには、自動で目的とするStreamのみをDemuxしないといけない。

EPGTimer_Bonを使って、program.txtを出力するようにし、録画ファイル名マクロを次のようにする。
$SDYYYY$$SDMM$$SDDD$$STHH$$STMM$$STSS$01-[$ServiceName$]$Title$.ts
チューナーIDのマクロが無かったので、暫定的に01とし、番組名がファイルの先端につくようにした。

EPGTimer_BonのChSet2.txtをSとT両方で読み込む。サービス番号は左から4番目にあるので、サービス名と一致するサービス番号を取り出す。

BonTsDemuxでその取り出したサービス番号を -srv nnnn として送る。


これで、衛星放送多重tsStream問題が解決した。

自動CMカットは話題のLogoGuilloを使う。

http://loggialogic.blogspot.jp/2011/11/cm-logoguillo.html

とにかく、こちらのページ書いてあるように、Aviutlにm2v.vfsを導入しAviutlでロゴ解析をがんばって行い、ロゴの表示されたフレーム番号を記録し、LogoGuilloのパラメータ調節モードで開いて調節、テストという流れ。


出力形式は.avsとした。

ffmpegを使って、出力されたm2vファイルの形式を確認する。

結構、SAR4:3だったりSAR1:1だったり1440x1080だったり1920x1080だったり480x480だったり変な形式も多いので、
Width = w * sarx / sary
Height = h
ということでSAR1:1になるように計算し直す。
また、計算結果1920x1080になったら、1280x720にダウンスケールするようにした。

.program.txtから番組のジャンルを取得する

EPGTimer_Bon形式にすると、「ジャンル:」という項目が出力される。
その行に「アニメ」の文字列があった場合、アニメ用のWarpSharpフィルタ、エッジ強調フィルタをオンにする。

AVSを編集し、リサイズ・フィルタをかける

次に、出力された.avsを書き換える。
ちょうど#REPKEY_1#のように、「置換してください!」っていう感じのキーが一杯並んでたので、それらを置換するように。
http://www.h6.dion.ne.jp/~nytheta/dtv/encode-video.html
ここを参考に、

#REPKEY_1#を次に置換。

global AviUtl_plugin_directory = "O:\PT2\Encoder\avisynth\"
global AviUtl_plugin_copy = false
global AviUtl_plugin_debug = false
global AviUtl_plugin_thread = 6
LoadPlugin("O:\PT2\Encoder\avisynth\warpsharp.dll")
LoadPlugin("O:\PT2\Encoder\avisynth\delogo.dll")

####################################
# エッジレベル調整 MT ver 0.7
####################################
# i0 : 特性 default(10) range(-31,31)
# i1 : 閾値 default(16) range(0,255)
# i2 : 黒補正 default(0) range(0,31)
# i3 : 白補正 default(0) range(0,31)
function AU_edgelevelMT(clip clip,
\ int "i0", int "i1", int "i2", int "i3")
{
LoadAviUtlFilterPlugin(AviUtl_plugin_directory+"edgelevelMT.auf", "_AU_edgelevelMT", copy=AviUtl_plugin_copy, debug=AviUtl_plugin_debug, thread=AviUtl_plugin_thread)
#LoadAviUtlFilterPlugin2(AviUtl_plugin_directory+"edgelevelMT.auf", "_AU_edgelevelMT", copy=AviUtl_plugin_copy, debug=AviUtl_plugin_debug, thread=AviUtl_plugin_thread)
return clip._AU_edgelevelMT(
\ default(i0,10), default(i1,16), default(i2,0), default(i3,0))
}
# example:
# ConvertYUY2ToAviUtlYC()
# AU_edgelevelMT(10,16,0,0)
# ConvertAviUtlYCToYUY2()

# フィールド別にフィルタを適用するための関数
function FPNR(clip clip, string "filter")
{
clip
SeparateFields() #フィールド分割
Top = SelectEven #トップフィールド
Bottom = SelectOdd #ボトムフィールド
Top = Eval("Top." + filter)
Bottom = Eval("Bottom." + filter)
Interleave(Top, Bottom).Weave() #インタレースに戻す
return last
}

# プログレッシブでフィルタを適用するための関数
function FPProg(clip clip, bool parity, string "filter")
{
clip
Bob(b=0,c=0.5) #プログレッシブにする
Eval(filter)
parity ? AssumeTFF() : AssumeBFF()
SeparateFields()
SelectEvery(4, 0, 3) #フィールドの選択
Weave() #インタレースに戻す
return last
}

#REPKEY_30#を置換(ロゴファイルがあるときのみ)

#ロゴ除去
EraseLOGO(logofile="%l", pos_x=0, pos_y=0, depth=128, yc_y=0, yc_u=0, yc_v=0, start=0, fadein=0, fadeout=0, end=-1, interlaced=true)

#REPKEY_31#を置換

AssumeTFF()
parity = GetParity()
FPProg(parity, "Lanczos4Resize(%x,%y)")

#REPKEY_32#を置換(アニメフラグがオンのとき)

# WarpSharp
FPNR("WarpSharp(95,3,85,0)")

# エッジレベル調整
ConvertYUY2ToAviUtlYC()
FPNR("AU_edgelevelMT(9,20,5,2)")
ConvertAviUtlYCToYUY2()

aviutlのヘルパーをつかって操作。

AviUtl Control ver1.4を使う。
http://www.geocities.co.jp/aji_0/
まあ、書こうと思えばC#で書けたんだけど、めんどくさいんで再利用した。


C#だとこんな感じ。
.glが存在しないときに、GOPリストを作るからそのときにちゃんと止まるように設定。

                    object   ret = Auc("exec", "\"" + @"c:\aviutl\aviutl.exe" + "\"");
                    int   hwnd = (int)ret;
                    if (hwnd == 0) return;


                    if (File.Exists(Path.ChangeExtension(InputFileName, ".gl")))
                    {
                        Auc("open", hwnd.ToString() + " \"" + AVSFile + "\"");
                        Thread.Sleep(1000);
                    }
                    else
                    {
                        Auc("open", hwnd.ToString() + " \"" + AVSFile + "\"");
                        Thread.Sleep(5000);
                        while ((int)FindWindowEx(IntPtr.Zero, IntPtr.Zero, "#32770", "MPEG-2 VIDEO VFAPI Plug-In : 情報") != 0)
                        {
                            Thread.Sleep(1000);
                        }
                    }

                    int prof = 0;
                    Auc("setprof", hwnd.ToString() + " " + prof);
                    Thread.Sleep(1000);

                    Console.WriteLine("出力開始");
                    Auc("plugout", hwnd.ToString() + " 1 \"" + OutputFileName + "\"");
                    Thread.Sleep(1000);
  
                    Auc("wait", hwnd.ToString());

                    Auc("exit", hwnd.ToString());
                    Thread.Sleep(1000);

とりあえずやっつけでこんな感じ。ちょっとしたらC#スクリプトをきれいに書き直して貼るか。