AVSLibのインストール
AVSLib は、AviSynth 用の拡張ライブラリです。詳しいことはわかりませんが、配列(array)を使えるようになったりするようです。
AVSLib については、いずれ AviSynth Wiki でも紹介するつもりですが、ここでは AVSLib のインストール方法だけを簡単に紹介します。これは、AVSLib :: Installation Instructions(英文)を、かなり簡略化したものです。
- SourceForge.net: Project Info - AVSLib からダウンロードしたアーカイブを解凍。
- フォルダを開いて、setup.vbsの場所を確認。
- setup.vbsをダブルクリックして実行。以下のファイルが作成される。
- rootdir.avsi; 修正してはいけない。
- template.avs; AVSLibを利用するときは、このavsファイルの内容をスクリプトにコピペする。
- AVSLibの説明書へのショートカット。
rootdir.avsi と template.avs は、setup.vbs と同じフォルダに、ショートカットはデスクトップに作成されます。
デスクトップにショートカットを作成したくない場合は、setup.vbs の 95 行目の行頭に「'」(アポストロフィ)を付ければ(たぶん)OKです。
例
'MakeShortcut ShortcutDest, SpFolder, "AVSLib-Docs", ....
これらのファイルは、手動で作成することもできます。
rootdir.avsi
global avslib_root = "X\"
template.avs
Import("X\headers\avslib-h.avsi")
rootdir.avsi と template.avs の内容は、それぞれ上記のようになります。「X」は AVSLib のフォルダ(setup.vbs があるフォルダ)のパスに置き換えてください。
あとは、template.avs の中の Import 文を、そのままスクリプト内にコピー&ペーストすれば、 AVSLib を使用できるようになります。Import 文を貼り付ける場所は、AVSLib のコマンドよりも前にしてください。
使用例
Import("C:\foo\headers\avslib-h.avsi") # template.avs より
AviSource("C:\capture\bar.avi")
EditDelete(2,2)
Project N: 023 - 文字雨(関数化してみる)
前回のスクリプトは、あまりにも長すぎて、とても実用的なものではありませんでした。とりあえず今回は、文字を縦書きにする部分を関数にして、少し簡略化してみたいと思います。
last = BlankClip(width=320, height=240)
last = last.Subtitle("A", 4,0, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("B", 4,13, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("C", 4,26, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("D", 4,39, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
last = last.Subtitle("E", 4,52, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
return last
これは前回の 2 つ目のスクリプトから、0 フレーム目の部分だけを抜き出して、クリップの変数を明示したものです。AviSynth では、変数が省略された場合、直前に処理されたクリップという意味の特別な変数 last が割り当てられます。これは、ただそれを省略せずに書いただけです。ちなみに、この場合、「return last」は省略することができません。
# 背景
bg = BlankClip(width=320, height=240)
# 固定値の指定
font = "Courier NEW" # フォント
font_size = 18 # フォントのサイズ
font_color = $6FE47A # フォントの色
halo_color = $11B301 # 文字の縁の色
# 縦書き
c1 = bg.Subtitle("A", 4,0, 0,0, font, font_size, font_color, halo_color)
c2 = c1.Subtitle("B", 4,13, 0,0, font, font_size, font_color, halo_color)
c3 = c2.Subtitle("C", 4,26, 0,0, font, font_size, font_color, halo_color)
c4 = c3.Subtitle("D", 4,39, 0,0, font, font_size, font_color, halo_color)
c5 = c4.Subtitle("E", 4,52, 0,0, font, font_size, font_color, halo_color)
# return 文
return c5
次に、フォントやフォントサイズなどの固定された値を、あらかじめ変数指定してみました(4 ~ 7 行目)。クリップの変数もわかりやすいように(?)、それぞれ違う名前を割り当ててみました。
Subtitle フィルタの x, y, first_frame, last_frame と 5つの文字(文字列)は、毎回、別の値を指定する可能性があります。そのため、これらの値(+clip)は、関数の引数として指定できるようにします。
つまり、引数リストの中身は、以下のようになります。
- c: 入力クリップを受け付ける部分。clip 型。
- x, y: 文字の位置を指定。Subtitle フィルタの x と y 。int 型。
- start, end: Subtitle フィルタの first_frame と last_frame。int 型。
- t1 ~ t5: 文字を指定。string 型。
では、関数化してみましょう。関数名は「tategaki」にして、引数リストと関数のコマンドを指定します。
function tategaki(clip c, int x, int y, int start, int end,
\ string t1, string t2, string t3, string t4, string t5)
{
# 固定値の指定
font = "Courier NEW" # フォント
font_size = 18 # フォントのサイズ
font_color = $6FE47A # フォントの色
halo_color = $11B301 # 文字の縁の色
# 縦書き
c1 = c.Subtitle(t1, x,y, start,end, font, font_size, font_color, halo_color)
c2 = c1.Subtitle(t2, x,y+13, start,end, font, font_size, font_color, halo_color)
c3 = c2.Subtitle(t3, x,y+26, start,end, font, font_size, font_color, halo_color)
c4 = c3.Subtitle(t4, x,y+39, start,end, font, font_size, font_color, halo_color)
c5 = c4.Subtitle(t5, x,y+52, start,end, font, font_size, font_color, halo_color)
# return 文
return c5
}
関数のコマンドは、さきほどのスクリプトの背景(1-2 行目)以外の部分と、大きく異なる部分はありません。入力クリップを受け入れる引数は「c」ですので、10 行目を「c1 = bg.Subtitle(...」から「c1 = c.Subtitle(...」に変更しています。
# Import("tategaki.avs") # インポートする場合
bg = BlankClip(width=320, height=240)
bg.tategaki(4, 0, 0, 0, "A", "B", "C", "D", "E") # 「tategaki(bg, 4, ...」でも可
return last
あとは、このように書けば、前回と同じように縦書き表示が可能になります。
tategaki 関数は、同じスクリプトの任意の場所に書いておくか、別の avs ファイルに保存して import フィルタでインポートしてください。
しかし、まだこれで終わりではありません。
ユーザー定義関数作成の参考になるかもしれないページ
Project N: 022 - 文字雨(文字の落下)
文字を上から下に移動させるには、どうすればいいのでしょうか。Subtitle フィルタの書式を思い出してみましょう。
Subtitle(clip clip, string text, int x, int y, int first_frame, int last_frame, string font, int size, int text_color, int halo_color, int align, int spc)
この中で、文字の位置に関係する引数は、x と y の 2 つです。このうち、縦方向の座標を指定する y を変化させれば、何とかなりそうです(本当か?)。文字の表示開始フレームと表示終了フレームを表す first_frame と last_frame も指定する必要があるでしょう。
BlankClip(width=320, height=240)
Subtitle("A", 4,0, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("A", 4,40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
return last
とりあえず、このような感じで書いてみました。A という文字を、0 フレームから 4 フレームまでの 各 1 フレームずつ、位置を変えて表示します。y の値が 10 ずつ増えていることに注目してください。

このように、文字が上から下へ落下しているように見える・・・はずです。パラパラマンガの要領ですね。
ただし、まだこの段階では、フレーム数が少なく、文字の表示時間も短いため、動画再生プレイヤーで再生しても、ほとんど真っ黒けの動画でしかないでしょうけれど。
では次に、もう少し文字数を増やしてみます。A, B, C, D, E の 5 文字を縦にならべて、同じように移動させます。
BlankClip(width=320, height=240)
# 0 フレーム
Subtitle("A", 4,0, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52, 0,0, "Courier NEW", 18, $6FE47A, $11B301)
# 1 フレーム
Subtitle("A", 4,0+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+10, 1,1, "Courier NEW", 18, $6FE47A, $11B301)
# 2 フレーム
Subtitle("A", 4,0+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+20, 2,2, "Courier NEW", 18, $6FE47A, $11B301)
# 3 フレーム
Subtitle("A", 4,0+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+30, 3,3, "Courier NEW", 18, $6FE47A, $11B301)
# 4 フレーム
Subtitle("A", 4,0+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("B", 4,13+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("C", 4,26+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("D", 4,39+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
Subtitle("E", 4,52+40, 4,4, "Courier NEW", 18, $6FE47A, $11B301)
return last
あらかじめ、A から E の各文字の間隔が一定になるように、y の値を調整しておきます。こうすることで、縦書きのようになります。そして、最初のスクリプトと同じように、y の値を一定の割合で増加させます。+n の部分がそれです。

このように、5 文字が連結した状態で落下する(しているように見える)と思います。
ただし、見てわかるように、このスクリプトは実用的ではありません。4 フレーム目でこの状態です。29.97fps の動画なら、1 秒でこの約 6 倍、1 分で約 360 倍の長さになってしまいます。
次回は、もう少しスクリプトを簡略化させる方法を考えてみたいと思います。
連載を再開するにあたって、前回から、いくつかの変更を行っています。変更点は、下記の通りです。
- Doom9's Forum - "The Matrix" Look [while keeping skin tones] の Soulhunter 氏の書き込みを参考にして、フォントとフォントの色を変更。
- カタカナからアルファベットに変更。
- 背景クリップの大きさを 320x240 に。
HowToApplyFilterToManySingleFrames
特定のフレームや範囲にだけフィルタをかけたい場合、AviSynthではApplyRangeフィルタやFilterRange関数を使って、これを行うことができます(参照)。
しかし、その対象フレームや対象範囲が複数に渡るときは、これらのフィルタを何度も呼び出す必要が出てきます。それは、スクリプトを書く手間がかかるだけでなく、AviSynthに負荷をかけてしまうことにもなりかねません。
AviSynth.orgに掲載されているHowToApplyFilterToManySingleFramesを使えば、なるべくAviSynthに負担をかけずに、かつ、比較的簡単に、複数の範囲にフィルタをかけることができます。この方法では、AviSynthに内蔵されているConditionalFilterフィルタとConditionalReaderフィルタを使用します。
ソースクリップ

例として、このビデオクリップの1フレームと3-4フレームだけに、GreyScaleフィルタを適用したいと思います。GreyScaleフィルタは、ビデオクリップをグレースケールに変換するフィルタです。
スクリプト
global FreezeThis = 0
video = ColorBars(80,60) # ソースクリップ
frozen = video.GreyScale() # 適用したいフィルタ
ConditionalFilter(video, frozen, video, "FreezeThis", "==", "1")
ConditionalReader("Setting.txt", "FreezeThis", false)
ここでは細かい説明は省きますが、「"FreezeThis"」の値が1ならフィルタ適用後のクリップ(frozen)を選択、そうでなければオリジナルのクリップ(video)を選択するという内容になっています(いずれAviSynth Wikiで、もう少し詳しく説明するかもしれません)。
2行目のクリップのパスと3行目の適用したいフィルタ、そして5行目のSetting.txtさえ変更すれば、ほかのフィルタを使用したい場合にも応用できます。
これとは別にSetting.txt(上記スクリプトの5行目で指定)を用意します。これは、"FreezeThis"の値を設定するためのファイルです。
Setting.txtは、次のように記述します。
type int
default 0
1 1
R 3 4 1
1行目:
type int
データがint型(整数)であることを宣言しています。この場合、とくに変更する必要はありません。
2行目:
default 0
デフォルト値を設定しています。指定されなかったフレームには、この値が適用されます。
今回の例では「"FreezeThis"」の値が1ならfrozenを選択することになっているので、デフォルトは0にしておきます。これも変更する必要はありません。
3行目:
3行目以降で、フィルタを適用したいフレーム(または範囲)を指定します。
1 1
左がフレーム番号、右が値です。このように値を1に設定すると、そのフレーム(この場合は1フレーム)ではfrozenが選択されます。
4行目:
R 開始フレーム 終了フレーム 値
範囲を指定したいときは、このように記述します。RはRange(範囲)のRです。
R 3 4 1
例の場合、3から4フレームまでの値を1に設定していることになり、その範囲はfrozenが選ばれることになります。
さらにフレームを指定したい場合は、同様にして設定を追加していきます。
フィルタ適用後
フィルタ適用後
上記のスクリプトを実行すると、このようになりました。Setting.txtで指定したフレームだけが、グレースケールになっています。
備考: 複数の範囲にフィルタを適用できるFilterRangeExプラグインもあります。
「2ステップでつくるスライドショー動画」を懲りずに更新
「2ステップでつくるスライドショー動画」を更新しました。Re:「3ステップでつくるスライドショー動…でkiraru2002さんにアドバイスしていただいたのを参考にして、バッチファイルの連番リネーム関係とソート関係を少しだけ変更しています。
まだまだ無駄やおかしな部分がありそうですが、よほどのミスがなければ、更新はこれで最後にするつもりです。
以下、余談です。
このスクリプトは、元々、高橋メソッド風のAviSynthスクリプトを作っていたときに、これを応用すればスライドショー動画作成スクリプトもできるのではないかと思ったのがきっかけで作りました。
じつは高橋メソッド風のAviSynthスクリプトの最新版を出した2日後くらいには原型となるものは出来ていて、実際に動いてもいたのですが、いかんせん重すぎました。10枚程度の画像なら問題はないのですが、100枚くらいになると、VirtualDubが10~30秒ほど応答不能に陥りました(笑)
それから、にーやんの苦悩の日々が始まりました(嘘です)。
結局、試行錯誤しているうちに現在の形に落ち着き、約二ヶ月かかって「2ステップでつくるスライドショー動画」の公開にこぎ着けたわけです。思いつきから作り始めたにしては、けっこう頑張っちゃった方かもしれません。
ほかにスライドショー動画を作ることができるソフトはたくさんあると思うので、私の作ったものを使う必要はありません(ていうかオススメしません)が、ただ個人的には、思いがけずkiraru2002さんにアドバイスをいただいたりして、結果的に色々と勉強になりました。



