« 循環参照でメモリリーク | メイン | VMR のカスタムアロケーターの不正アクセス問題 »

2007年05月12日

吉里吉里 ムービー拡張日誌2:: WMVソースフィルタ のメモリリーク

    

WMV ソースフィルタのメモリリークの原因も循環参照だった。

WMV ソースフィルタ では、シークを実現させるため IMediaSeeking を実装している。
そして、 IMediaSeeking はピンでも実装する必要がある。
単純にピンに送られた IMediaSeeking への操作をアップストリームへ渡して処理する場合は、CPosPassThru を使用すれば良いが、WMV ソースフィルタの場合は、そのピンを持っているソースフィルタに処理させたい。
そこで、フィルタへのポインタを持つ、CMediaSeekingProxy と言う単純に保持したポインタへ操作を流すクラスを作って対処した。
CMediaSeekingProxy では、フィルタへのポインタを CComPtr を使って保持していた。
CComPtr は代入した時にポインタの参照カウンタを増加させる。
CComPtr はデストラクタが呼ばれるか、明示的に Release をコールした時に、参照カウンタを減少させる。
つまり、CMediaSeekingProxy は、生存期間中渡されたフィルタの参照カウンタを増加させたままにする。

CMediaSeekingProxy は、前述の通り、出力ピンが持っている。
出力ピンは、WMV ソースフィルタが持っている。
以上で循環参照の出来上がり!と言うわけだ。

これを解消するには、CMediaSeekingProxy が CComPtr を使わずに、単純にポインタを持つようにすれば良さそうだ。
ただ、単純にポインタを持つと不正なポインタへのアクセスが発生してしまう可能性があるが、前述したような構造上生存期間は、CMediaSeekingProxy の持っているポインタよりも CMediaSeekingProxy の方が短い。
と言うことで、CMediaSeekingProxy では CComPtr を使わずに、ポインタとしてソースフィルタを持つことにした。

これで解決したかと思いきや、まだ開放できていないメモリがあった。
この問題はアロケーターだった。
WMV の SDK のアロケーターと DirectShow のアロケーターは少し違う。
そのため、この橋渡しをしてやるアロケーターを作る必要がある。
このアロケーターは、単純に WMV の SDK のアロケーターのアロケート要求を DirectShow のアロケーターを使って実現しているだけなのだが、この DirectShow のアロケーターでは同時に確保できる個数を2個に制限していた。
なぜ2個かと言うとレイヤー描画用のレンダーフィルタのためだ。
DirectShow のアロケーターは、ダウンストリームのフィルタ(ピン)から渡される。
レイヤー描画用のレンダーフィルタは、表示用のメモリに直接デコーダーにデコードさせるようなアロケーターを持っている。
そして、このアロケーターはダブルバッファリングのために2個だけ同時に確保できるようになっている。
WMV ソースフィルタは、初めは直接レンダーフィルタに接続するような形態になっていた。
そのため2個という制限が発生していた。
なぜ直接接続するようにしていたかと言うと、その構造の方がオーバーヘッドが少ないだろうという判断からだ。
しかし、その構造で DirectX VA を有効に使う方法を見出せなかったため、WMV Decoder DMO を間に挟む構造となった。
この時点で上記2個の制限はなくなったわけだが、とくに変更を行っていなかった。

しかし、WMV は2個以上のバッファを要求する。
ダウンストリームから渡されたアロケーターでは、上述のように2個しか確保できない。
そのため、WMV の SDK のアロケーターは、別にもう一つアロケーターを持っていた。
WMV がバッファを要求した時、ダウンストリームから渡されたアロケーターで確保に失敗すると、もう片方のアロケーターからメモリを確保する。
このようにすることで WMV からのアロケート要求にこたえる形となっていた。

DirectShow のアロケーターは、実際にメモリの確保を行う前に Commit をコールしておく必要がある。
また、確保する必要がなくなったとき、Decommit をコールする必要がある。
しかし、Decommit のコールを忘れていた。
調べると Commit は参照カウンタを増加させ、Decommit は参照カウンタを減じる。
橋渡し用に作った WMV の SDK のアロケーターのデストラクタで、Decommit をコールしてやると開放されるようになった。
他に DirectShow のアロケーターの Release を不用意にコールしてしまっている箇所があり、不正アクセスが発生してしまったが、これはその箇所を修正して解消した。

これで解決したと思っていたのだが、このエントリーを書いていて、上記2個の制限の経緯を思い出した。
既に2個の制限は必要ない。
この制限が必要ないのであれば、予備のアロケーターを別に作る必要もないし、Commit がどうとか言うことも関係ない。
と言うことで、2個の制限を撤廃し、アロケーターを決定する時にダウンストリームへ7個を要求するようにした。
これによって、予備のアロケーターは必要なくなり、構造はすっきりした。

以上で WMV ソースフィルタのメモリリークが解消され、すべてすっきりしたかと思いきや、VMR モードにするとなぜか不正アクセスが発生。
VMR のカスタムアロケーターの不正アクセス問題へ続く。



投稿者 Takenori : 2007年05月12日 19:48




comments powered by Disqus
Total : Today : Yesterday : なかのひと