サンプル グラバ フィルタとは、ビデオをサンプリングして静止画として抜き出すフィルタです。
分類 | メソッド | 説明 |
---|---|---|
動作設定 | SetBufferSamples | フィルタ内を通るサンプルをバッファにコピーするかどうかを指定する。(サンプリングの開始と停止の指示) |
SetOneShot | サンプルを1つ受け取ったときに、フィルタ グラフを停止させるかどうかを指定する。 | |
メディア タイプ | SetMediaType | サンプリング形式のメディア タイプを設定する。 |
GetConnectedMediaType | サンプリング形式のメディア タイプを取得する。 | |
GetCurrentBuffer | バッファの内容を取得する。 | |
GetCurrentSample | [現在、使用されていない] | |
コールバック | SetCallback | サンプリング終了時に呼び出すコールバックを指定する。 |
ISampleGrabber sampleGrabber = null; sampleGrabber = ( ISampleGrabber )new SampleGrabber();
どのような形式で画像をサンプリングするのかを設定します。
ISampleGrabber.SetMediaType()メソッドは、フィルタが受け入れるメディア タイプの範囲を制限します。それはAMMediaTypeクラスによって定義され、majorType、subType、formatTypeメンバの順で適用されます。
AMMediaType mediaType = new AMMediaType(); mediaType.majorType = MediaType.Video; // メジャータイプ mediaType.subType = MediaSubType.RGB24; // サブタイプ mediaType.formatType = FormatType.VideoInfo; // フォーマットタイプ // メディア タイプを設定する int hr = sampleGrabber.SetMediaType( mediaType ); DsError.ThrowExceptionForHR( hr ); DsUtils.FreeAMMediaType( mediaType );ISampleGrabber::SetMediaType | MSDN
AMMediaTypeのインスタンスを作成したときには、メモリリークを防ぐためDsUtils.FreeAMMediaTypeで解放する必要があります。
分類 | フィールド | 型 | 説明 |
---|---|---|---|
タイプ | majorType | Guid | メディアサンプルのメジャータイプ。MediaTypeクラスから指定。 |
subType | Guid | メディアサンプルのサブタイプ。 | |
フォーマット | formatType | Guid | フォーマット タイプ。 |
formatSize | int | フォーマット ブロックのバイト数。 | |
formatPtr | IntPtr | フォーマット ブロックへのポインタ。 | |
種類 | fixedSizeSamples | bool | サンプルのサイズが固定であるかどうか。 |
temporalCompression | bool | サンプルが時系列圧縮方式で圧縮されているかどうか。 | |
sampleSize | int | サンプルのバイト数。 | |
unkPtr | IntPtr | [未使用] |
formatPtrが格納するフォーマットの内容は、下記のようにVideoInfoHeaderに変換して取得します。
// アンマネージ ポインタをマネージ オブジェクトにマーシャリングする object formatObj = Marshal.PtrToStructure( mediaType.formatPtr, typeof( VideoInfoHeader ) ); // VideoInfoHeaderにキャストする VideoInfoHeader videoInfoHeader = ( VideoInfoHeader )formatObj;
フィールド | 説明 |
---|---|
Audio | オーディオ |
Video | ビデオ |
AnalogAudio | アナログ オーディオ |
AnalogVideo | アナログ ビデオ |
ScriptCommand | スクリプト コマンド (クローズド キャプション用) |
AuxLine21Data | Line21データ (クローズド キャプション用) |
AUXTeletextPage | |
Interleaved | インターリーブされたオーディオとビデオ (デジタル ビデオ用) |
Mpeg2Sections | MPEG-2 PES パケット |
MSTVCaption | |
Texts | テキスト |
Midi | MIDIフォーマット |
Timecode | タイムコード データ |
File | ファイル [廃止] |
Stream | タイム スタンプのないバイト ストリーム |
VBI | |
CC_Container | |
DTVCCData | |
LMRT | [現在、使用されていない] |
URLStream | [現在、使用されていない] |
サンプリング結果を受け取るための、バッファを確保します。
AMMediaType mediaType = new AMMediaType(); // サンプル グラバからメディア タイプを取得する int hr = sampGrabber.GetConnectedMediaType( mediaType ); DsError.ThrowExceptionForHR( hr ); // サイズ情報を取得する VideoInfoHeader videoInfoHeader = ( VideoInfoHeader )Marshal.PtrToStructure( mediaType.formatPtr, typeof( VideoInfoHeader ) ); int width = videoInfoHeader.BmiHeader.Width; int height = videoInfoHeader.BmiHeader.Height; int stride = videoInfoHeader.BmiHeader.Width * ( videoInfoHeader.BmiHeader.BitCount / 8 ); DsUtils.FreeAMMediaType( mediaType ); // バッファのサイズを算出する int bufferSize = Math.Abs( stride ) * height;
SampleGrabber.GetCurrentBuffer()メソッドの呼び出し時に、第2引数にIntPtr.Zeroを渡すことでバッファのサイズを取得できます。
int bufferSize = 0;
IntPtr buffer = IntPtr.Zero;
// バッファのサイズを取得する
sampleGrabber.GetCurrentBuffer( ref bufferSize, buffer );
ISampleGrabberCB.BufferCBメソッドの引数BufferLenには、バッファのサイズが格納されています。
Marshal.AllocCoTaskMemでメモリを確保できます。なお確保したメモリは、Marshal.FreeCoTaskMemで解放する必要があります。
サンプル グラバは1つのフレームしか保持できません。サンプリングは動画のフレームごとにくり返し処理されるため、古いフレームのデータは上書きして処理されます。よってサンプリングは、必要なときにのみ処理すべきです。
int SetBufferSamples(
bool BufferThem // trueでサンプリングの開始、falseで停止
);
サンプリングの実行と停止を指示します。
サンプリングの終了を検知するために、コールバックを登録します。
int SetCallback( ISampleGrabberCB pCallback, // コールバック メソッドが格納されたISampleGrabberCBインターフェイスへのポインタ int WhichMethodToCallback // 呼び出すコールバックメソッドの指定 );
WhichMethodToCallbackには呼び出したいメソッドによって、次のいずれかの値を指定します。
値 | 呼び出されるメソッド |
---|---|
0 | ISampleGrabberCB.SampleCB |
1 | ISampleGrabberCB.BufferCB |
int SampleCB( double SampleTime, // サンプルの開始時間 [sec] IMediaSample pSample // サンプルのIMediaSampleインターフェイス );
int BufferCB( double SampleTime, // サンプルの開始時間 [sec] IntPtr pBuffer, // サンプル データを含むバッファへのポインタ int BufferLen // サンプル データを含むバッファのバイト数 );
バッファからデータを取得するには、事前にSetBufferSamplesでサンプリングを開始している必要があります。
int GetCurrentBuffer( ref int pBufferSize, // バッファのサイズ IntPtr pBuffer // バッファ );
int bufferSize = 0; IntPtr buffer = IntPtr.Zero; // バッファのサイズを取得する sampleGrabber.GetCurrentBuffer( ref bufferSize, buffer ); // バッファにメモリを割り当てる buffer = Marshal.AllocCoTaskMem( bufferSize ); // バッファのコピーを取得する sampleGrabber.GetCurrentBuffer( ref bufferSize, buffer );
[DllImport( "Kernel32.dll", EntryPoint = "RtlMoveMemory" )] private static extern void MoveMemory( IntPtr Destination, IntPtr Source, [MarshalAs( UnmanagedType.U4 )] int Length ); /// <summary> /// サンプリング終了時に呼び出されるコールバック /// </summary> /// <param name="sampleTime">サンプルの開始時間</param> /// <param name="pBuffer">サンプル データを含むバッファへのポインタ</param> /// <param name="bufferLength">サンプル データを含むバッファのバイト数</param> /// <returns></returns> int ISampleGrabberCB.BufferCB( double sampleTime, IntPtr pBuffer, int bufferLength ) { // バッファを保存する MoveMemory( this.buffer, // 移動先のメモリへのポインタ pBuffer, // 移動元のメモリへのポインタ bufferLength // 移動するメモリのバイト数 ); }
サンプリング バッファのデータはIntPtr型で返されるため、これをSystem.Drawing.Bitmapのインスタンスに変換して、画像としての処理を容易にします。
IntPtr buffer; // サンプリング バッファのデータ AMMediaType mediaType = new AMMediaType(); // サンプル グラバからメディア タイプを取得する int hr = sampGrabber.GetConnectedMediaType( mediaType ); DsError.ThrowExceptionForHR( hr ); // サイズ情報を取得する VideoInfoHeader videoInfoHeader = ( VideoInfoHeader )Marshal.PtrToStructure( mediaType.formatPtr, typeof( VideoInfoHeader ) ); int width = videoInfoHeader.BmiHeader.Width; int height = videoInfoHeader.BmiHeader.Height; int stride = videoInfoHeader.BmiHeader.Width * ( videoInfoHeader.BmiHeader.BitCount / 8 ); DsUtils.FreeAMMediaType( mediaType ); // ビットマップの作成 System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap( width, // Bitmapの幅 height, // Bitmapの高さ stride, // スキャン ラインの間のバイト オフセット数 PixelFormat.Format24bppRgb, // カラーデータの形式 buffer // ピクセル データを格納しているバッファ ); // 上下を反転する bitmap.RotateFlip( System.Drawing.RotateFlipType.RotateNoneFlipY );