private void UpdateVideoSettings() { _AMMediaType mt; object formatBlock; vcg.Source.GetMediaType(out mt, out formatBlock); // TODO - Is VIH the right type for all video? VIDEOINFOHEADER vih = (VIDEOINFOHEADER)formatBlock; BITMAPINFOHEADER bmih = vih.BitmapInfo; if (lblCurrentSettings.Text == String.Empty) { lblCurrentSettings.Text = "Video stream"; } else { lblCurrentSettings.Text += "\r\n\r\nVideo stream"; } lblCurrentSettings.Text += string.Format("\r\n{0}Resolution: {1}x{2}" + "\r\n{0}Frame rate: {3} fps \r\n{0}Color space: {4} ({5} bit)" + "\r\n{0}Uncompressed bit rate: {6} Kbps", TAB, bmih.Width, bmih.Height, vih.FrameRate.ToString("F2"), MediaType.SubType.GuidToString(mt.subtype), bmih.BitCount, (uint)(bmih.Width * bmih.Height * bmih.BitCount * vih.FrameRate) / 1000); }
/// <summary>Gets the size of a frame based on a video's media type.</summary> /// <param name="mediaType">The media type of the video.</param> /// <returns>The size of a frame in the video.</returns> private static Size GetFrameSize(_AMMediaType mediaType) { VIDEOINFOHEADER videoInfo = (VIDEOINFOHEADER)Marshal.PtrToStructure( mediaType.pbFormat, typeof(VIDEOINFOHEADER)); return(new Size(videoInfo.bmiHeader.biWidth, videoInfo.bmiHeader.biHeight)); }
private void UpdateVideoBox() { btnAdvancedVideoSettings.Enabled = true; lblVideoInfo.Enabled = true; // Update video info about the camera _AMMediaType mt; object formatBlock; vcg.Source.GetMediaType(out mt, out formatBlock); // TODO - Is VIH the right type for all video VIDEOINFOHEADER vih = (VIDEOINFOHEADER)formatBlock; BITMAPINFOHEADER bmih = vih.BitmapInfo; string info = string.Format("Resolution: {0}x{1}\r\nFrame rate: {2} fps", bmih.Width, bmih.Height, vih.FrameRate.ToString("F2")); if (vcg.Compressor == null) { info += string.Format("\r\nCompressor: Disabled"); } else { info += string.Format("\r\nCompressed bit rate: {0} Kbps", vcg.VideoCompressor.QualityInfo.BitRate / 1000); } lblVideoInfo.Text = info; }
/// <summary> /// By default, we use the WMVideo9 Encoder DMO, WMV1 media type /// /// We support 3 basic default bit rates for video /// 100 Kbps for video < 320 x 240 /// 300 Kbps for video >e; 320 x 240 && < 640 x 480 /// 1 Mbps for video >e; 640 x 480 /// </summary> private void DefaultVideoCompressorSettings() { // Read camera's current media type _AMMediaType mt; object fb; cg.Source.GetMediaType(out mt, out fb); int bmpRes = 640 * 480; if (fb is VIDEOINFOHEADER) { VIDEOINFOHEADER vih = (VIDEOINFOHEADER)fb; bmpRes = vih.BitmapInfo.Height * vih.BitmapInfo.Width; } else if (fb is DVINFO) { DVCaptureGraph dvcg = cg as DVCaptureGraph; if (dvcg != null) { dvcg.GetVideoMediaType(out mt, out fb); if (fb is VIDEOINFOHEADER) { VIDEOINFOHEADER vih = (VIDEOINFOHEADER)fb; bmpRes = vih.BitmapInfo.Height * vih.BitmapInfo.Width; } } } else { Debug.Fail(string.Format(CultureInfo.CurrentCulture, "We were expecting a DVINFO or VIDEOINFOHEADER format block, not a {0}", MediaType.FormatType.GuidToString(mt.formattype))); return; } // Construct the compressor settings VideoCompressorQualityInfo vcqi = DefaultQualityInfo(); if (bmpRes < 320 * 240) { vcqi.BitRate = 100000; } else if (bmpRes < 640 * 480) { vcqi.BitRate = 300000; } else { vcqi.BitRate = 1000000; } // Set the Video Compressor's Quality vcg.VideoCompressor.QualityInfo = vcqi; }
/// <summary> /// By default, we use the WMVideo9 Encoder DMO, WMV1 media type /// /// We support 3 basic default bit rates for video /// 100 Kbps for video < 320 x 240 /// 300 Kbps for video >e; 320 x 240 && < 640 x 480 /// 1 Mbps for video >e; 640 x 480 /// </summary> private void DefaultVideoCompressorSettings() { // Read camera's current media type _AMMediaType mt; object fb; vcg.Source.GetMediaType(out mt, out fb); if (!(fb is VIDEOINFOHEADER)) { Debug.Fail("We were expecting a VIDEOINFOHEADER format block, not a " + MediaType.FormatType.GuidToString(mt.formattype)); return; } // Construct the compressor settings VideoCompressorQualityInfo vcqi = DefaultQualityInfo(); VIDEOINFOHEADER vih = (VIDEOINFOHEADER)fb; int bmpRes = vih.BitmapInfo.Height * vih.BitmapInfo.Width; if (bmpRes < 320 * 240) { vcqi.BitRate = 100000; } else if (bmpRes < 640 * 480) { vcqi.BitRate = 300000; } else { vcqi.BitRate = 1000000; } // Set the Video Compressor's Quality vcg.VideoCompressor.QualityInfo = vcqi; }
/// <summary> /// プレイヤーの接続 /// </summary> /// <param name="filename"></param> private void Player_Connect(string filename) { #region グラフビルダーの生成: { Graph = (IGraphBuilder)Axi.CoCreateInstance(GUID.CLSID_FilterGraph); if (Graph == null) { throw new System.IO.IOException("Failed to create a GraphBuilder."); } Builder = (ICaptureGraphBuilder2)Axi.CoCreateInstance(GUID.CLSID_CaptureGraphBuilder2); if (Builder == null) { throw new System.IO.IOException("Failed to create a GraphBuilder."); } Builder.SetFiltergraph(Graph); } #endregion #region 像入力用: ソースフィルタを生成します. { Graph.AddSourceFilter(filename, "VideoSource", ref VideoSource); if (VideoSource == null) { throw new System.IO.IOException("Failed to create a VideoSource."); } } #endregion #region 像捕獲用: サンプルグラバーを生成します. { VideoGrabber = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_SampleGrabber); if (VideoGrabber == null) { throw new System.IO.IOException("Failed to create a VideoGrabber."); } Graph.AddFilter(VideoGrabber, "VideoGrabber"); // サンプルグラバフィルタの入力形式設定. // SetMediaType で必要なメディア タイプを指定します。 // http://msdn.microsoft.com/ja-jp/library/cc369546.aspx // ※AM_MEDIA_TYPE 構造体のメンバをすべて設定する必要はない。 // ※デフォルトでは、サンプル グラバに優先メディア タイプはない。 // ※サンプル グラバを正しいフィルタに確実に接続するには、フィルタ グラフを作成する前にこのメソッドを呼び出す。 // majortype: http://msdn.microsoft.com/ja-jp/library/cc370108.aspx // subtype : http://msdn.microsoft.com/ja-jp/library/cc371040.aspx { var grabber = (ISampleGrabber)VideoGrabber; var mt = new AM_MEDIA_TYPE(); mt.majortype = new Guid(GUID.MEDIATYPE_Video); mt.subtype = new Guid(GUID.MEDIASUBTYPE_RGB24); mt.formattype = new Guid(GUID.FORMAT_VideoInfo); grabber.SetMediaType(mt); grabber.SetBufferSamples(false); // サンプルコピー 無効. grabber.SetOneShot(false); // One Shot 無効. //grabber.SetCallback(VideoGrabberCB, 0); // 0:SampleCB メソッドを呼び出すよう指示する. grabber.SetCallback(VideoGrabberCB, 1); // 1:BufferCB メソッドを呼び出すよう指示する. } } #endregion #region 音声捕獲用: サンプルグラバーを生成します. { AudioGrabber = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_SampleGrabber); if (AudioGrabber == null) { throw new System.IO.IOException("Failed to create a AudioGrabber."); } Graph.AddFilter(AudioGrabber, "AudioGrabber"); // サンプルグラバフィルタの入力形式設定. // SetMediaType で必要なメディア タイプを指定します。 // http://msdn.microsoft.com/ja-jp/library/cc369546.aspx // ※AM_MEDIA_TYPE 構造体のメンバをすべて設定する必要はない。 // ※デフォルトでは、サンプル グラバに優先メディア タイプはない。 // ※サンプル グラバを正しいフィルタに確実に接続するには、フィルタ グラフを作成する前にこのメソッドを呼び出す。 // majortype: http://msdn.microsoft.com/ja-jp/library/cc370108.aspx // subtype : http://msdn.microsoft.com/ja-jp/library/cc371040.aspx { var grabber = (ISampleGrabber)AudioGrabber; var mt = new AM_MEDIA_TYPE(); mt.majortype = new Guid(GUID.MEDIATYPE_Audio); mt.subtype = new Guid(GUID.MEDIASUBTYPE_PCM); mt.formattype = new Guid(GUID.FORMAT_WaveFormatEx); grabber.SetMediaType(mt); grabber.SetBufferSamples(false); // サンプルコピー 無効. grabber.SetOneShot(false); // One Shot 無効. //grabber.SetCallback(AudioGrabberCB, 0); // 0:SampleCB メソッドを呼び出すよう指示する. grabber.SetCallback(AudioGrabberCB, 1); // 1:BufferCB メソッドを呼び出すよう指示する. } } #endregion #region 像出力用: レンダラーを生成します. { VideoRenderer = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_NullRenderer); if (VideoRenderer == null) { throw new System.IO.IOException("Failed to create a VideoRenderer."); } Graph.AddFilter(VideoRenderer, "VideoRenderer"); } #endregion #region 音声出力用: レンダラーを生成します. { AudioRenderer = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_NullRenderer); if (AudioRenderer == null) { throw new System.IO.IOException("Failed to create a AudioRenderer."); } Graph.AddFilter(AudioRenderer, "AudioRenderer"); } #endregion #region フィルタの接続: if (filename.EndsWith(".avi", StringComparison.InvariantCultureIgnoreCase)) { #region AVI 形式ファイル用の初期化: unsafe { HRESULT hr; // AVI 分離器の追加: Splitter = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_AviSplitter); if (Splitter == null) { throw new System.IO.IOException("Failed to create a Splitter."); } Graph.AddFilter(Splitter, "Splitter"); // フィルタの接続: (AVI 分離器) hr = (HRESULT)Builder.RenderStream(IntPtr.Zero, IntPtr.Zero, VideoSource, null, Splitter); if (hr < HRESULT.S_OK) { throw new CxDSException(hr); } // フィルタの接続: (映像入力) var mediatype_video = new Guid(GUID.MEDIATYPE_Video); hr = (HRESULT)Builder.RenderStream(IntPtr.Zero, new IntPtr(&mediatype_video), Splitter, VideoGrabber, VideoRenderer); if (hr < HRESULT.S_OK) { throw new CxDSException(hr); } // フィルタの接続: (音声入力) ※ Audioless も有る. try { var mediatype_audio = new Guid(GUID.MEDIATYPE_Audio); hr = (HRESULT)Builder.RenderStream(IntPtr.Zero, new IntPtr(&mediatype_audio), Splitter, AudioGrabber, AudioRenderer); } catch (System.Exception ex) { Debug.WriteLine(ex.StackTrace); } } #endregion } else if ( filename.EndsWith(".asf", StringComparison.InvariantCultureIgnoreCase) || filename.EndsWith(".wmv", StringComparison.InvariantCultureIgnoreCase)) { #region WMV 形式ファイル用の初期化: unsafe { HRESULT hr; // フィルタの接続: (映像入力) var mediatype_video = new Guid(GUID.MEDIATYPE_Video); hr = (HRESULT)Builder.RenderStream(IntPtr.Zero, new IntPtr(&mediatype_video), VideoSource, VideoGrabber, VideoRenderer); if (hr < HRESULT.S_OK) { throw new CxDSException(hr); } // フィルタの接続: (音声入力) var mediatype_audio = new Guid(GUID.MEDIATYPE_Audio); hr = (HRESULT)Builder.RenderStream(IntPtr.Zero, new IntPtr(&mediatype_audio), VideoSource, AudioGrabber, AudioRenderer); if (hr < HRESULT.S_OK) { throw new CxDSException(hr); } } #endregion } #endregion // 同期用: サンプルグラバーのイベント登録: VideoGrabberCB.Enable = true; VideoGrabberCB.Notify += VideoGrabberCB_Notify; VideoInfoHeader = Axi.GetVideoInfo((ISampleGrabber)VideoGrabber); }
private void UpdateVideoSettings() { _AMMediaType mt; object formatBlock; vc.CaptureGraph.Source.GetMediaType(out mt, out formatBlock); VIDEOINFOHEADER vih = new VIDEOINFOHEADER(); bool unknownFormat = false; if (formatBlock is VIDEOINFOHEADER) { vih = (VIDEOINFOHEADER)formatBlock; } else if (formatBlock is DVINFO) { DVCaptureGraph dvcg = vc.CaptureGraph as DVCaptureGraph; if (dvcg != null) { dvcg.GetVideoMediaType(out mt, out formatBlock); if (formatBlock is VIDEOINFOHEADER) { vih = (VIDEOINFOHEADER)formatBlock; } else { unknownFormat = true; } } else { unknownFormat = true; } } else { unknownFormat = true; } if (unknownFormat) { lblCurrentSettings.Text += "Unknown Video Format"; return; } BITMAPINFOHEADER bmih = vih.BitmapInfo; if (lblCurrentSettings.Text == String.Empty) { lblCurrentSettings.Text = Strings.VideoStream; } else { lblCurrentSettings.Text += "\r\n\r\n" + Strings.VideoStream; } lblCurrentSettings.Text += string.Format(CultureInfo.CurrentCulture, "\r\n" + Strings.AdvancedVideoSettingsStatus, TAB, bmih.Width, bmih.Height, vih.FrameRate.ToString("F2", CultureInfo.InvariantCulture), MediaType.SubType.GuidToString(mt.subtype), bmih.BitCount, (uint)(bmih.Width * bmih.Height * bmih.BitCount * vih.FrameRate) / 1000); }
/// <summary> /// カメラの接続 /// </summary> /// <param name="filterInfo"></param> /// <param name="pinno"></param> /// <param name="frameSize"></param> private void Camera_Connect(CxFilterInfo filterInfo, int pinno, Size frameSize) { #region グラフビルダーの生成: { Graph = (IGraphBuilder)Axi.CoCreateInstance(GUID.CLSID_FilterGraph); if (Graph == null) { throw new System.IO.IOException("Failed to create a GraphBuilder."); } Builder = (ICaptureGraphBuilder2)Axi.CoCreateInstance(GUID.CLSID_CaptureGraphBuilder2); if (Builder == null) { throw new System.IO.IOException("Failed to create a GraphBuilder."); } Builder.SetFiltergraph(Graph); } #endregion #region 像入力用: ソースフィルタを生成します. { VideoSource = Axi.CreateFilter(GUID.CLSID_VideoInputDeviceCategory, filterInfo.CLSID, filterInfo.Index); if (VideoSource == null) { throw new System.IO.IOException("Failed to create a VideoSource."); } Graph.AddFilter(VideoSource, "VideoSource"); // フレームサイズを設定します. // ※注) この操作は、ピンを接続する前に行う必要があります. IPin pin = Axi.FindPin(VideoSource, pinno, PIN_DIRECTION.PINDIR_OUTPUT); Axi.SetFormatSize(pin, frameSize.Width, frameSize.Height); } #endregion #region 像捕獲用: サンプルグラバーを生成します. { VideoGrabber = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_SampleGrabber); if (VideoGrabber == null) { throw new System.IO.IOException("Failed to create a VideoGrabber."); } Graph.AddFilter(VideoGrabber, "VideoGrabber"); // サンプルグラバフィルタの入力形式設定. // SetMediaType で必要なメディア タイプを指定します。 // http://msdn.microsoft.com/ja-jp/library/cc369546.aspx // ※AM_MEDIA_TYPE 構造体のメンバをすべて設定する必要はない。 // ※デフォルトでは、サンプル グラバに優先メディア タイプはない。 // ※サンプル グラバを正しいフィルタに確実に接続するには、フィルタ グラフを作成する前にこのメソッドを呼び出す。 // majortype: http://msdn.microsoft.com/ja-jp/library/cc370108.aspx // subtype : http://msdn.microsoft.com/ja-jp/library/cc371040.aspx { var grabber = (ISampleGrabber)VideoGrabber; var mt = new AM_MEDIA_TYPE(); mt.majortype = new Guid(GUID.MEDIATYPE_Video); mt.subtype = new Guid(GUID.MEDIASUBTYPE_RGB24); mt.formattype = new Guid(GUID.FORMAT_VideoInfo); grabber.SetMediaType(mt); grabber.SetBufferSamples(false); // サンプルコピー 無効. grabber.SetOneShot(false); // One Shot 無効. //grabber.SetCallback(VideoGrabberCB, 0); // 0:SampleCB メソッドを呼び出すよう指示する. grabber.SetCallback(VideoGrabberCB, 1); // 1:BufferCB メソッドを呼び出すよう指示する. } } #endregion #region 像出力用: レンダラーを生成します. { VideoRenderer = (IBaseFilter)Axi.CoCreateInstance(GUID.CLSID_NullRenderer); if (VideoRenderer == null) { throw new System.IO.IOException("Failed to create a VideoRenderer."); } Graph.AddFilter(VideoRenderer, "VideoRenderer"); } #endregion #region フィルタの接続: unsafe { var mediatype = new Guid(GUID.MEDIATYPE_Video); var hr = (HRESULT)Builder.RenderStream(IntPtr.Zero, new IntPtr(&mediatype), VideoSource, VideoGrabber, VideoRenderer); if (hr < HRESULT.S_OK) { throw new CxDSException(hr); } } #endregion // 同期用: サンプルグラバーのイベント登録: VideoGrabberCB.Enable = true; VideoGrabberCB.Notify += VideoGrabberCB_Notify; VideoInfoHeader = Axi.GetVideoInfo((ISampleGrabber)VideoGrabber); // カメラ制御インターフェースの抽出. CameraControl = Axi.GetInterface <IAMCameraControl>(this.Graph); }
private StreamInfo GatherStreamInfo(AMMediaType pmt) { var streamInfo = new StreamInfo(); streamInfo.MajorType = pmt.majorType; streamInfo.SubType = pmt.subType; streamInfo.FormatType = pmt.formatType; if (pmt.formatType == FormatType.VideoInfo) { // Check the buffer size. if (pmt.formatSize >= Marshal.SizeOf(typeof(VIDEOINFOHEADER))) { VIDEOINFOHEADER pVih = (VIDEOINFOHEADER)Marshal.PtrToStructure(pmt.formatPtr, typeof(VIDEOINFOHEADER)); streamInfo.dwBitRate = pVih.dwBitRate; streamInfo.AvgTimePerFrame = pVih.AvgTimePerFrame; streamInfo.Flags = StreamInfoFlags.SI_VIDEOBITRATE | StreamInfoFlags.SI_FRAMERATE; streamInfo.rcSrc.right = GetVideoDimension(SourceRect.right, pVih.bmiHeader.biWidth); streamInfo.rcSrc.bottom = GetVideoDimension(SourceRect.bottom, pVih.bmiHeader.biHeight); } else { streamInfo.rcSrc.right = SourceRect.right; streamInfo.rcSrc.bottom = SourceRect.bottom; } streamInfo.Flags |= (StreamInfoFlags.SI_RECT | StreamInfoFlags.SI_FOURCC); } else if (pmt.formatType == FormatType.VideoInfo2) { // Check the buffer size. if (pmt.formatSize >= Marshal.SizeOf(typeof(VIDEOINFOHEADER2))) { VIDEOINFOHEADER2 pVih2 = (VIDEOINFOHEADER2)Marshal.PtrToStructure(pmt.formatPtr, typeof(VIDEOINFOHEADER2)); streamInfo.dwBitRate = pVih2.dwBitRate; streamInfo.AvgTimePerFrame = pVih2.AvgTimePerFrame; streamInfo.dwPictAspectRatioX = pVih2.dwPictAspectRatioX; streamInfo.dwPictAspectRatioY = pVih2.dwPictAspectRatioY; streamInfo.dwInterlaceFlags = pVih2.dwInterlaceFlags; streamInfo.Flags = StreamInfoFlags.SI_VIDEOBITRATE | StreamInfoFlags.SI_FRAMERATE | StreamInfoFlags.SI_ASPECTRATIO | StreamInfoFlags.SI_INTERLACEMODE; streamInfo.rcSrc.right = GetVideoDimension(SourceRect.right, pVih2.bmiHeader.biWidth); streamInfo.rcSrc.bottom = GetVideoDimension(SourceRect.bottom, pVih2.bmiHeader.biHeight); } else { streamInfo.rcSrc.right = SourceRect.right; streamInfo.rcSrc.bottom = SourceRect.bottom; } streamInfo.Flags |= (StreamInfoFlags.SI_RECT | StreamInfoFlags.SI_FOURCC); } else if (pmt.formatType == FormatType.WaveEx) { // Check the buffer size. if (pmt.formatSize >= /*Marshal.SizeOf(typeof(WAVEFORMATEX))*/ 18) { WAVEFORMATEX pWfx = (WAVEFORMATEX)Marshal.PtrToStructure(pmt.formatPtr, typeof(WAVEFORMATEX)); streamInfo.wFormatTag = pWfx.wFormatTag; streamInfo.nSamplesPerSec = pWfx.nSamplesPerSec; streamInfo.nChannels = pWfx.nChannels; streamInfo.wBitsPerSample = pWfx.wBitsPerSample; streamInfo.nAvgBytesPerSec = pWfx.nAvgBytesPerSec; streamInfo.Flags = StreamInfoFlags.SI_WAVEFORMAT | StreamInfoFlags.SI_SAMPLERATE | StreamInfoFlags.SI_WAVECHANNELS | StreamInfoFlags.SI_BITSPERSAMPLE | StreamInfoFlags.SI_AUDIOBITRATE; } } else if (pmt.formatType == FormatType.MpegVideo) { // Check the buffer size. if (pmt.formatSize >= Marshal.SizeOf(typeof(MPEG1VIDEOINFO))) { MPEG1VIDEOINFO pM1vi = (MPEG1VIDEOINFO)Marshal.PtrToStructure(pmt.formatPtr, typeof(MPEG1VIDEOINFO)); streamInfo.dwBitRate = pM1vi.hdr.dwBitRate; streamInfo.AvgTimePerFrame = pM1vi.hdr.AvgTimePerFrame; streamInfo.Flags = StreamInfoFlags.SI_VIDEOBITRATE | StreamInfoFlags.SI_FRAMERATE; streamInfo.rcSrc.right = GetVideoDimension(SourceRect.right, pM1vi.hdr.bmiHeader.biWidth); streamInfo.rcSrc.bottom = GetVideoDimension(SourceRect.bottom, pM1vi.hdr.bmiHeader.biHeight); } else { streamInfo.rcSrc.right = SourceRect.right; streamInfo.rcSrc.bottom = SourceRect.bottom; } streamInfo.Flags |= (StreamInfoFlags.SI_RECT | StreamInfoFlags.SI_FOURCC); } else if (pmt.formatType == FormatType.Mpeg2Video) { // Check the buffer size. if (pmt.formatSize >= Marshal.SizeOf(typeof(MPEG2VIDEOINFO))) { MPEG2VIDEOINFO pM2vi = (MPEG2VIDEOINFO)Marshal.PtrToStructure(pmt.formatPtr, typeof(MPEG2VIDEOINFO)); streamInfo.dwBitRate = pM2vi.hdr.dwBitRate; streamInfo.AvgTimePerFrame = pM2vi.hdr.AvgTimePerFrame; streamInfo.dwPictAspectRatioX = pM2vi.hdr.dwPictAspectRatioX; streamInfo.dwPictAspectRatioY = pM2vi.hdr.dwPictAspectRatioY; streamInfo.dwInterlaceFlags = pM2vi.hdr.dwInterlaceFlags; streamInfo.Flags = StreamInfoFlags.SI_VIDEOBITRATE | StreamInfoFlags.SI_FRAMERATE | StreamInfoFlags.SI_ASPECTRATIO | StreamInfoFlags.SI_INTERLACEMODE; streamInfo.rcSrc.right = GetVideoDimension(SourceRect.right, pM2vi.hdr.bmiHeader.biWidth); streamInfo.rcSrc.bottom = GetVideoDimension(SourceRect.bottom, pM2vi.hdr.bmiHeader.biHeight); } else { streamInfo.rcSrc.right = SourceRect.right; streamInfo.rcSrc.bottom = SourceRect.bottom; } streamInfo.Flags |= (StreamInfoFlags.SI_RECT | StreamInfoFlags.SI_FOURCC); } return(streamInfo); }
/// <summary> /// Hardcode video config for testing. /// </summary> /// <returns></returns> public bool ConfigVideo() { // Basic video settings: int w = 320; int h = 240; int fps = 30; // For RGB24: ushort bpp = 24; uint comp = 0; GUID stype = WMGuids.ToGUID(WMGuids.WMMEDIASUBTYPE_RGB24); // ..or for I420: //WORD bpp=12; //DWORD comp=0x30323449; //GUID stype= WMMEDIASUBTYPE_I420; // Settings for the video stream: // BITMAPINFOHEADER // DWORD biSize = size of the struct in bytes.. 40 // LONG biWidth - Frame width // LONG biHeight - height could be negative indicating top-down dib. // WORD biPlanes - must be 1. // WORD biBitCount 24 in our sample with RGB24 // DWORD biCompression 0 for RGB // DWORD biSizeImage in bytes.. biWidth*biHeight*biBitCount/8 // LONG biXPelsPerMeter 0 // LONG biYPelsPerMeter 0; // DWORD biClrUsed must be 0 // DWORD biClrImportant 0 // // notes: // biCompression may be a packed 'fourcc' code, for example I420 is 0x30323449, IYUV = 0x56555949... // I420 and IYUV are identical formats. They use 12 bits per pixel, and are planar, comprised of // nxm Y plane followed by n/2 x m/2 U and V planes. Each plane is 8bits deep. BITMAPINFOHEADER bi = new BITMAPINFOHEADER(); bi.Size = (uint)Marshal.SizeOf(bi); bi.Width = w; bi.Height = h; bi.Planes = 1; //always 1. bi.BitCount = bpp; bi.Compression = comp; //RGB is zero.. uncompressed. bi.SizeImage = (uint)(w * h * bpp / 8); bi.XPelsPerMeter = 0; bi.YPelsPerMeter = 0; bi.ClrUsed = 0; bi.ClrImportant = 0; // WMVIDEOINFOHEADER // RECT rcSource; // RECT rcTarget; // DWORD dwBitRate.. bps.. Width*Height*BitCount*Rate.. 320*240*24*29.93295=55172414 // DWORD dwBitErrorRate zero in our sample. // LONGLONG AvgTimePerFrame in 100ns units.. 334080=10000*1000/29.93295 // BITMAPINFOHEADER bmiHeader copy of the above struct. VIDEOINFOHEADER vi = new VIDEOINFOHEADER(); RECT r = new RECT(); r.Left = r.Top = 0; r.Bottom = bi.Height; r.Right = bi.Width; vi.Source = r; // vi.Source.Left = 0; // vi.Source.Top = 0; // vi.Source.Bottom = bi.Height; // vi.Source.Right = bi.Width; vi.Target = vi.Source; vi.BitRate = (uint)(w * h * bpp * fps); vi.BitErrorRate = 0; vi.AvgTimePerFrame = (long)((10000 * 1000) / fps); vi.BitmapInfo = bi; IntPtr viPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(vi)); Marshal.StructureToPtr(vi, viPtr, true); // WM_MEDIA_TYPE // GUID majortype WMMEDIATYPE_Video // GUID subtype WMMEDIASUBTYPE_RGB24 in our sample // BOOL bFixedSizeSamples TRUE // BOOL bTemporalCompression FALSE // ULONG lSampleSize in bytes This was zero in our sample, but could be 320*240*24/8=230400 // GUID formattype WMFORMAT_VideoInfo // IUnknown* pUnk NULL // ULONG cbFormat size of the WMVIDEOINFOHEADER // [size_is(cbFormat)] BYTE *pbFormat pointer to the WMVIDEOINFOHEADER //Note WM_MEDIA_TYPE is the same as Directshow's AM_MEDIA_TYPE. //WM_MEDIA_TYPE mt; _WMMediaType mt = new _WMMediaType(); mt.majortype = WMGuids.ToGUID(WMGuids.WMMEDIATYPE_Video); mt.subtype = stype; mt.bFixedSizeSamples = 1; mt.bTemporalCompression = 0; //mt.lSampleSize = w * h * bpp / 8; // this was zero in avinetwrite! mt.lSampleSize = 0; //hmm. Don't think it matters?? mt.formattype = WMGuids.ToGUID(WMGuids.WMFORMAT_VideoInfo); mt.pUnk = null; mt.cbFormat = (uint)Marshal.SizeOf(vi); mt.pbFormat = viPtr; bool ret = ConfigVideo(mt); Marshal.FreeCoTaskMem(viPtr); return(ret); }