--- /dev/null
+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
+ }
+}