Example #1
0
 public CAviDS(string filename, double playSpeed)
 {
     builder              = new FilterGraph() as IGraphBuilder;
     grabber              = new SampleGrabber() as ISampleGrabber;
     mediaType            = new AMMediaType();
     mediaType.majorType  = MediaType.Video;
     mediaType.subType    = MediaSubType.RGB32;
     mediaType.formatType = FormatType.VideoInfo;
     DsError.ThrowExceptionForHR(grabber.SetMediaType(mediaType));
     DsError.ThrowExceptionForHR(builder.AddFilter(grabber as IBaseFilter, "Sample Grabber(DTXMania)"));
     DsError.ThrowExceptionForHR(builder.RenderFile(filename, null));
     CDirectShow.ConnectNullRendererFromSampleGrabber(builder, grabber as IBaseFilter);
     if (builder is IVideoWindow videoWindow)
     {
         videoWindow.put_AutoShow(OABool.False);
     }
     DsError.ThrowExceptionForHR(grabber.GetConnectedMediaType(mediaType));
     videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));
     nWidth    = videoInfo.BmiHeader.Width;
     nHeight   = videoInfo.BmiHeader.Height;
     seeker    = builder as IMediaSeeking;
     DsError.ThrowExceptionForHR(seeker.GetDuration(out nMediaLength));
     DsError.ThrowExceptionForHR(seeker.SetRate(playSpeed / 20.0));
     control = builder as IMediaControl;
     filter  = builder as IMediaFilter;
     grabber.SetBufferSamples(BufferThem: true);
     Run();
     Pause();
     bPlaying = false;
     bPause   = false;
 }
Example #2
0
        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();
        }
Example #3
0
 protected static void tインスタンスを登録する(CDirectShow ds)
 {
     for (int i = 1; i < CDirectShow.nインスタンスIDの最大数; i++)
     {
         if (!CDirectShow.dicインスタンス.ContainsKey(i))                              // 空いている番号を使う。
         {
             ds.nインスタンスID = i;
             CDirectShow.dicインスタンス.Add(i, ds);
             break;
         }
     }
 }
Example #4
0
        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
            {
                CCommon.tReleaseComObject(ref connectedOutputPin);
                CCommon.tReleaseComObject(ref renderInputPin);
                CCommon.tReleaseComObject(ref videoRenderer);
            }
        }
Example #5
0
        /// <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);
            }
        }
Example #6
0
        public CAviDS(string filename, double playSpeed)
        {
            int hr = 0x0;

            builder = (IGraphBuilder) new FilterGraph();

            #region [Sample Grabber]
            {
                grabber              = new SampleGrabber() as ISampleGrabber;
                mediaType            = new AMMediaType();
                mediaType.majorType  = MediaType.Video;
                mediaType.subType    = MediaSubType.RGB32;
                mediaType.formatType = FormatType.VideoInfo;
                hr = grabber.SetMediaType(mediaType);
                DsError.ThrowExceptionForHR(hr);

                hr = builder.AddFilter((IBaseFilter)grabber, "Sample Grabber");
                DsError.ThrowExceptionForHR(hr);
            }
            #endregion

            hr = builder.RenderFile(filename, null);
            DsError.ThrowExceptionForHR(hr);

            // Null レンダラに接続しないとウィンドウが表示される。
            // また、レンダリングを行わないため処理速度を向上できる。
            CDirectShow.ConnectNullRendererFromSampleGrabber(builder, grabber as IBaseFilter);
            CDirectShow.tグラフを解析しデバッグ出力する(builder);

            IVideoWindow videoWindow = builder as IVideoWindow;
            if (videoWindow != null)
            {
                videoWindow.put_AutoShow(OABool.False);
            }

            #region [Video Info]
            {
                hr = grabber.GetConnectedMediaType(mediaType);
                DsError.ThrowExceptionForHR(hr);

                videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));
                nWidth    = videoInfo.BmiHeader.Width;
                nHeight   = videoInfo.BmiHeader.Height;
            }
            #endregion

            #region [ Seeker ]
            {
                seeker = builder as IMediaSeeking;
                hr     = seeker.GetDuration(out nMediaLength);
                DsError.ThrowExceptionForHR(hr);
                hr = seeker.SetRate(playSpeed / 20);
                DsError.ThrowExceptionForHR(hr);
            }
            #endregion

            #region [Control]
            {
                control = builder as IMediaControl;
            }
            #endregion

            #region [Filter]
            {
                filter = builder as IMediaFilter;
            }
            #endregion

            grabber.SetBufferSamples(true);
            this.Run();
            this.Pause();

            bPlaying = false;
            bPause   = false;                   // 外見えには演奏停止している。PAUSE中として外に見せないこと。
        }
Example #7
0
        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();                           // SharpDX.Multimedia.WaveFormat は Marshal.PtrToStructure() で使えないので、それが使える DirectShowLib.WaveFormatEx を介して取得する。(面倒…)
                    Marshal.PtrToStructure(type.formatPtr, (object)wfxTemp);

                    wfx = WaveFormat.CreateCustomFormat((WaveFormatEncoding)wfxTemp.wFormatTag, wfxTemp.nSamplesPerSec, wfxTemp.nChannels, wfxTemp.nAvgBytesPerSec, wfxTemp.nBlockAlign, wfxTemp.wBitsPerSample);
                    //-----------------
                    #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
            {
                CCommon.tReleaseComObject(ref nullRendererInputPin);
                CCommon.tReleaseComObject(ref nullRenderer);
                CCommon.tReleaseComObject(ref rendererConnectedOutputPin);
                CCommon.tReleaseComObject(ref rendererInputPin);
                CCommon.tReleaseComObject(ref audioRenderer);
            }
        }
Example #8
0
        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;
                    CDirectShow.tビデオレンダラとその入力ピンを探して返す(this.graphBuilder, out videoRenderer, out videoInputPin);
                    if (videoRenderer == null)
                    {
                        this.b音声のみ = true;
                    }
                    else
                    {
                        CCommon.tReleaseComObject(ref videoInputPin);
                        CCommon.tReleaseComObject(ref videoRenderer);
                    }
                }


                // イメージ情報を取得。

                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;
                    // CCommon.tReleaseComObject( 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)
            {
                CCommon.t例外の詳細をログに出力する(e);
                this.Dispose();
                throw;                  // 例外発出。
            }
#endif
            finally
            {
            }
        }