1st  step to understand DirectShow その6 (Allocator)



 1.Bufferの長さを決めるのは、誰?

     前節では、SampleGrabberのcallback関数を使って、データを取り出しました。

     今の場合、取り出したデータを入れるbufferの長さは、192000bytesです。

     一方、私のプログラムでは、

     portaudioを使って取り出す 1回当りの buffer lengthは

       2048個のfloat値( sizeof(float) ) * 左右 = 2048*4*2= 16384 bytes

     私としては、16384bytes、又は、 その倍数が、bufferの長さとして、欲しい訳です。

     得られたbuffer length は192000bytesですから、食い違いがあります。

     その為には、DirectShowに対する、もう少し突っ込んだ理解が、必要になります。

2.Allocator

     ここに、詳しい解説があります。 
     
Microsoft DirectX 9.0

サンプルとアロケータ



     出展 http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/DirectX9_c/directx/htm/samplesandallocators.asp

     
     

ピンが別のピンにメディア データを送る場合、ピンはメモリ バッファへの直接のポインタを渡すわけではない。その代わりに、メモリを管理する COM オブジェクトへのポインタを渡す。このオブジェクトは、"メディア サンプル" と呼ばれ、IMediaSample インターフェイスを公開する。
.....
メディア サンプルの作成と管理を行うもう 1 つの COM オブジェクトが "アロケータ" である。アロケータは IMemAllocator インターフェイスを公開する。

     で、この IMemAllocatorを辿ると
      
IMemAllocator::SetProperties

SetProperties メソッドは、割り当てるバッファの数と各バッファのサイズを指定する。

     そして、この PropertyがALLOCATOR_PROPERTIES 構造体です。

typedef struct _AllocatorProperties {
    long cBuffers;
    long cbBuffer;
    long cbAlign;
    long cbPrefix;
} ALLOCATOR_PROPERTIES;

メンバ

cBuffers

このアロケータのバッファ数。

cbBuffer

プレフィックスを除いた各バッファのサイズ (バイト単位)。

cbAlign

バッファのアラインメント。バッファはこの値の倍数から始まる。

cbPrefix

各バッファの先頭にあるプレフィックスのバイト数。

     なるほど、 192000と言う数字は、

     AllocatorPropaties.cbBuffer の数字なんや....

     これを、確かめましょう。

  .

     先ず、Sample Grabberのinput pinに、IMemInputPinを、問い合わせます。

     そして、このIMemInputPin から、Allocator を、得ます。

プッシュ モデルでは、ソース フィルタはダウンストリーム フィルタの入力ピンの IMemInputPin インターフェイスを使って、ダウンストリーム フィルタにデータをプッシュする。 (出展 アロケータの調整 )

///////////////////////////////////////////////////////////////////////
 IPin* p;
 IMemInputPin *pMemInpPin;
 IMemAllocator *pMemAl;
 ALLOCATOR_PROPERTIES Al;

 hr=GetConnectedPin(pGrabberF,PINDIR_INPUT,&p); //HRESULT GetUnconnectedPin( IBaseFilter *pFilter,PIN_DIRECTION PinDir,IPin **ppPin)を、もじる。    
  hr=p->QueryInterface(IID_IMemInputPin,(void**)&pMemInpPin);

if (hr==S_OK)
{
 
 hr=pMemInpPin->GetAllocator(&pMemAl);

 hr=pMemInpPin->GetAllocatorRequirements(&Al); //これは、実装されていない
 hr=pMemAl->GetProperties(&Al);
  }
pMemInpPin->Release();

pMemAl->Release();
p->Release();

      

     出たー!、これやがな。

     それに、この Allocator には、

IMemAllocator::SetProperties

SetProperties メソッドは、割り当てるバッファの数と各バッファのサイズを指定する。

    しめしめ、ええ methodが、ありますね。

    これを使えば、buffer lengthを 変える事ができる...

    pinを接続する前に

 hr=GetUnconnectedPin(pGrabberF,PINDIR_INPUT,&p);
  hr=p->QueryInterface(IID_IMemInputPin,(void**)&pMemInpPin);

  p->Release();

if (hr==S_OK)
{
 hr=pMemInpPin->GetAllocator(&pMemAl);
// while(pMemAl->Commit()!=S_OK);
 hr=pMemAl->GetProperties(&AlProps);

  AlProps.cBuffers=1;

 AlProps.cbAlign=8;
 AlProps.cbBuffer=16384;
 AlProps.cBuffers=1;
 AlProps.cbPrefix=0;
 hr=pMemAl->SetProperties(&AlProps,&actuAlProps);
 hr=pMemAl->Commit();

}
hr=pMemInpPin->NotifyAllocator(pMemAl,true);

     hrは、全て、S_OKを返し、成功します。

     接続後に、これを行うと、失敗します

     しかしですね、この方法は、全く効果無く、 bufferの値は、変わりません......
         
    以上は、WaveParserと、SampleGrabberの間の接続は、Push モデルだと、仮定しての話です。多分、そうだと思います。

    一方、Pull モデルも存在していて、
 
プル モデルでは、ソース フィルタはパーサー フィルタに接続される。パーサー フィルタがソース フィルタにデータを要求する。ソース フィルタはデータを送ることによって要求に応答する。プッシュ モデルでは IMemInputPin インターフェイスを使い、プル モデルでは IAsyncReader インターフェイスを使う。  (出展 トランスポート )

    で、このIAsyncReaderを調べると、 そこには

IAsyncReader インターフェイスは、非同期読み取り処理を行う出力ピンによって公開される。インターフェイスは、ダウンストリーム フィルタの入力ピンが使う。アプリケーションがこのインターフェイスを使うことはない。 (出展 IAsyncReader インターフェイス 

   
     「
アプリケーションがこのインターフェイスを使うことはない。」 ですって!

     ここに来て、はたと、気付いた事は、

       pin間の接続を、プログラムで、細かく制御するのではなくて

       アプリケーションが為すべきことは

       目的に合った、カスタムAllocatorを、プログラミングする事なのでは、ないだろうか.....

     幸いにして、ここまで来ると、WavDestの ソースプログラムも、少し、読めるようになりました。



 
      そやけど、気が重いわ....難しそうやし...
 

    H.20.3.18