protected void Dispose(bool bManagedDispose) { this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (bManagedDispose) { #region [ 経緯時間計測用サウンドバッファを解放。] //----------------- if (this.sd経過時間計測用サウンドバッファ != null) { this.sd経過時間計測用サウンドバッファ.tサウンドを停止する(); C共通.tDisposeする(ref this.sd経過時間計測用サウンドバッファ); } //----------------- #endregion #region [ 単位繰り上げ用スレッド停止。] //----------------- if (this.th経過時間測定用スレッド != null) { this.th経過時間測定用スレッド.Abort(); this.th経過時間測定用スレッド = null; } //----------------- #endregion C共通.tDisposeする(ref this.DirectSound); C共通.tDisposeする(this.tmシステムタイマ); } if (ctimer != null) { C共通.tDisposeする(ref this.ctimer); } }
protected void Dispose(bool bManagedDispose) { this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (bManagedDispose) { #region [ 経緯時間計測用サウンドバッファを解放。] //----------------- if (this.sd経過時間計測用サウンドバッファ != null) { this.sd経過時間計測用サウンドバッファ.tサウンドを停止する(); C共通.tDisposeする(ref this.sd経過時間計測用サウンドバッファ); } //----------------- #endregion #region [ 単位繰り上げ用スレッド停止。] //----------------- if (this.th経過時間測定用スレッド != null) { this.th経過時間測定用スレッド.Abort(); this.th経過時間測定用スレッド = null; } //----------------- #endregion C共通.tDisposeする(this.tmシステムタイマ); } if (ctimer != null) { C共通.tDisposeする(ref this.ctimer); } //使わなくなったデータをクリーンアップ Alc.MakeContextCurrent(ContextHandle.Zero); Alc.DestroyContext(this.context); Alc.CloseDevice(this.device); }
protected void Dispose(bool bManagedDispose) { this.eOutputDevice = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (bManagedDispose) { #region [ 経緯時間計測用サウンドバッファを解放。] //----------------- if (this.sd経過時間計測用サウンドバッファ != null) { this.sd経過時間計測用サウンドバッファ.tサウンドを停止する(); C共通.tDisposeする(ref this.sd経過時間計測用サウンドバッファ); } //----------------- #endregion C共通.tDisposeする(this.tmSystemTimer); } if (ctimer != null) { C共通.tDisposeする(ref this.ctimer); } //使わなくなったデータをクリーンアップ Alc.MakeContextCurrent(ContextHandle.Zero); Alc.DestroyContext(this.context); Alc.CloseDevice(this.device); }
private static IBaseFilter tオーディオレンダラを探して返す(IFilterGraph graph) { int hr = 0; IBaseFilter audioRenderer = null; IEnumFilters eFilters; hr = graph.EnumFilters(out eFilters); DsError.ThrowExceptionForHR(hr); try { var filters = new IBaseFilter[1]; while (eFilters.Next(1, filters, IntPtr.Zero) == CWin32.S_OK) { if ((filters[0] as IAMAudioRendererStats) != null) { audioRenderer = filters[0]; break; } C共通.tCOMオブジェクトを解放する(ref filters[0]); } } finally { C共通.tCOMオブジェクトを解放する(ref eFilters); } return(audioRenderer); }
public static void t現在のユーザConfigに従ってサウンドデバイスとすべての既存サウンドを再構築する() { #region [ すでにサウンドデバイスと演奏タイマが構築されていれば解放する。] //----------------- if (SoundDevice != null) { // すでに生成済みのサウンドがあれば初期状態に戻す。 CSound.tすべてのサウンドを初期状態に戻す(); // リソースは解放するが、CSoundのインスタンスは残す。 // サウンドデバイスと演奏タイマを解放する。 C共通.tDisposeする(SoundDevice); SoundDevice = null; C共通.tDisposeする(ref rc演奏用タイマ); // Global.SoundDevice を解放した後に解放すること。(Global.SoundDevice で参照されているため) } //----------------- #endregion #region [ 新しいサウンドデバイスを構築する。] //----------------- switch (SoundDeviceType) { case ESoundDeviceType.ExclusiveWASAPI: SoundDevice = new CSoundDeviceWASAPI(CSoundDeviceWASAPI.Eデバイスモード.Exclusive, SoundDelayExclusiveWASAPI, SoundUpdatePeriodExclusiveWASAPI); break; case ESoundDeviceType.SharedWASAPI: SoundDevice = new CSoundDeviceWASAPI(CSoundDeviceWASAPI.Eデバイスモード.Shared, SoundDelaySharedWASAPI, SoundUpdatePeriodSharedWASAPI); break; case ESoundDeviceType.ASIO: SoundDevice = new CSoundDeviceASIO(SoundDelayASIO, ASIODevice); break; case ESoundDeviceType.BASS: SoundDevice = new CSoundDeviceBASS(SoundUpdatePeriodBASS, SoundDelayBASS); break; case ESoundDeviceType.OpenAL: SoundDevice = new CSoundDeviceOpenAL(SoundDelayOpenAL, bUseOSTimer); break; default: throw new Exception(string.Format("未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString())); } //----------------- #endregion #region [ 新しい演奏タイマを構築する。] //----------------- rc演奏用タイマ = new CSoundTimer(SoundDevice); //----------------- #endregion SoundDevice.nMasterVolume = _nMasterVolume; // サウンドデバイスに対して、マスターボリュームを再設定する CSound.tすべてのサウンドを再構築する(SoundDevice); // すでに生成済みのサウンドがあれば作り直す。 }
protected virtual void Dispose(bool bManagedリソースも解放する) { if (bManagedリソースも解放する) { #region [ ROTから解放する。] //----------------- #if DEBUG C共通.tDisposeする(ref this.rot); #endif //----------------- #endregion CDirectShow.tインスタンスを解放する(this.nインスタンスID); } #region [ インターフェース参照をなくし、COMオブジェクトを解放する。 ] //----------------- if (this.ip != IntPtr.Zero) { Marshal.FreeCoTaskMem(this.ip); this.ip = IntPtr.Zero; } if (this.MediaCtrl != null) { this.MediaCtrl.Stop(); this.MediaCtrl = null; } if (this.MediaEventEx != null) { this.MediaEventEx.SetNotifyWindow(IntPtr.Zero, 0, IntPtr.Zero); this.MediaEventEx = null; } if (this.MediaSeeking != null) { this.MediaSeeking = null; } if (this.BasicAudio != null) { this.BasicAudio = null; } CCommon.tReleaseComObject(ref this.nullRenderer); CCommon.tReleaseComObject(ref this.memoryRenderer); CCommon.tReleaseComObject(ref this.memoryRendererObject); CCommon.tReleaseComObject(ref this.graphBuilder); //----------------- #endregion CCommon.tRunGarbageCollector(); }
private static IPin t最初の入力ピンを探して返す(IBaseFilter baseFilter) { int hr = 0; IPin firstInputPin = null; IEnumPins ePins; hr = baseFilter.EnumPins(out ePins); DsError.ThrowExceptionForHR(hr); try { var pins = new IPin[1]; while (ePins.Next(1, pins, IntPtr.Zero) == CWin32.S_OK) { PinInfo pinfo = new PinInfo() { filter = null }; try { hr = pins[0].QueryPinInfo(out pinfo); DsError.ThrowExceptionForHR(hr); if (pinfo.dir == PinDirection.Input) { firstInputPin = pins[0]; break; } } finally { if (pinfo.filter != null) { C共通.tCOMオブジェクトを解放する(ref pinfo.filter); } DsUtils.FreePinInfo(pinfo); if (firstInputPin == null) { C共通.tCOMオブジェクトを解放する(ref pins[0]); } } } } finally { C共通.tCOMオブジェクトを解放する(ref ePins); } return(firstInputPin); }
protected void Dispose(bool bManagedDispose) { this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (hMixer != -1) { Bass.BASS_StreamFree(this.hMixer); } if (!this.bIsBASSFree) { BassWasapi.BASS_WASAPI_Free(); // システムタイマより先に呼び出すこと。(tWasapi処理() の中でシステムタイマを参照してるため) Bass.BASS_Free(); } if (bManagedDispose) { C共通.tDisposeする(this.tmシステムタイマ); this.tmシステムタイマ = null; } }
public static void tビデオレンダラをグラフから除去する(IGraphBuilder graphBuilder) { int hr = 0; IBaseFilter videoRenderer = null; IPin renderInputPin = null; IPin connectedOutputPin = null; try { // videoRenderer を探す。 CDirectShow.tビデオレンダラとその入力ピンを探して返す(graphBuilder, out videoRenderer, out renderInputPin); if (videoRenderer == null || renderInputPin == null) { return; // なかった } #region [ renderInputPin へ接続している前段の出力ピン connectedOutputPin を探す。 ] //----------------- renderInputPin.ConnectedTo(out connectedOutputPin); //----------------- #endregion if (connectedOutputPin == null) { return; // なかった } // 前段の出力ピンとビデオレンダラの入力ピンを切断する。双方向から切断しないとグラフから切り離されないので注意。 renderInputPin.Disconnect(); connectedOutputPin.Disconnect(); // ビデオレンダラをグラフから除去。 graphBuilder.RemoveFilter(videoRenderer); } finally { C共通.tCOMオブジェクトを解放する(ref connectedOutputPin); C共通.tCOMオブジェクトを解放する(ref renderInputPin); C共通.tCOMオブジェクトを解放する(ref videoRenderer); } }
protected void Dispose(bool bManagedDispose) { this.eOutputDevice = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ) if (hMixer != -1) { Bass.BASS_StreamFree(this.hMixer); } if (!this.bIsBASSSoundFree) { BassAsio.BASS_ASIO_Free(); // システムタイマより先に呼び出すこと。(tAsio処理() の中でシステムタイマを参照してるため) Bass.BASS_Free(); } if (bManagedDispose) { C共通.tDisposeする(this.tmSystemTimer); this.tmSystemTimer = null; } }
/// <summary> /// <para>指定された動画ファイルから音声のみをエンコードし、WAVファイルイメージを作成して返す。</para> /// </summary> public static void t変換(string fileName, out byte[] wavFileImage) { int hr = 0; IGraphBuilder graphBuilder = null; try { graphBuilder = (IGraphBuilder) new FilterGraph(); #region [ オーディオ用サンプルグラバの作成と追加。] //----------------- ISampleGrabber sampleGrabber = null; try { sampleGrabber = (ISampleGrabber) new SampleGrabber(); // サンプルグラバのメディアタイプの設定。 var mediaType = new AMMediaType() { majorType = MediaType.Audio, subType = MediaSubType.PCM, formatType = FormatType.WaveEx, }; try { hr = sampleGrabber.SetMediaType(mediaType); DsError.ThrowExceptionForHR(hr); } finally { if (mediaType != null) { DsUtils.FreeAMMediaType(mediaType); } } // サンプルグラバのバッファリングを有効にする。 hr = sampleGrabber.SetBufferSamples(true); DsError.ThrowExceptionForHR(hr); // サンプルグラバにコールバックを追加する。 sampleGrabberProc = new CSampleGrabberCallBack(); hr = sampleGrabber.SetCallback(sampleGrabberProc, 1); // 1:コールバックの BufferCB() メソッドの方を呼び出す。 // サンプルグラバをグラフに追加する。 hr = graphBuilder.AddFilter((IBaseFilter)sampleGrabber, "SampleGrabber for Audio/PCM"); DsError.ThrowExceptionForHR(hr); } finally { C共通.tCOMオブジェクトを解放する(ref sampleGrabber); } //----------------- #endregion var e = new DirectShowLib.DsROTEntry(graphBuilder); // fileName からグラフを自動生成。 hr = graphBuilder.RenderFile(fileName, null); // IMediaControl.RenderFile() は推奨されない DsError.ThrowExceptionForHR(hr); // ビデオレンダラを除去。 // オーディオレンダラをNullに変えるより前に実行すること。 // (CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する() の中で一度再生するので、 // そのときにActiveウィンドウが表示されてしまうため。) // chnmr0 : ウィンドウを表示しないだけなら IVideoWindow で put_AutoShow した。 IVideoWindow vw = graphBuilder as IVideoWindow; vw.put_AutoShow(OABool.False); // オーディオレンダラを NullRenderer に置換。 WaveFormat wfx; byte[] wfx拡張領域; CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する(graphBuilder, out wfx, out wfx拡張領域); // 基準クロックを NULL(最高速)に設定する。 IMediaFilter mediaFilter = graphBuilder as IMediaFilter; mediaFilter.SetSyncSource(null); mediaFilter = null; // メモリストリームにデコードデータを出力する。 sampleGrabberProc.MemoryStream = new MemoryStream(); // CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する() で一度再生しているので、ストリームをクリアする。 var ms = sampleGrabberProc.MemoryStream; var bw = new BinaryWriter(ms); bw.Write(new byte[] { 0x52, 0x49, 0x46, 0x46 }); // 'RIFF' bw.Write((UInt32)0); // ファイルサイズ - 8 [byte];今は不明なので後で上書きする。 bw.Write(new byte[] { 0x57, 0x41, 0x56, 0x45 }); // 'WAVE' bw.Write(new byte[] { 0x66, 0x6D, 0x74, 0x20 }); // 'fmt ' bw.Write((UInt32)(16 + ((wfx拡張領域.Length > 0) ? (2 /*sizeof(WAVEFORMATEX.cbSize)*/ + wfx拡張領域.Length) : 0))); // fmtチャンクのサイズ[byte] bw.Write((UInt16)wfx.Encoding); // フォーマットID(リニアPCMなら1) bw.Write((UInt16)wfx.Channels); // チャンネル数 bw.Write((UInt32)wfx.SampleRate); // サンプリングレート bw.Write((UInt32)wfx.AverageBytesPerSecond); // データ速度 bw.Write((UInt16)wfx.BlockAlign); // ブロックサイズ bw.Write((UInt16)wfx.BitsPerSample); // サンプルあたりのビット数 if (wfx拡張領域.Length > 0) { bw.Write((UInt16)wfx拡張領域.Length); // 拡張領域のサイズ[byte] bw.Write(wfx拡張領域); // 拡張データ } bw.Write(new byte[] { 0x64, 0x61, 0x74, 0x61 }); // 'data' int nDATAチャンクサイズ位置 = (int)ms.Position; bw.Write((UInt32)0); // dataチャンクのサイズ[byte];今は不明なので後で上書きする。 #region [ 再生を開始し、終了を待つ。- 再生中、sampleGrabberProc.MemoryStream に PCM データが蓄積されていく。] //----------------- IMediaControl mediaControl = graphBuilder as IMediaControl; mediaControl.Run(); // 再生開始 IMediaEvent mediaEvent = graphBuilder as IMediaEvent; EventCode eventCode; hr = mediaEvent.WaitForCompletion(-1, out eventCode); DsError.ThrowExceptionForHR(hr); if (eventCode != EventCode.Complete) { throw new Exception("再生待ちに失敗しました。"); } mediaControl.Stop(); mediaEvent = null; mediaControl = null; //----------------- #endregion bw.Seek(4, SeekOrigin.Begin); bw.Write((UInt32)ms.Length - 8); // ファイルサイズ - 8 [byte] bw.Seek(nDATAチャンクサイズ位置, SeekOrigin.Begin); bw.Write((UInt32)ms.Length - (nDATAチャンクサイズ位置 + 4)); // dataチャンクサイズ [byte] // 出力その2を作成。 wavFileImage = ms.ToArray(); // 終了処理。 bw.Close(); sampleGrabberProc.Dispose(); // ms.Close() } finally { C共通.tCOMオブジェクトを解放する(ref graphBuilder); } }
//----------------- public void Dispose() { C共通.tDisposeする(ref this.timer); }
public static void t終了() { C共通.tDisposeする(SoundDevice); SoundDevice = null; C共通.tDisposeする(ref rc演奏用タイマ); // Global.Bass を解放した後に解放すること。(Global.Bass で参照されているため) }
private static void tビデオレンダラとその入力ピンを探して返す(IFilterGraph graph, out IBaseFilter videoRenderer, out IPin inputPin) { int hr = 0; string strフィルタ名 = null; string strピンID = null; // ビデオレンダラと入力ピンを探し、そのフィルタ名とピンIDを控える。 IEnumFilters eFilters; hr = graph.EnumFilters(out eFilters); DsError.ThrowExceptionForHR(hr); try { var filters = new IBaseFilter[1]; while (eFilters.Next(1, filters, IntPtr.Zero) == CWin32.S_OK) { try { #region [ 出力ピンがない(レンダラである)ことを確認する。] //----------------- IEnumPins ePins; bool b出力ピンがある = false; hr = filters[0].EnumPins(out ePins); DsError.ThrowExceptionForHR(hr); try { var pins = new IPin[1]; while (ePins.Next(1, pins, IntPtr.Zero) == CWin32.S_OK) { try { if (b出力ピンがある) { continue; } PinDirection dir; hr = pins[0].QueryDirection(out dir); DsError.ThrowExceptionForHR(hr); if (dir == PinDirection.Output) { b出力ピンがある = true; } } finally { C共通.tCOMオブジェクトを解放する(ref pins[0]); } } } finally { C共通.tCOMオブジェクトを解放する(ref ePins); } if (b出力ピンがある) { continue; // 次のフィルタへ } //----------------- #endregion #region [ 接続中の入力ピンが MEDIATYPE_Video に対応していたら、フィルタ名とピンIDを取得する。] //----------------- hr = filters[0].EnumPins(out ePins); DsError.ThrowExceptionForHR(hr); try { var pins = new IPin[1]; while (ePins.Next(1, pins, IntPtr.Zero) == CWin32.S_OK) { try { if (!string.IsNullOrEmpty(strフィルタ名)) { continue; } var mediaType = new AMMediaType(); #region [ 現在接続中の MediaType を取得。つながってなければ次のピンへ。] //----------------- hr = pins[0].ConnectionMediaType(mediaType); if (hr == CWin32.VFW_E_NOT_CONNECTED) { continue; // つながってない } DsError.ThrowExceptionForHR(hr); //----------------- #endregion try { if (mediaType.majorType.Equals(MediaType.Video)) { #region [ フィルタ名取得!] //----------------- FilterInfo filterInfo; hr = filters[0].QueryFilterInfo(out filterInfo); DsError.ThrowExceptionForHR(hr); strフィルタ名 = filterInfo.achName; C共通.tCOMオブジェクトを解放する(ref filterInfo.pGraph); //----------------- #endregion #region [ ピンID取得!] //----------------- hr = pins[0].QueryId(out strピンID); DsError.ThrowExceptionForHR(hr); //----------------- #endregion continue; // 次のピンへ。 } } finally { DsUtils.FreeAMMediaType(mediaType); } } finally { C共通.tCOMオブジェクトを解放する(ref pins[0]); } } } finally { C共通.tCOMオブジェクトを解放する(ref ePins); } //----------------- #endregion } finally { C共通.tCOMオブジェクトを解放する(ref filters[0]); } } } finally { C共通.tCOMオブジェクトを解放する(ref eFilters); } // 改めてフィルタ名とピンIDからこれらのインターフェースを取得し、戻り値として返す。 videoRenderer = null; inputPin = null; if (!string.IsNullOrEmpty(strフィルタ名)) { hr = graph.FindFilterByName(strフィルタ名, out videoRenderer); DsError.ThrowExceptionForHR(hr); hr = videoRenderer.FindPin(strピンID, out inputPin); DsError.ThrowExceptionForHR(hr); } }
public static void tオーディオレンダラをNullレンダラに変えてフォーマットを取得する(IGraphBuilder graphBuilder, out WaveFormat wfx, out byte[] wfx拡張データ) { int hr = 0; IBaseFilter audioRenderer = null; IPin rendererInputPin = null; IPin rendererConnectedOutputPin = null; IBaseFilter nullRenderer = null; IPin nullRendererInputPin = null; wfx = null; wfx拡張データ = new byte[0]; try { // audioRenderer を探す。 audioRenderer = CDirectShow.tオーディオレンダラを探して返す(graphBuilder); if (audioRenderer == null) { return; // なかった } #region [ 音量ゼロで一度再生する。(オーディオレンダラの入力ピンMediaTypeが、接続時とは異なる「正しいもの」に変わる可能性があるため。)] //----------------- { // ここに来た時点で、グラフのビデオレンダラは無効化(NullRendererへの置換や除去など)しておくこと。 // さもないと、StopWhenReady() 時に一瞬だけ Activeウィンドウが表示されてしまう。 var mediaCtrl = (IMediaControl)graphBuilder; var basicAudio = (IBasicAudio)graphBuilder; basicAudio.put_Volume(-10000); // 最小音量 // グラフを再生してすぐ止める。(Paused → Stopped へ遷移する) mediaCtrl.StopWhenReady(); // グラフが Stopped に遷移完了するまで待つ。(StopWhenReady() はグラフが Stopped になるのを待たずに帰ってくる。) FilterState fs = FilterState.Paused; hr = CWin32.S_FALSE; while (fs != FilterState.Stopped || hr != CWin32.S_OK) { hr = mediaCtrl.GetState(10, out fs); } // 終了処理。 basicAudio.put_Volume(0); // 最大音量 basicAudio = null; mediaCtrl = null; } //----------------- #endregion // audioRenderer の入力ピンを探す。 rendererInputPin = t最初の入力ピンを探して返す(audioRenderer); if (rendererInputPin == null) { return; } // WAVEフォーマットを取得し、wfx 引数へ格納する。 var type = new AMMediaType(); hr = rendererInputPin.ConnectionMediaType(type); DsError.ThrowExceptionForHR(hr); try { wfx = new WaveFormat(); #region [ type.formatPtr から wfx に、拡張領域を除くデータをコピーする。] //----------------- var wfxTemp = new WaveFormatEx(); // SlimDX.Multimedia.WaveFormat は Marshal.PtrToStructure() で使えないので、それが使える DirectShowLib.WaveFormatEx を介して取得する。(面倒…) Marshal.PtrToStructure(type.formatPtr, (object)wfxTemp); wfx.AverageBytesPerSecond = wfxTemp.nAvgBytesPerSec; wfx.BitsPerSample = wfxTemp.wBitsPerSample; wfx.BlockAlignment = wfxTemp.nBlockAlign; wfx.Channels = wfxTemp.nChannels; wfx.FormatTag = (WaveFormatTag)((ushort)wfxTemp.wFormatTag); // DirectShowLib.WaveFormatEx.wFormatTag は short だが、SlimDX.Mulrimedia.WaveFormat.FormatTag は ushort である。(面倒…) wfx.SamplesPerSecond = wfxTemp.nSamplesPerSec; //----------------- #endregion #region [ 拡張領域が存在するならそれを wfx拡張データ に格納する。 ] //----------------- int nWaveFormatEx本体サイズ = 16 + 2; // sizeof( WAVEFORMAT ) + sizof( WAVEFORMATEX.cbSize ) int nはみ出しサイズbyte = type.formatSize - nWaveFormatEx本体サイズ; if (nはみ出しサイズbyte > 0) { wfx拡張データ = new byte[nはみ出しサイズbyte]; var hGC = GCHandle.Alloc(wfx拡張データ, GCHandleType.Pinned); // 動くなよー unsafe { byte *src = (byte *)type.formatPtr.ToPointer(); byte *dst = (byte *)hGC.AddrOfPinnedObject().ToPointer(); CWin32.CopyMemory(dst, src + nWaveFormatEx本体サイズ, (uint)nはみ出しサイズbyte); } hGC.Free(); } //----------------- #endregion } finally { if (type != null) { DsUtils.FreeAMMediaType(type); } } // audioRenderer につながる出力ピンを探す。 hr = rendererInputPin.ConnectedTo(out rendererConnectedOutputPin); DsError.ThrowExceptionForHR(hr); // audioRenderer をグラフから切断する。 rendererInputPin.Disconnect(); rendererConnectedOutputPin.Disconnect(); // audioRenderer をグラフから除去する。 hr = graphBuilder.RemoveFilter(audioRenderer); DsError.ThrowExceptionForHR(hr); // nullRenderer を作成し、グラフに追加する。 nullRenderer = (IBaseFilter) new NullRenderer(); hr = graphBuilder.AddFilter(nullRenderer, "Audio Null Renderer"); DsError.ThrowExceptionForHR(hr); // nullRenderer の入力ピンを探す。 hr = nullRenderer.FindPin("In", out nullRendererInputPin); DsError.ThrowExceptionForHR(hr); // nullRenderer をグラフに接続する。 hr = rendererConnectedOutputPin.Connect(nullRendererInputPin, null); DsError.ThrowExceptionForHR(hr); } finally { C共通.tCOMオブジェクトを解放する(ref nullRendererInputPin); C共通.tCOMオブジェクトを解放する(ref nullRenderer); C共通.tCOMオブジェクトを解放する(ref rendererConnectedOutputPin); C共通.tCOMオブジェクトを解放する(ref rendererInputPin); C共通.tCOMオブジェクトを解放する(ref audioRenderer); } }
// メソッド public CDirectShow(string fileName, IntPtr hWnd, bool bオーディオレンダラなし) { // 初期化。 this.n幅px = 0; this.n高さpx = 0; this.b上下反転 = false; this.nスキャンライン幅byte = 0; this.nデータサイズbyte = 0; this.b音声のみ = false; this.graphBuilder = null; this.MediaCtrl = null; this.b再生中 = false; this.bループ再生 = false; // 静的リストに登録し、インスタンスIDを得る。 CDirectShow.tインスタンスを登録する(this); // 並列処理準備。 if (CDirectShow.n並列度 == 0) // 算出がまだなら算出する。 { CDirectShow.n並列度 = Environment.ProcessorCount; // 並列度=CPU数とする。 } unsafe { this.dgライン描画ARGB32 = new DGライン描画[CDirectShow.n並列度]; this.dgライン描画XRGB32 = new DGライン描画[CDirectShow.n並列度]; for (int i = 0; i < CDirectShow.n並列度; i++) { this.dgライン描画ARGB32[i] = new DGライン描画(this.tライン描画ARGB32); this.dgライン描画XRGB32[i] = new DGライン描画(this.tライン描画XRGB32); } } try { int hr = 0; // グラフビルダを生成。 this.graphBuilder = (IGraphBuilder) new FilterGraph(); #if DEBUG // ROT への登録。 this.rot = new DsROTEntry(graphBuilder); #endif // QueryInterface。存在しなければ null。 this.MediaCtrl = this.graphBuilder as IMediaControl; this.MediaEventEx = this.graphBuilder as IMediaEventEx; this.MediaSeeking = this.graphBuilder as IMediaSeeking; this.BasicAudio = this.graphBuilder as IBasicAudio; // IMemoryRenderer をグラフに挿入。 AMMediaType mediaType = null; this.memoryRendererObject = new MemoryRenderer(); this.memoryRenderer = (IMemoryRenderer)this.memoryRendererObject; var baseFilter = (IBaseFilter)this.memoryRendererObject; hr = this.graphBuilder.AddFilter(baseFilter, "MemoryRenderer"); DsError.ThrowExceptionForHR(hr); // fileName からグラフを自動生成。 hr = this.graphBuilder.RenderFile(fileName, null); // IMediaControl.RenderFile() は推奨されない DsError.ThrowExceptionForHR(hr); // 音声のみ? { IBaseFilter videoRenderer; IPin videoInputPin; IBaseFilter audioRenderer; IPin audioInputPin; #if MemoryRenderer CDirectShow.tビデオレンダラとその入力ピンを探して返す(this.graphBuilder, out videoRenderer, out videoInputPin); #else CDirectShow.SearchMMRenderers(this.graphBuilder, out videoRenderer, out videoInputPin, out audioRenderer, out audioInputPin); #endif if (videoRenderer == null && audioRenderer != null) { this.b音声のみ = true; } else { C共通.tCOMオブジェクトを解放する(ref videoInputPin); C共通.tCOMオブジェクトを解放する(ref videoRenderer); C共通.tCOMオブジェクトを解放する(ref audioInputPin); C共通.tCOMオブジェクトを解放する(ref audioRenderer); } } // イメージ情報を取得。 if (!this.b音声のみ) { long n; int m; this.memoryRenderer.GetWidth(out n); this.n幅px = (int)n; this.memoryRenderer.GetHeight(out n); this.n高さpx = (int)n; this.memoryRenderer.IsBottomUp(out m); this.b上下反転 = (m != 0); this.memoryRenderer.GetBufferSize(out n); this.nデータサイズbyte = (int)n; this.nスキャンライン幅byte = (int)this.nデータサイズbyte / this.n高さpx; // C共通.tCOMオブジェクトを解放する( ref baseFilter ); なんかキャスト元のオブジェクトまで解放されるので解放禁止。 } // グラフを修正する。 if (bオーディオレンダラなし) { WaveFormat dummy1; byte[] dummy2; CDirectShow.tオーディオレンダラをNullレンダラに変えてフォーマットを取得する(this.graphBuilder, out dummy1, out dummy2); } // その他の処理。 this.t再生準備開始(); // 1回以上 IMediaControl を呼び出してないと、IReferenceClock は取得できない。 this.t遷移完了まで待って状態を取得する(); // 完全に Pause へ遷移するのを待つ。(環境依存) // イベント用ウィンドウハンドルを設定。 this.MediaEventEx.SetNotifyWindow(hWnd, (int)WM_DSGRAPHNOTIFY, new IntPtr(this.nインスタンスID)); } #if !DEBUG catch (Exception e) { C共通.t例外の詳細をログに出力する(e); this.Dispose(); throw; // 例外発出。 } #endif finally { } }