KbMedia Player の kbrunkpi.exe 解析結果

KbMedia Player が、再入不能(KMPMODULE::dwReentrant == FALSE)なプラグインを使って、クロスフェードなど再入が必要な動作をしたいときに使われるのが kbrunkpi.exe である。こいつは本体(kbmplay.exe)から指定されたプラグインとソースファイルを開いてデコードを行い、その結果の PCM を本体に返すものである。本体とは別のプロセスでプラグインを使うため、再入不能プラグインであっても安全に利用することができるというわけだ。

この記事では、KbMedia Player 本体と kbrunkpi.exe が協調して動作するその仕組みを示す。これらの解析結果は Sumire Kinoshita 氏(a.k.a.「触手の人」)によるものである。

本体と kbrunkpi.exe との間の通信は、ファイルマッピングオブジェクト(以下 FMO)を介して行われている。ここに本体がコマンドと必要なパラメータを書き込んで、コマンド用イベントを立てると、kbrunkpi.exe がコマンドに応じた処理を行い、結果を FMO に書き込んで、コマンド完了イベントを立てる。本体はこのイベントが立つのを待って、結果を FMO から読み取り、必要な操作を行う。

実際に kbrunkpi.exe を使うには、

  1. FMO を準備してビューを取得する。
  2. ビューに所定のフォーマットで初期化情報(プラグインのファイル名など)を書き込む。
  3. コマンド用イベントオブジェクトとコマンド完了イベントオブジェクトを準備する。それらの名前は FMO の名前から求められる。
  4. FMO 名をパラメータとして kbrunkpi.exe を起動する。
  5. コマンド CMD_INIT を実行させる。
  6. コマンド CMD_SEEK を実行させ、ファイルの先頭にシークする(この動作はプラグインの仕様上は必須ではないが、一部のプラグインのバグを回避するために行われる)。
  7. コマンド CMD_DECODE を繰り返し実行させ、PCM を得る。
  8. 用が済んだらコマンド CMD_DEINIT を実行させる。
  9. 各種オブジェクトを片付ける。

以上のようなステップが必要となる。

このプログラムは使いまわされることを前提として CMD_DEINIT 後もしばらく(最長 15 分)待機しているので、同じ FMO を使って再び CMD_INIT すればまた使うことができるようになる。FMO に記述されている親プロセスが終了すると、kbrunkpi.exe もまた終了する。

大まかな使い方の流れは以上である。以下に KbMedia Player Version 2.34.2004.0720 現在での FMO の使われ方を示す。

typedef struct
{
  DWORD dwMapFileSize;            // ファイルマッピングオブジェクトのサイズ。sizeof(SKbRunKpi)
  DWORD dwUniqueCodeLow;          // マジックナンバー下位。0x2E0102FB
  DWORD dwUniqueCodeHigh;         // マジックナンバー上位。0x8883EFD8
  DWORD dwProcessId;              // 親プロセスのプロセス ID
  char szPluginFileName[260 * 2]; // 使わせたいプラグインへのパス
  char szSourceFileName[260 * 2]; // デコードさせたいファイルへのパス
  DWORD dwCommand;                // コマンド。CMD_*
  DWORD dwPosition;               // CMD_SEEK へのパラメータ。
  SOUNDINFO sSoundInfo;           // 開かせたファイルの SOUNDINFO
  DWORD dwSize;                   // Buffer 中の実際のデータサイズ
  BYTE Buffer[16384];             // PCM.  フォーマットは SOUNDINFO で示される
  BYTE Reserved[256];             // たぶん 2.34beta3 から追加、おそらく本体の再生時間が
                                  // 格納されている。
} SKbRunKpi;

SOUNDINFO 構造体は kmp_pi.h に記述されているものである。

dwCommand には現在、

#define CMD_INIT  0
#define CMD_DEINIT  1
#define CMD_DECODE  2
#define CMD_SEEK  3

これらの値が与えられることがわかっている。

これらの情報を元に、実際に kbrunkpi.exe とプラグインを使用して、wav ファイルへのデコードを行うサンプルプログラムを示す。このプログラムは Sumire Kinoshita 氏が最初に書き、Autch が冗長な出力と日本語コメントを追加したものである。

http://www.autch.net/online/files/kbrunkpi_test.zip

Visual C++ .NET 2003 にてコンパイルおよび動作確認した。