OSDN Git Service

DTXManiaソリューション、DTXManiaプロジェクト、DTXCreatorプロジェクト、FDKプロジェクトについて英語化。
[dtxmania/dtxmania.git] / FDK / コード / 05.DirectShow / CDStoWAVFileImage.cs
diff --git a/FDK/コード/05.DirectShow/CDStoWAVFileImage.cs b/FDK/コード/05.DirectShow/CDStoWAVFileImage.cs
new file mode 100644 (file)
index 0000000..d0319d2
--- /dev/null
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using DirectShowLib;
+using SharpDX.Multimedia;
+
+namespace FDK
+{
+       public class CDStoWAVFileImage
+       {
+               /// <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 );
+                       }
+               }
+
+               #region [ private ]
+               //-----------------
+               private class CSampleGrabberCallBack : ISampleGrabberCB, IDisposable
+               {
+                       public MemoryStream MemoryStream = new MemoryStream();
+
+                       public int BufferCB( double SampleTime, IntPtr pBuffer, int BufferLen )
+                       {
+                               var bytes = new byte[ BufferLen ];
+                               Marshal.Copy( pBuffer, bytes, 0, BufferLen );           // unmanage → manage
+                               this.MemoryStream.Write( bytes, 0, BufferLen );         // byte[] → Stream
+                               return CWin32.S_OK;
+                       }
+                       public int SampleCB( double SampleTime, IMediaSample pSample )
+                       {
+                               throw new NotImplementedException( "実装されていません。" );
+                       }
+
+                       public void Dispose()
+                       {
+                               this.MemoryStream.Close();
+                       }
+               }
+               private static CSampleGrabberCallBack sampleGrabberProc = null;
+               //-----------------
+               #endregion
+       }
+}