OggVorbis_Fileって、ヒープ中で完全に位置が固定されている事を仮定しているんでしょうか? 今作っている曲のループ境界探索ツール(?)でAccessViolation問題が再発したので、試しに次のようにしてみたら、ぴたりと止みました(また気のせいかも知れませんが)。
public class OggVorbisFile : IDisposable { #region コンストラクタ/ファイナライザ public OggVorbisFile() { this.data = new byte[ 720 ]; this.gchandle = GCHandle.Alloc( this.data, GCHandleType.Pinned ); this.address = Marshal.UnsafeAddrOfPinnedArrayElement ( this.data, 0 ); return; } ~OggVorbisFile() { this.Dispose(); return; } private bool disposed = false; public void Dispose() { if ( this.disposed ) return; this.gchandle.Free(); this.disposed = true; GC.SuppressFinalize( this ); return; } #endregion #region 実体 byte[] data; GCHandle gchandle; IntPtr address; #endregion #region 型変換 public static implicit operator IntPtr ( OggVorbisFile oggVorbisFile ) { return oggVorbisFile.address; } #endregion }
OggVorbis_Fileは720バイトだという事を既知として(無論、libvorbisのバージョンアップによって変わる可能性はあります)、720バイトのbyte配列を作り、GCHandleでpinする、つまりヒープ中でのアドレスを固定するというものです。以前のOggVorbisFileと違う所は、ヒープ中で固定されているかいないかだけ(のはず)なのですが、何故なんででしょうねぇ(libvorbisのソースを見ていないので、これで解決できているのかどうかは断言できませんが、OggVorbis_Fileのメンバにアクセスしないのであればこれが一番簡単なCヒープの模倣手段でしょう)。
ついでに、セカンダリバッファを更新するスレッド「だけ」で、ファイルのov_open_callbacks
からov_read
までの処理をするようにしていましたが、ov_open_callbacks
をメインスレッドで、ov_read
を別スレッドで呼び出すようにしても、AccessViolationが出なくなりました。これでdeferOpeningとかいう、あまり外部に見せたくない引数を消す事ができました。
2007-03-09追記: この方法を使う時は、アンマネージド関数のプロトタイプ宣言で[In, Out] OggVorbisFile oggVorbisFile
としていた所は、IntPtr oggVorbisFile
に変えておいてください。暗黙の型変換が行われるので、労力は小さくて済むでしょう。
コメントする