2018/09

PeloReaper Extensionの情報やダウンロードはこちらからどうぞ。
PeloReaper Extension for REAPER is here.
ReaperBanner01_50p

REAPERで動画編集 (12) : VideoProcessor : APIリファレンス

今回はREAPERのVideoProcessor(以下VP)のAPIをまとめておきます。

ちなみにどこに書かれていたか忘れてしまいましたが、VPのAPIリファレンスはVPのスクリプトウィンドウで[F1]キーを押すと表示されます。かなり見づらいですが、これくらいしか情報源がないというのも事実です。

予約済み変数

既に予約されている変数があり、様々な値が設定されている。これらを上書きすることで、設定を変更できるものもある。
  • project_time
    タイムライン上での現在の再生時刻(秒)
  • project_tempo
    テンポの値(BPM)
  • project_ts_num
    現在の拍子の分子の値
  • project_ts_denom
    現在の拍子の分母の値
  • project_time_qn
    タイムライン上での現在の再生時刻(QN(4分音符)単位)
  • time
    VPを実行しているItemかTrack先頭からの経過時間。ItemとTrackいずれにVPを挿しても、実際より0.02秒程度大きい値が返るが、理由は不明。
  • framerate
    プロジェクトのVideo設定で指定されたフレームレート(FPS)
  • project_w
    画像の出力サイズ(幅)。値を変更することで、強制的に出力サイズを変更可能。
  • project_h
    画像の出力サイズ(高さ)。値を変更することで、強制的に出力サイズを変更可能。
  • project_wh_valid
    プロジェクトのVideo設定の画像サイズになっているか(0の場合はメディア側のサイズなどになっている)
  • colorspace
    現在の描画用色空間。'RGBA'、'YV12'、'YUY2'が設定できる。文字列ではないため、シングルクォートで囲むこと。設定によって色の解釈が変わる。
  • param_wet
    FXに挿したVPであれば、そのFXのWet値。Wet値はエンベロープ等で変更可能。
  • param1~param16
    GUI(ノブ)で操作できるパラメータ。以下のような記述方法で定義するが、VPプリセットのサンプルを見ると分かりやすい。
    //@param <index>[:varname] 'name' [defval minval maxval centval step]

描画用の状態変数

描画の前に設定することで、描画に影響を与えられる変数たち。
  • gfx_r, gfx_g, gfx_b, gfx_a
    矩形描画や文字列描画などに使用されるRGBA値を個別に設定できる。
  • gfx_mode
    いわゆる描画のブレンドモード指定。colorspaceにより使えるものが異なる。
    • 0:通常のαブレンドモード
    • 1:加算モード
    • 3:乗算モード(RGBAとYUVとで結果が大きく異なる)
    • 17:[YUVのみ有効] (dest + src * gfx_a) * 0.5 + 0.5
    • 18:[YUVのみ有効] dest + (src -0.5) * gfx_a * 2
    • 19:[YUVのみ有効] 差分の絶対値 abs(dest - src) * gfx_a
    また、以下のフラグ追加で挙動が変わる模様。
    • 0x100:可能な場合、blit()でフィルタリングがかかるようになる
    • 0x10000:[RGBAのみ有効] ソースα値を使用
    • 0x40000:通常モードで追加のクランプを行う(αやGradient値の範囲外防止)
    • 0x80000:[YUVのみ有効] gfx_r, gfx_g, gfx_b をYUV値として扱う
  • gfx_dest
    描画先になる画像ハンドルを設定できる。-1に設定するとメインのフレームバッファに戻せる。

入力画像関連

画像管理のしくみについてはこちらの記事を参照。
  • input_count()
    現在アクセス可能な画像の個数
  • input_track_count()
    現在の再生時刻でアクセス可能な有効トラック数(動画・VPが配置されているもののみ)
  • input_track( trackIndex )
    指定したトラックの最終出力画像を取得。trackIndex=0はこの関数を呼ぶVPがある次のトラックを指し示すことに注意。
  • input_track_exact_count()
    現在の再生時刻における、トラック数を返す。これには動画・VPを含まないトラックも数に含まれる。
  • input_track_exact( trackIndex )
    指定したトラックの最終出力画像を取得。エラーとして、トラックに動画・VPがない場合は-1000、trackIndexが有効範囲外であれば-10000という値が返る。
  • input_next_item( img )
    imgの次の画像を取得する。検索はアイテム単位で順に進んでいく。
  • input_next_track( img )
    imgの次の画像を取得する。検索はトラック単位で順に進んでいく。
  • input_ismaster()
    通常は0が返るが、MasterFX, MonitorFXにVPを挿していると以下の値が返る。
    • 1:MasterFX ChainにVPが挿入されている
    • 2:MonitorFX ChainにVPが挿入されている
  • input_info( img, w, h [, srctime, wet, param1, ...] )
    画像の情報を取得する。img以外は全て画像の情報が引数の変数に書き込まれる。

動的な画像確保関連

画像をVP内で一時的に確保して、効果を作るための画像バッファとして利用できます。
  • gfx_img_alloc( [w, h, clear] )
    新しい画像インスタンスを確保します。戻り値に画像ハンドルが返ります。
  • gfx_img_free( img )
    gfx_img_alloc()で確保した画像インスタンスを解放します。
  • gfx_img_info( img, w, h )
    画像の情報(幅、高さ)を取得します。戻り値に取得できたかどうかが返ります。
  • gfx_img_resize( img, w, h [,clear] )
    画像のリサイズ。
  • gfx_img_hold( img )
    現在の画像を後のフレームでも参照できるようにコピーして保持(戻り値に画像ハンドルが返る)。これで取得したハンドルは不要になったらgfx_img_free()で解放する必要があります。
  • gfx_img_getptr( img )
    画像単位で割り振られる?ユニークなID値を取得します。gfx_img_hold()で画像が保持されている間だけ有効。

描画関連

画像や矩形の描画や色変換等の関数がいろいろと用意されています。意外とラインや円を描画するといったものはないので、それに近い表現をするには画像を用意するとか、gfx_evalrect()で頑張るとかする必要がありそうです。
  • gfx_set( r, g, b [, a=1, mode=0, dest] )
    描画用状態変数の設定。R,G,B,A, Modeは省略も含めて必ず設定されます。destのみ指定されたら更新されます。
  • gfx_blit( img [, preserveAspect=0, x, y, w, h, srcX, srcY, srcW, srcH] )
    画像を描画。アスペクト保持や描画範囲などの指定が可能。
  • gfx_fillrect( x, y, w, h )
    現在の色設定で矩形を描画
  • gfx_procrect( x, y, w, h, channelTable [, mode] )
    チャンネルカラーテーブルを使って色変換を行う。使い方はこちらの記事を参照。
  • gfx_evalrect( x, y, w, h, codeString [, flags, src2] )
    ピクセルフォーマットの処理単位でスクリプトを実行する。使い方はこちらの記事を参照。
  • gfx_gradrect( x, y, w, h, r, g, b, a [, drdx, dgdx, dbdx, dadx, drdy, dgdy, dbdy, dady] )
    グラデーションの具合を指定して矩形を描画。
  • gfx_rotoblit( srcIndex, angle [, x, y, w, h, srcX, srcY, srcW, srcH, clipToSrcRect=0, centXOffs=0, centYOffs=0] )
    画像を回転させて描画。centXOffs, centYOffsで回転の中心をずらすことが出来る。
  • gfx_deltablit( srcIndex, x, y, w, h, srcX, srcY, dsdx, dtdx, dsdy, dtdy, dsdxdy, dtdxdy [, dadx, dady, dadxdy] )
    画像の読み書き参照位置等をずらしながら描画を行う。どんなパラメータを設定すればいいのか、かなり分かりづらいので、まず通常に描画される設定である以下の設定からはじめるとよい。
    gfx_deltablit(img, 0, 0, w, h, 0, 0, 1, 0, 0,1, 0, 0);
  • gfx_xformblit( srcIndex, x, y, w, h, vW, vH, table [, wantAlpha=0] )
    画像を横方向・縦方向に分割し、その分割位置での画像参照位置をテーブルで指定する。言葉で説明すると難しそうですが、3DCGの知識がある人は平面の頂点にUVを張り付けるイメージでとらえれば分かりやすい。
    vW, vHは横方向・縦方向の頂点数(画像が矩形なので、必ずそれぞれ2以上が必要)を表し、この個数分だけ画像参照位置(いわゆるテクスチャUV。値域は[0,1])を用意します。つまりテーブルの要素数は vW * vH * (頂点情報数) 。頂点情報数は通常はUV座標なので2ですが、wantAlpha=1の場合はUVとα値で3になります。
  • gfx_keyedblit( img [, x, y, w, h, srcX, srcY, kv1, kv2, kv3, kv4] )
    カラーを指定して特定の色を透過させつつ画像を描画。要するにクロマキー合成を行うのに利用できる。k1~k4の指定はcolorspace毎に意味が異なるので注意。クロマキー合成の方法についてはこちらの記事を参照。
    • YV12・YUY2
      kv1:U(default: -0.5)、kv2:V(default: -0.5)、kv3:許容範囲値(Clossness-Factor、default: 0.4)、kv4:ゲイン(default: 2.0)
    • RGBA
      kv1:GreenFactor(default:1)、kv2:BlueFactor(default: -1)、kv3:オフセット(default: -1)、kv4:色が漏れ出し(オーバーフロー?)たら削除(default: 1)
  • gfx_destkeyedblit( img [, x, y, w, h, srcX, srcY, kv1, kv2, kv3, kv4] )
    描画先のピクセルカラー値を参照して、キーカラーに該当する部分にこれから描画する画像を描画します。パラメータはgfx_keyedblit()と同様。つまりkv1~kv4を省略すると、デフォルトでは緑っぽいところにだけ画像が描画されることになります。
    gfx_blit( imgBG ); // 背景側の描画
    gfx_destkeyedblit( imgFG, 0, 0, w, h ); // imgBGの緑色部分にだけ画像を描画
    

文字列描画関連

文字列を描画するための関数があります。文字列の幅も取得できるので、意外と便利。
  • gfx_setfont( pxSize [, #fontname, flags] )
    フォントや書式の指定
    • pxSize:フォントサイズ
    • #fontname:フォント名(日本語指定は不可。英文名で指定)
    • flags:Bold:'B'、Italic:'I'、複合指定は 'BI' のようにする。文字列ではなくシングルクォートで囲った値にする。
  • gfx_str_measure( #string [, w, h] )
    文字列を描画した場合のサイズを取得。戻り値には幅(w)が返る。幅と高さを取得したい場合はw, hに変数を指定してやれば取得できる。
  • gfx_str_draw( #string [, x, y, r, g, b] )
    文字列を指定位置に描画する。r, g, bで色を指定出来るようですが、指定しても変化がありませんでした(バグかも?)

その他の関数など

いくつか値の変換関数などが用意されています。
  • rgb2yuv( r, g, b )
    r, g, bをy, u, vに変換(結果は引数に上書きされる)。[0, 1]の範囲へのクランプは行われません。
  • yuv2rgb( y, u, v )
    y, u, vをr, g, bに変換(結果は引数に上書きされる)。[0, 1]の範囲へのクランプは行われません。


REAPERで動画編集 (11) : VideoProcessor : 画像を作ったVPのパラメータを受け取る

前回だいぶ面倒なところの説明を終えたので、さらに応用編という感じでいってみましょう。

画像を生成したVPのパラメータ取得について

再生カーソルのタイミングで存在する動画とVoiceProcessor(以下VP)はそれぞれ画像を生成していて、VPのAPIでそれらの画像にアクセス出来ることは前回説明しました。

画像の幅などの情報は input_info() というAPIを使って取得するのですが、このAPIに渡す画像を生成したVPのパラメータ値を取得することも可能になっています。
// 画像の生成に使われたVPのパラメータ1, 2も取得する例
isOK = input_info( img, w, h, srctime, wet, param1, param2 );
  • img: 情報を取得したい画像のハンドルを渡す
  • w: 画像の幅を取得
  • h: 画像の高さを取得
  • srctime: ItemのSourceメディアにおける再生時刻(Item最初からの再生時刻ではなく、Source内の時刻)を取得
  • wet: VPのFX Wet値(Itemクロスフェード具合も考慮)を取得
  • param1:imgを生成したVPのパラメータ1を取得
  • param2:imgを生成したVPのパラメータ2を取得
ここではparam1~2までを取得していますが、必要なだけ引数を続ければこれより後ろも取れるようです。とはいえ、VPのパラメータを取得できたからといって何が嬉しいんでしょうか。

もし他のVPのパラメータも参照できるのであれば、VP間でパラメータを連動させたり出来ます。1つのVPだけでは可変パラメータが足りなくても複数のVPで構築が可能になったり、パラメータモジュレーションなども出来たりと、アイデア次第でいろいろ出来そうな気がしてきます。

とはいえ実際のところ、この input_info() を呼び出している側は相手のVPがどんな効果を実装しているのか、パラメータが一体何なのか、などといった情報を一切知ることは出来ません。VPは全て単なるスクリプトなので、VPで実装しているエフェクトのタイプといったものも存在しませんし、単純にパラメータの値を取れるというだけです。

こういう場合は、ある画像のためのVP(パラメータ送信側)とこのパラメータを取得する側のVP(パラメータ受信側)をうまくつながるように手動で合わせてやれば、意図したパラメータを送受信可能です。これを実現するには、自分で決まりを作って、それに沿ってパラメータが受け渡されるようにVPを挿入してプログラムを書くといった比較的高度な技量が要求されます(要するに自分で設計しないといけない)。

自分の書いているVPがどの位置関係にいるVPの画像を使用するかを正確に把握し、そのVPのパラメータセットも自分で構築しないといけません。この時どの画像を利用するのか正確に把握する必要がありますが、前回の記事に書いたような画像管理について理解していれば難しくはありません。

パラメータ送受信のやり方の例

ここではパラメータ送受信の大まかなやり方を説明します。
やるべきことは以下の通り。
  • 送信したいパラメータを並べたVPを実装。パラメータ以外は gfx_blit( 0 ); とだけ書いておけば、ひとまず問題ないかと。これを送信側VPと呼ぶことにします。
  • 送信側VPはItemFXやTrackFXの最後尾に配置。ここに置かないとVPのAPIで辿れません。
  • 受信側VPを作成。これは必ず送信側VPより上側のトラックにないといけません。送信側VPの画像を取得し、その画像から input_info() でパラメータを取得するようなコードを実装。
これで送信側VP、受信側VPが繋がるはずなので、パラメータ送受信が出来るはずです。

受信側VPから画像を取得する際に気を付ける必要がある点は、TrackFXにVPがあると、そのトラックが生成する最終画像はItem側ではなくTrackFX側のVPの画像である点です。Item単位で送信するパラメータを変えたいなどといった場合は、input_next_item()などのAPIを駆使して正確にそのItemのVPの画像を指定するようにして下さい。

実装例を見てみる

・・・ハイ、言葉で説明するより実装を見た方が早いですね。

まずは送信側VPスクリプト。
VP_SendRec01
送信用パラメータを1つ実装しました。名前はprm1にしてますが何でも構いません。

受信側のVPスクリプトはこんな感じにしました。
VP_SendRec02
色のついた半透明の矩形を動画の上に描画するだけです。
色のRチャンネルに受信したパラメータを使っていますので、これによって色が変わります。

で、動画とVPをセットしたのが以下のような感じ。
VP_SendRec03
動画のItem 1, 2がありますが、Item1ではprm1=1、Item2ではprm1=0に設定しています。
今は再生カーソルがItem1に重なっているのでprm1=1ですが、次の画像だとItem2に重なっているためprm1=0になり、矩形の色が変わります。
VP_SendRec04

動画にするとこんな感じ。
VPSendRec

何やら説明の段階では難しそうな印象だったかもしれませんが、やってみると簡単ですね。

まぁでも正直に言うとここまでやる機会は少ないかもしれません。どうしても複数のVPを連携させたいという場合の切り札という感じでしょうか。それにしてもこういった自由度の高い機能を用意してくれているというのはありがたいですね。

REAPERで動画編集 (10) : VideoProcessor : 動画の画像管理のしくみ

ついに動画編集の連載も10回目になってしまいましたね。
まさかこんなに続けることになるとは思いもしませんでした。
今回はVideoProcessor(以下VP)で扱う画像に関するお話です。


REAPER上の全トラックを見渡してみて、現在の再生カーソル位置に複数の動画が縦に並んでいる場合を考えてみましょう。この時、例えば一番上のトラックに挿入されたVPスクリプトでは複数の画像を参照出来るようになっています。

VPのAPIではある画像の「次の画像」のハンドルを取得できるようになっているのですが、これは一体何を指しているのでしょうか。などなど、こういった入力画像まわりの事が一見分かりにくいように感じたので、このあたりどうなっているのか少し調べた結果をまとめておきます。

画像コンテナ(推測)

REAPERの動画機能では再生中の位置に応じて何枚もの画像が構築され、これが複数のVPによってアクセスされるといった構造になっているようです。REAPER内部の画像コンテナがあるようで、そこに現在のフレームで使用される画像が全て追加されていくようです。

どういう画像が追加されていくかというと、現在のフレームにおける「動画の現在の画像」「Itemに挿したVP処理後の画像」「Trackに挿したVP処理後の画像」などです。FXに複数のVPを挿していれば、それらの処理後の画像が全てコンテナ内に追加されていくことになります。

VPの処理内においても一時的に使用する画像を確保・解放(gfx_img_alloc(), gfx_img_free())ができますが、これもこの画像コンテナとのやりとりになります。最大で扱える画像枚数は全部で32個までのようです。

あるVPを処理するタイミングでは、その下にあるトラック群で作られた画像が全てコンテナに含まれるので、それらを利用して画像効果を作れるという感じです。このようにVPは他のTrackの動画やVPと連携した処理が行える点が特徴の1つになっていると言えるでしょう。

※このへんはAPIを使った結果を見ての推定なので、間違ってたらごめんなさい

画像ハンドルについて

画像を扱うには画像ハンドルという整数の番号を使ってアクセスします。
ハンドルの番号には一応規則性がありますが、どの動画・VPが何番なのかということを本来意識する必要はありません。刻々と再生位置での動画・VPの個数が変わっていくので、決め打ちの番号でアクセスするのは危険です(後述するAPIを使うことになる)。

また、画像ハンドルの0番はある意味特殊なもので、そのVPの直前までに生成された結果の画像になっています。なので、多くのVPプリセットではこれを使って画像エフェクトを実装しています。

画像ハンドルを取得するAPI

現在のVPの処理を行う時点で存在する画像の個数は input_count() で取得できます。ただし、個数が分かるだけで、どの画像がどれなのかはこれだけでは特定できません。

次は動画処理を行っているトラック数、これを取得するには input_track_count() を使用します。ただしここで言う「トラック数」にはVP自身のいるトラックを含まず、これより下側に位置するトラック数のうち動画処理を行わないトラックは除外されたトラック数が返ってきます。

ここでさらに input_track_exact_count() では、上記のトラック数に似ていますが動画処理を行わないトラックも含まれたトラック数が返ってきます。VPを処理している次のトラックから、動画処理をしている最も下に位置するトラックまでのトラック数、という感じです(後で出てくる図を参考に)。

ここまでで個数が3種類出てきましたが、普通に各トラックの画像を取得したければ、例えば
numTrack = input_track_count();
という感じで有効なトラック数を取得します。
numTrack=3 だったら、0~2のインデックスで
img = input_track( index );
としてやれば img に現在使われている各動画トラック処理後の画像が取得できます。

input_track_exact( index ) では input_track_exact_count()-1 までのインデックスを指定出来ますが、動画処理を含まないトラックを指定すると、その旨を表す値(-1000)が返ってきます。また、input_track_exact_count()以上の値のインデックスを渡すと、これも範囲外を示す値(-10000)が返ってきます。

では同じトラック上で重なっている複数の動画の画像にアクセスするにはどうすればいいかというと、 input_next_item( img ) を使用します。ある画像ハンドルを渡すと、次の画像ハンドルを返してくれます。そのトラック上に次がなければ、次のトラックへ進んでいくことになります。

input_next_track( img ) というものもありますが、これはトラック単位で次のものを探すものになります。ひとつのトラック上で複数の動画が重なっていても、次のトラックへ進むという感じです。

実際の例で挙動を確認

ここで実際に例を見てみましょう。
現在再生カーソルはアイテム[1]とアイテム[2]が重なっているところにいます。
各アイテムにはFXにVPが2つあり、色変えと文字表示(アイテム[1]なら (1) と表示)をしています。
トラック1には下の方の図に示す画像を表示するVPスクリプトを挿入しています。
トラック4には "ABC" という文字を表示するVPがセットしてあります。

以下ではトラック1のTrackFXで実行しているVPスクリプトにおける値を説明します。下図に再生位置やVideoWindowの表示例を示してあります。

VP_Img01
 ↓ Track1のVPでVideoWindowに表示している画像です
VP_Img02
  • 全画像数: input_count() = 7(画像ハンドルは0~6までが有効)
  • 有効トラック数: input_track_count() = 1
  • トラック数(exact): input_track_exact_count() = 3
  • 最終画像ハンドル 0 をスタートと考えると、画像0の次の画像(Item単位)は画像3、画像3の次は画像6(画像ハンドル値は下にあるVideoWindowの図の下方の画像それぞれに対応しています。図の赤線で囲ったNextImg(Item)などの値が、ある画像の次の画像ハンドルを示しています)
  • 上記に出てこない、画像1, 2, 4, 5は何かというと、このフレームに存在する各VPが出力した画像のようです。動画のオリジナル画像(2, 5)、それを色変えした画像(1, 4)、さらにテキストを乗せた画像(0, 3)、の3つが各ItemのVPで生成されていると考えればわかりやすいですね。
だいぶ数字だらけで眩暈がしそうですが、「へー、そうなんだー」くらいにとらえてもらえればよいかと。こういったVPのAPIを使う時の参考にしてもらえれば幸いです。


今回の検証では、動画の画像を加工する際に必要になる画像まわりの仕組みについて、いろいろと理解出来てよかったです。

このブログについて
ぺろりがREAPERで遊びたいというだけのブログかもしれない

必ずこちらをお読みください

twitter: @pelori

管理人用
  • ライブドアブログ