ホーム >プログラム >Delphi 6 ローテクTips >DirectShow フィルター同士を接続するルーチン

フィルター同士を接続するルーチン

DirectShowのフィルターを自力で接続させるためのルーチン。


参考サイト

function GetUnconnectedPin(pFilter: IBaseFilter; PinDir: PIN_DIRECTION; var ppPin: IPin): HResult;
function ConnectFilters(pGraph: IGraphBuilder; pOut: IPin; pDest: IBaseFilter): HResult; overload;
function ConnectFilters(pGraph: IGraphBuilder; pSrc: IBaseFilter; pDest: IBaseFilter): HResult; overload;

一番下のConnectFilters関数をメインに使います。
その上の二つの関数は一番下のConnectFilters関数から呼ばれるルーチンです。

function GetUnconnectedPin(pFilter: IBaseFilter; PinDir: PIN_DIRECTION; var ppPin: IPin): HResult;
// http://msdn.microsoft.com/ja-jp/library/cc973418.aspx
var
  li_Ret     : HResult;
  pEnum      : IEnumPins;
  pPin       : IPin;
  pTmp       : IPin;
  ThisPinDir : TPinDirection ;
begin
  ppPin := nil;
  if (pFilter = nil) then
  begin
    Result := E_POINTER;
Exit;
  end;

  pEnum := nil;
  pPin  := nil;
  li_Ret := pFilter.EnumPins(pEnum);
  if (FAILED(li_Ret)) then
  begin
    Result := li_Ret;
Exit;
  end;

  while (pEnum.Next(1, pPin, nil) = S_OK) do
  begin
    pPin.QueryDirection(ThisPinDir);
    if (ThisPinDir = PinDir) then
    begin
      pTmp   := nil;
      li_Ret := pPin.ConnectedTo(pTmp);
      if (Succeeded(li_Ret)) then
      begin
        // 既に接続済み。必要なピンではない。
        pTmp := nil;
      end
      else
      begin
        // 未接続。これが必要なピン。
        pEnum  := nil;
        ppPin  := pPin;
        Result := S_OK;
Exit;
      end;
    end;
    pPin := nil;
  end;
  pEnum := nil;
  // 一致するピンが見つからなかった。
  Result := E_FAIL;
end;

function ConnectFilters(
  pGraph : IGraphBuilder; // フィルタ グラフ マネージャ。
  pOut   : IPin;          // アップストリーム フィルタの出力ピン。
  pDest  : IBaseFilter    // ダウンストリーム フィルタ。
): HResult; overload;
// http://msdn.microsoft.com/ja-jp/library/cc973418.aspx
var
  PinDir : TPinDirection;
  pIn    : IPin;
begin
  if (pGraph = nil)
  or (pOut   = nil)
  or (pDest  = nil)
  then begin
    Result := E_POINTER;
Exit;
  end;

  pOut.QueryDirection(PinDir);
  if (PinDir <> PINDIR_OUTPUT) then
  begin
    Result := E_FAIL;
Exit;
  end;

  // ダウンストリーム フィルタの入力ピンを検索する。
  pIn    := nil;
  Result := GetUnconnectedPin(pDest, PINDIR_INPUT, pIn);
  if (FAILED(Result)) then
  begin
Exit;
  end;

  // 接続を試す。
  Result := pGraph.Connect(pOut, pIn);
  pIn    := nil;
end;

function ConnectFilters(
  pGraph : IGraphBuilder;
  pSrc   : IBaseFilter;
  pDest  : IBaseFilter
): HResult; overload;
// http://msdn.microsoft.com/ja-jp/library/cc973418.aspx
var
  pOut : IPin;
begin
  if (pGraph = nil)
  or (pSrc   = nil)
  or (pDest  = nil)
  then begin
    Result := E_POINTER;
Exit;
  end;

  // 最初のフィルタの出力ピンを検索する。
  pOut   := nil;
  Result := GetUnconnectedPin(pSrc, PINDIR_OUTPUT, pOut);
  if (FAILED(Result)) then
  begin
Exit;
  end;

  Result := ConnectFilters(pGraph, pOut, pDest);
  pOut   := nil;
end;

フィルターには出力用(out)と入力用(in)のピンというものがあります。
フィルターによっては出力ピンだけのものや入力ピンだけのもの、あるいは複数の入出力ピンを持つものあります。
例えばファイルを読み込むソースフィルターは出力ピンだけを持つフィルターですしビデオ映像を画面に出力するビデオレンダラーは入力ピンだけを持つフィルターです。
更にビデオレンダラーのうちでもVMR7やVMR9などは複数の入力ピンを持っています。

これらの色々あるフィルターを繋ぐにはソースフィルターに近い上流側のフィルターの出力ピンと下流側のフィルターの入力ピンを取得して繋ぐということになります。
この出力ピンと入力ピンを繋ぐということを行っているのが1番目のConnectFilters関数中の pGraph.Connect(pOut, pIn) の部分です。

ではその繋ぐためのピンをどうやって取得するのかというと、フィルター中にあるピンを列挙していき、まだどのフィルターのピンとも接続されていないピンを探し当てるということをします。
それを行っているのがGetUnconnectedPin関数です。
こうして繋ぎたいフィルター中の未接続のピンをGetUnconnectedPin関数で取得して、それをフィルターグラフのConnectメソッドで接続します。
それが pGraph.Connect(pOut, pIn); の部分なわけです。


このConnectFilters関数は引数を三つ取ります。
第一引数にはフィルタグラフを指定します。
第二引数には繋ぎたいフィルターのうち、入力(ソースフィルターなど)に近い上流側のフィルターを指定します。
第三引数には繋ぎたいフィルターのうち、出力(ビデオレンダラーなど)に近い下流側のフィルターを指定します。

function ConnectFilters(
  pGraph : IGraphBuilder; // フィルターグラフ
  pSrc   : IBaseFilter;   // 上流側フィルター
  pDest  : IBaseFilter    // 下流側フィルター
): HResult;