Example #1
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 #2
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
            {
            }
        }