fc2ブログ

PREV | PAGE-SELECT | NEXT

≫ EDIT

PowerShell + QSVで自動エンコード・自動CMカット part3

とりあえずCLIEnc4TSの設定までは終わっていると思うのですが、
このままでは何をやっているのかわかりにくいと思うので、
大雑把ではありますが説明したいと思います。



PowerShell + QSVで自動エンコード・自動CMカット part1
PowerShell + QSVで自動エンコード・自動CMカット part2
PowerShell + QSVで自動エンコード・自動CMカット part3


スポンサーリンク



CLIEnc4TSの非常に大雑把な解説
再度スクリプトの全体図を見てみます。



では「#処理実行」が何を行っているか説明します。
if文がありますが、これは作業フォルダ内にTSが存在するか確かめています。
存在する場合以下の処理が行われます。

RenameTS
これは作業フォルダ内のTSファイルにリネームを行う関数です。
ファイル名に記号や半角スペースが存在すると処理が停止してしまうので、
エラーが起きない文字列に置き換えてから処理を開始します。

$TargetPass = @($(Get-ChildItem $Global:WorkShop -Filter *.ts).FullName)
これは配列$TargetPassにフォルダ内のTSパスを設定するスクリプトです。

次のfor文では、$TargetPassに含まれるTSパスを順番に関数SubRoutineに渡して実行
を繰り返しています。

もしTSファイルが存在しない場合は「else」以下の処理、
TSが存在しない事のメッセージが表示される事になります。

関数説明
RenameTS
作業フォルダ内のTSのファイル名を処理エラーとならないファイル名に変更する
MakeTrimeCode自動CMカットの中核。本編と判断された区間をトリム情報としてavsファイルに書き込む。
SubRoutine「処理の流れ」で書いた1~12を行う。エンコードの本処理部分。
メインルーチンはSubRoutineを繰り返すだけで、SubRoutineが中心となります。
それではまずRenameTSから見て行きましょう。

RenameTS
これは
【PowerShell】指定フォルダからファイル名を取得しリネームする の改良版で、
この関数単体でも動きます。コマンドで動く一括リネームツールとしても使えるかも?
$WorkShopは作業フォルダのパス、$RenameExtはリネームする拡張子の設定です。
.tsの他に.txtや.errがあるのはEDCB利用者の為。

$SerchWordの配列には置換対象としたい単語、文字を設定して下さい。
上から順に置換されるので、優先したい複合文字を上に設定します。
エラーとなる記号は大体入っていると思います。

$KeyHushの連想配列には置換対象と変換したい文字を設定して下さい。
例えば「"♡" = "_" ;」とすると、ファイル名含まれる「」は「_」になります。

流れとしては$SerchWord配列最初の要素を全てのTSファイル名に対して検索、
$KeyHushから$SerchWordに対応する要素に置換する、
これを$SerchWordの最後の要素になるまで繰り返す事になります。
「ロゴファイルを選択するための放送局名設定」のやり方と似てますかね。


SubRoutine
MakeTrimeCode飛ばしてこちらから。設定で説明した部分も飛ばします。
function SubRoutine($Source)
まずこの$Sourceは何かというと引数(ひきすう)で、

SubRoutine $TargetPass[$i]
$Source $TargetPass[$i]、TSのパスが格納される事になります。

なので、
$SrcPass = "$Source"
$SrcPass$TargetPass[$i]が格納されます。
このように"引数"を使用して関数内に外部の値を渡す事ができます。

・移動先・出力場所など
次のスクリプトはこの$SrcPassから新たな変数を作成します。
$SrcPassWoExt = $SrcPass.Replace(".ts", "")
$SrcParent = Split-Path $SrcPass -Parent
$SrcLeaf = Split-Path $SrcPass -Leaf
$SrcName = $SrcLeaf.Replace(".ts", "")
$SrcPassWoExt$SrcPassから拡張子を削除した値
$SrcParent$SrcPassの親フォルダ

$SrcLeaf$SrcPassの拡張子を含めたファイル名
$SrcNameはファイル名のみ
を設定します。

$OUT_avs  = $SrcPass.Replace(".ts", ".avs") 他省略
各ファイルを出力する際ファイル名をつける時に使用します。

・放送局名ごとによる制御
選択した放送局のロゴで個別に何か制御できる。
枠組みを作っただけで機能は特に無いです。消してもOK。

・制御に関する設定
よく設定しそうな項目はここにまとめています。
$NoCut_Switch値を1にするとCMカットは行わず単純にエンコードします。
$NoCutkey_Switch値を1にすると$NoCutkeyに設定した文字列がTSファイル名に存在場合、
CMカットは行わず単純にエンコードします。
$NoCutkeyCMカットを行わない様にするキーワード設定。(放送局/番組名など)
$Refusekey_Switch値を1にすると$RefuseKeyに設定した文字列がTSファイル名に存在する場合、
エンコードせずTrashTSに移します
$RefuseKeyエンコードを行わない様にするキーワード設定。(放送局/番組名など)
$NoDel_Switch値を1にすると処理終了後の残骸ファイルの移動・削除を行いません。
$MoveLogFile設定された項目は削除されずに移動されます。ログファイルなどが対象
$DeleteExt処理終了後の残骸ファイルを対象として、指定拡張子のファイルを削除します。
Switch系は0か1を設定します。
どうしても自動CMカットが失敗する場合は$NoCut_Switchの値を1にして、
単純エンコードしたり、他に$Refusekey_SwitchでNHKの様にCMがなかったり、
tvkのようにロゴがない局はCMカットしないようにできます。

$NoDel_Switchはデバックの際に使う程度なので基本0で問題ないです。

・ここから処理を開始します。
実際にここからTSファイルの操作を開始します。
以前の記事で紹介した「QSVEncC.bat」と似通った構成になっていると思います。

・無効キーワード設定実行
上で説明した$Refusekey_Switchの処理を行う部分です。
TSを移動した後は呼び出し元に戻ります。

・TsSplitter処理
そのまんまTsSplitterの処理です。オプション設定はここで変更して下さい。

・Mpeg2-TSの解析
MediaInfoを使用してソースTSの解析を行います。
目的は再生時間の取得、音声/字幕の個数を取得します。

・parserよりソースからAAC抽出
ts_parserを用いてAACを抽出します。parserのオプション設定は以下を記事を参考。

AviSynth音声メモ | すなふりり
出力したaacを$Out_parser_aacに設定。複数トラックに対応しています。

・FAW偽装→解除 ディレイ適用
$Out_parser_aacに格納されているトラック全てにディレイ適用をし、
適用されたaacファイルは$Out_fawcl_aacに格納されます。

・Avs作成
お気づきかと思いますが、このスクリプトではDGindexは使用しません。
LSMASHSource使用することによりTSを直接読みこむ事が可能です。
aacに関しては上のts_parserで、avsに関してはpowershellで作成する感じになりました。
$Avs_contentがavsファイルの中身になります。シンプル!

$Avs_content = @"
LWLibavVideoSource("$Out_TsSplitter")
KillAudio()



return last
"@
@"~"@で囲むと改行含めて文字列として扱われます。
KillAudio()
return last
の間の空行は意味があり、
自動CMカットした時のTrim情報が記述される事になります。

必要であれば、Avisynthのコマンドを追加することもできるでしょう。

・CMカット処理
$Cut_conditionの真偽でCMカットするかどうかを判断します。

・AAC→WAV  / Soxによるのゲインアップ
なぜこれを行うかというと、無音情報の精度を高めるためです。
許容範囲内の音量/長さであれば無音区切りのタイムコードが出力されるので、
本編内でもそのタイムコードが発生する可能性はあります。
そこで音声全体のボリュームを上げれば、
許容範囲外の音量となり本編内での無音区切り発生の確率を下げる事ができます。

弱点としては、CMとCMの間などにあるノイズの音量も上がり、
許容範囲外の音量となる可能性もあるので、ほどほどにしておく必要があります。
Soxはaacを読み込めないためfaadでwavにしてからSoxで音量をあげます。

なおこのwavは無音区切り判別のために使用するもので最終的には削除します。
mp4に格納するわけではないのでそこは安心してください。


・無音区切りファイル作成
&$wave2chapter -s 1000 -m 300 -p 2 -i "$Out_wav" -o "$Out_chap_txt"
wave2chapterのオプションは重要です。
CMカットが上手くいかない場合、ここを変更すると上手く可能性があります。
「-s 数値」は許容する音量を設定します。1000で大体-30dBまでは無音と判断されます。
「-m 数値」は必要とする長さ(ms)です。
CMとCMの間等の長さはだいたい1000msなので、それ以下に設置して下さい。
100msなど短すぎると本編中にも無音区切りが発生し、精度が落ちます。
500ms以上と長すぎるとCMとCMの間に存在するノイズに邪魔される可能性があります。

一応CMカットされているが一部15秒CMがまるごと残っている場合は、
無音情報が正常でないと考えられます。このような時は、
soxでゲインアップしたwavを波形編集ソフト
SoundEngine Freeで確認すると
なぜ失敗したのかの原因を調べる事ができます。

・logoframe実行

&$logoframe $Out_avs -logo $LgdPass -oa $Out_logo_txt -onlevel 21 -ymin 16 -ymax 235
logoframeは上記で作成したavsとロゴファイルを読み込んでロゴ表示区間の
タイムコードを吐き出します。本来logoframeは結構時間がかかる処理なのですが、
TSソースを「LWLibavVideoSource」で読みこむ事ですぐ終了します。
30分アニメであれば1~2分でしょうか。

・Trimコード作成→Avs書き換え
これで無音情報とロゴ情報が出来たので関数MakeTrimCodeでトリムコードを計算します。

・aacをaaceditでトリム適用(avs読み込み)
MakeTrimCodeよりavsにTrim情報が書かれています。
その情報を用いて$Out_fawcl_aacに含まれる全ての音声トラックに対し、
トリムを適用して$Out_trim_aacに格納します。
これでCM音声がカットされたaacファイルが作成されました。

・QSVEncCエンコード

&$QSVEncC --quality best --cqp 24:26:27 --gop-len 300 --bframes 3 --sar -16:-9 -i $Out_avs -o $Out_264
次にQSVエンコードです。オプションとかはご自由に。

・字幕ファイル抽出・トリミング
MediaInfoで調べた字幕の有無より、
$Caption2Ass字幕ファイルを抽出します。
…ただ存在すると判断されても中身が無い場合もあるのでいまいちですが。
もし自動CMカットが行われているのなら、
$srtsyncを使用して字幕情報をトリム情報を元にカットします。

・mp4boxで結合
あとは264ファイル、aac、あれば字幕情報をmp4コンテナに格納して動画作成完了です。
ただ字幕ファイルがある場合やCMカットされていた場合の場合分けが必要です。
また、音声が複数ある場合は全て「-add」で追加する必要が有ります。

・残骸ファイル移動・削除
作成された不要ファイルの後処理です。
ソースTSやログファイルは削除したくないので移動し、残ったものは完全削除します。

・SCRename実行
最後にSCRenameでしょぼいカレンダーより取得した番組情報でリネームします。

SubRoutineはここらで終了です!計算部で多少な複雑なMakeTrimCodeの説明に移ります。


MakeTrimCode
さてさてここが自動CMカット計算の中心部分です。
SubRoutineから起動し、無音/ロゴ情報を処理します。


・各種設定項目
ここはユーザーが値を設定出来る部分です。

$ChapCut_Start
指定したフレーム数だけ加算します。マイナスだと全てのStartが早く始まります。
$ChapCut_End  指定したフレーム数だけ加算します。マイナスだと全てのEndが早く終わります。
$LogoCut_Start 上と同じ。LogoTrim用上と同じ。
$LogoCut_End 上と同じ。LogoTrim用
$ChainTrim あるTrimのEndとその次のTrimのStartの差が設定フレーム以下であれば、
双方削除し繋げます。本編途中で分割が起きたときの対策になります。
$AddLine 作成したTrimコードをAVSファイルの何行目に追加するかの設定。
powershellは0から数えるので3だと4行目に追加されます。
$LogoRange_Loose  ChapterTrimがLogoTrimよりも、広い範囲の時に有効です。
指定した値まではChapterTrimを優先します。(300より高いを推奨)
$LogoRange_Strict ChapterTrimがLogoTrimよりも、狭い範囲の時に有効です。
Looseより小さい値にし、LogoTrimを優先させます。
CMが終わってから本編が始まる十数フレームは、
本編映像が存在しても音声が全く無い場合があります。
wave2chapterで出力されるタイムコードをそのまま使用すると、
CM終了直後の本編映像が少し切れたりするので
それを避ける為に、
強制的に開始・終了位置を
変更する設定場所が$ChapCut_Start等の変数です。

トリム間が指定した値以下なら結合するようになっていますが、
その値を設定するのが
$ChainTrimになっています。初期値は1000フレームですね。
例えば、以下に実際のChapterTrimでStart、End、Start…と並んでいます。
931(S)
4162(E)
4163(S)

6849(E)
8964(S)
26344(E)
28148(S)
43651(E)
43652(S)

47390(E)
931(S)
6849(E)
8964(S)
26344(E)
28148(S)
47390(E)
この様に赤い部分が削除されトリムが整理される事になります。
間違って本編内で分割があってもその差が指定した値以下なら修正されるので便利です。

$AddLineはそのままで、作成したTrimコードをAVSの何行目に書き込むかの設定です。
他の設定を上書きしないようにして下さい。

Trimを合成する際は、基本的にはChapterTrimを優先して取得します。
$LogoRangeは差の範囲を設定する変数です。以下に実際のTrimの例を。緑は予告です。
ChapterTrim LogoTrim合成結果
921(S)
6839(E)
8954(S)
26334(E)
28138(S)
47380(E)



911(S)
7177(E)
8943(S)
26358(E)
28124(S)
47397(E)
49163(S)
49405(E)
921(S)
7177(E)
8954(S)
26334(E)
28138(S)
47380(E)

49163(S)
49405(E)
判断方法は以下の不等号が真の場合にChapterTrimを取得する感じになっています。
・Startの例(映像カット防止の為なるべく小さい値が良い)

911 + $LogoRange_Loose(400) > 921 911 - $LogoRange_Strict(100)
・Endの例(映像カット防止の為なるべく大きい値が良い)
7177 + $LogoRange_Strict(100) > 6839 7177 - $LogoRange_Loose(400)

Startの例は真ですが、もしLogoTrimの"911"が500"なら範囲外となりLogoTrimの方を取得。
Endの例は偽となっているのでLogoTrimが取得されています。
ChapterTrimを優先する理由は、音なのでどの局でも似たような部分で区切られる為です。

・関数一覧
MainFilm 引数が指定したフレーム数なら本編と判断します。
Global:SumCM 引数が指定したフレーム数ならCMのまとまりと判断します。
StrictTest 引数が指定したフレーム数ならCMと判断します。
FailRangeTest CMとCMの間はCMと判断する関数です。
FailSumTest Global:Fail内の要素を順次加算、テストし最終的にCMと判断されない要素を取り入れます
バグが存在しますが、ほとんど使わないのでそのままになってます。
ExcludeCM CMを除去する関数です。
TrimDelete あるTrimのEndとその次のTrimのStartの差が設定値以下であれば双方削除します。
TrimRangeChg Start/Endが数フレーム遅い為、カットを早めます。
TrailerTest 予告が存在しているかの確認に使用します。
SearchTrailer 音声のみで予告を取得する際に使用します。微妙。
TrimCompose 無音とロゴ情報の作成したトリム情報を一つのトリムに合成します。
LogoTest 試行対象がLogoTrim範囲内であればLogoTestResultに1を代入します。



・秒換算→フレーム変換
まず$ChapterLineとはwave2chapterが出力した内容を配列として格納したものです。
00:00:19.855
00:00:34.854
00:01:06.411
00:01:16.897
省略
上の様に無音の終わりのタイムコードが入っています。
ここではこれをフレーム換算して利用しやすい形にしています。

・ChapterLineからStartとEndへの振り分け、Diffにそれら差を格納
wave2chapterのオプションで無音の終わりが記録するようになっています。
なのである要素が映像の終わりで、その前の要素+1が始まりとなります。
そしてその差が$Diffに格納されこの数値でCMか本編か判断する事になります。

・LogoLineを扱える形に変換する
logoframeの出力した内容が配列として格納されています。
こちらはフレーム換算する必要は無いのですが、無駄な情報があるので除去しています。

・$Diffに存在するStartとEndの差を利用して、本編情報を抽出する
基本的には$Diffで判断して本編映像なら$Startと$Endのフレームを取り込む感じです。
最初のif文は$Diffが本編映像であるか、$Diff[-1]と等しい(最終行)か、
$Global:LogoTestResultが1であるか調べています。

・ChaptertTrimとLogoTrimの差の検証
これは結構大切な処理です。以前台風があった時L字テロップが出てlogoframeが正常に
動かなくなることが有りました。ロゴが通常時より小さくなるためです。
その状態で合成すると、正常なChapterTrimも無意味になってしまいます。
無音とロゴ共に正常であればほぼ同じフレーム数となりますから、
LogoTrimでのフレーム数の合計がChaptertTrimの80%以下となるならロゴの情報を
使用しないようにしました。

・漏れの補完と予告の追加
TrimDeleteはLogoTrimを整理するためのものです。ChapterTrimと合成する際に必要となります。
TrimRangeChgは各Trimを手動でフレーム追加する際に使います。

予告については基本的にlogoframeが取得してくれますが、
SearchTrailerlogoframeが使用出来ない時、
無音情報だけで予告取得しようと考えたものです。大体予告の後に10秒間の提供があるので、
提供とその前の要素を取得する感じになっています。しかし提供が発見出来ない場合もあり、
その場合はED後全て取り込むお粗末な感じになっています。
このことからも無音とロゴ情報併用してCMカットした方が良いです。
その後TrimCodeを作成して、avsに書き込んでこの関数は終了です。

かなり簡単な説明ですが以上です。


最後に
とりあえずこのシリーズは以上となります。
いい感じにエンコード&カット出来た方も、そうでない方もお疲れ様でした。
また新たな条件や基準を使えばより精度を上げられるかもしれません。
ではでは~

関連記事
スポンサーリンク

| エンコード | 21:29 | comments:0 | trackbacks:0 | TOP↑















非公開コメント

http://higitune.blog106.fc2.com/tb.php/133-2eed65b9

PREV | PAGE-SELECT | NEXT