Exemple #1
0
        /// <summary>
        /// ビデオキャプチャデバイスがサポートするメディアタイプ・サイズを取得する。
        /// </summary>
        private static VideoFormat[] GetVideoOutputFormat(DirectShow.IPin pin)
        {
            // IAMStreamConfigインタフェース取得
            if (!(pin is DirectShow.IAMStreamConfig config))
            {
                throw new InvalidOperationException("no IAMStreamConfig interface.");
            }

            // フォーマット個数取得
            int cap_count = 0, cap_size = 0;

            config.GetNumberOfCapabilities(ref cap_count, ref cap_size);
            if (cap_size != Marshal.SizeOf(typeof(DirectShow.VIDEO_STREAM_CONFIG_CAPS)))
            {
                throw new InvalidOperationException("no VIDEO_STREAM_CONFIG_CAPS.");
            }

            // 返却値の確保
            var result = new VideoFormat[cap_count];

            // データ用領域確保
            var cap_data = Marshal.AllocHGlobal(cap_size);

            // 列挙
            for (var i = 0; i < cap_count; i++)
            {
                var entry = new VideoFormat();

                // x番目のフォーマット情報取得
                DirectShow.AM_MEDIA_TYPE mt = null;
                config.GetStreamCaps(i, ref mt, cap_data);
                entry.Caps = PtrToStructure <DirectShow.VIDEO_STREAM_CONFIG_CAPS>(cap_data);

                // フォーマット情報の読み取り
                entry.MajorType = DirectShow.DsGuid.GetNickname(mt.MajorType);
                entry.SubType   = DirectShow.DsGuid.GetNickname(mt.SubType);

                if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo)
                {
                    var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER>(mt.pbFormat);
                    entry.Size         = new Size(vinfo.bmiHeader.biWidth, vinfo.bmiHeader.biHeight);
                    entry.TimePerFrame = vinfo.AvgTimePerFrame;
                }
                else if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo2)
                {
                    var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER2>(mt.pbFormat);
                    entry.Size         = new Size(vinfo.bmiHeader.biWidth, vinfo.bmiHeader.biHeight);
                    entry.TimePerFrame = vinfo.AvgTimePerFrame;
                }

                // 解放
                DirectShow.DeleteMediaType(ref mt);

                result[i] = entry;
            }

            // 解放
            Marshal.FreeHGlobal(cap_data);

            return(result);
        }
Exemple #2
0
        /// <summary>
        /// ビデオキャプチャデバイスの出力形式を選択する。
        /// 事前にGetVideoOutputFormatでメディアタイプ・サイズを得ておき、その中から希望のindexを指定する。
        /// 同時に出力サイズとフレームレートを変更することができる。
        /// </summary>
        /// <param name="index">希望のindexを指定する</param>
        /// <param name="size">Empty以外を指定すると出力サイズを変更する。事前にVIDEO_STREAM_CONFIG_CAPSで取得した可能範囲内を指定すること。</param>
        /// <param name="timePerFrame">0以上を指定するとフレームレートを変更する。事前にVIDEO_STREAM_CONFIG_CAPSで取得した可能範囲内を指定すること。</param>
        private static void SetVideoOutputFormat(DirectShow.IPin pin, int index, Size size, long timePerFrame)
        {
            // IAMStreamConfigインタフェース取得
            var config = pin as DirectShow.IAMStreamConfig;

            if (config == null)
            {
                throw new InvalidOperationException("no IAMStreamConfig interface.");
            }

            // フォーマット個数取得
            int cap_count = 0, cap_size = 0;

            config.GetNumberOfCapabilities(ref cap_count, ref cap_size);
            if (cap_size != Marshal.SizeOf(typeof(DirectShow.VIDEO_STREAM_CONFIG_CAPS)))
            {
                throw new InvalidOperationException("no VIDEO_STREAM_CONFIG_CAPS.");
            }

            // データ用領域確保
            var cap_data = Marshal.AllocHGlobal(cap_size);

            // idx番目のフォーマット情報取得
            DirectShow.AM_MEDIA_TYPE mt = null;
            config.GetStreamCaps(index, ref mt, cap_data);
            var cap = PtrToStructure <DirectShow.VIDEO_STREAM_CONFIG_CAPS>(cap_data);

            if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo)
            {
                var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER>(mt.pbFormat);
                if (!size.IsDefault)
                {
                    vinfo.bmiHeader.biWidth  = (int)size.Width;
                    vinfo.bmiHeader.biHeight = (int)size.Height;
                }

                if (timePerFrame > 0)
                {
                    vinfo.AvgTimePerFrame = timePerFrame;
                }

                Marshal.StructureToPtr(vinfo, mt.pbFormat, true);
            }
            else if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo2)
            {
                var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER2>(mt.pbFormat);
                if (!size.IsDefault)
                {
                    vinfo.bmiHeader.biWidth  = (int)size.Width;
                    vinfo.bmiHeader.biHeight = (int)size.Height;
                }

                if (timePerFrame > 0)
                {
                    vinfo.AvgTimePerFrame = timePerFrame;
                }

                Marshal.StructureToPtr(vinfo, mt.pbFormat, true);
            }

            // フォーマットを選択
            config.SetFormat(mt);

            // 解放
            if (cap_data != System.IntPtr.Zero)
            {
                Marshal.FreeHGlobal(cap_data);
            }
            if (mt != null)
            {
                DirectShow.DeleteMediaType(ref mt);
            }
        }
Exemple #3
0
        /// <summary>
        /// ビデオキャプチャデバイスの出力形式を選択する。
        /// </summary>
        private static void SetVideoOutputFormat(DirectShow.IPin pin, VideoFormat format)
        {
            var formats = GetVideoOutputFormat(pin);

            // 仕様ではVideoCaptureDeviceはメディア タイプごとに一定範囲の出力フォーマットをサポートできる。例えば以下のように。
            // [0]:YUY2 最小:160x120, 最大:320x240, X軸4STEP, Y軸2STEPごと
            // [1]:RGB8 最小:640x480, 最大:640x480, X軸0STEP, Y軸0STEPごと
            // SetFormatで出力サイズとフレームレートをこの範囲内で設定可能。
            // ただし試した限り、手持ちのUSBカメラはすべてサイズ固定(最大・最小が同じ)で返してきた。

            // https://msdn.microsoft.com/ja-jp/windows/dd407352(v=vs.80)
            // VIDEO_STREAM_CONFIG_CAPSの以下を除くほとんどのメンバーはdeprecated(非推奨)である。
            // アプリケーションはその他のメンバーの利用を避けること。かわりにIAMStreamConfig::GetFormatを利用すること。
            // - Guid:FORMAT_VideoInfo or FORMAT_VideoInfo2など。
            // - VideoStandard:アナログTV信号のフォーマット(NTSC, PALなど)をAnalogVideoStandard列挙体で指定する。
            // - MinFrameInterval, MaxFrameInterval:ビデオキャプチャデバイスがサポートするフレームレートの範囲。100ナノ秒単位。

            // 上記によると、VIDEO_STREAM_CONFIG_CAPSは現在はdeprecated(非推奨)であるらしい。かわりにIAMStreamConfig::GetFormatを使用することらしい。
            // 上記仕様を守ったデバイスは出力サイズを固定で返すが、守ってない古いデバイスは出力サイズを可変で返す、と考えられる。
            // 参考までに、VIDEO_STREAM_CONFIG_CAPSで解像度・クロップサイズ・フレームレートなどを変更する手順は以下の通り。

            // ①フレームレート(これは非推奨ではない)
            // VIDEO_STREAM_CONFIG_CAPS のメンバ MinFrameInterval と MaxFrameInterval は各ビデオ フレームの最小の長さと最大の長さである。
            // 次の式を使って、これらの値をフレーム レートに変換できる。
            // frames per second = 10,000,000 / frame duration

            // 特定のフレーム レートを要求するには、メディア タイプにある構造体 VIDEOINFOHEADER か VIDEOINFOHEADER2 の AvgTimePerFrame の値を変更する。
            // デバイスは最小値と最大値の間で可能なすべての値はサポートしていないことがあるため、ドライバは使用可能な最も近い値を使う。

            // ②Cropping(画像の一部切り抜き)
            // MinCroppingSize = (160, 120) // Cropping最小サイズ。
            // MaxCroppingSize = (320, 240) // Cropping最大サイズ。
            // CropGranularityX = 4         // 水平方向細分度。
            // CropGranularityY = 8         // 垂直方向細分度。
            // CropAlignX = 2               // the top-left corner of the source rectangle can sit.
            // CropAlignY = 4               // the top-left corner of the source rectangle can sit.

            // ③出力サイズ
            // https://msdn.microsoft.com/ja-jp/library/cc353344.aspx
            // https://msdn.microsoft.com/ja-jp/library/cc371290.aspx
            // VIDEO_STREAM_CONFIG_CAPS 構造体は、このメディア タイプに使える最小と最大の幅と高さを示す。
            // また、"ステップ" サイズ"も示す。ステップ サイズは、幅または高さを調整できるインクリメントの値を定義する。
            // たとえば、デバイスは次の値を返すことがある。
            // MinOutputSize: 160 × 120
            // MaxOutputSize: 320 × 240
            // OutputGranularityX:8 ピクセル (水平ステップ サイズ)
            // OutputGranularityY:8 ピクセル (垂直ステップ サイズ)
            // これらの数値が与えられると、幅は範囲内 (160、168、176、... 304、312、320) の任意の値に、
            // 高さは範囲内 (120、128、136、... 224、232、240) の任意の値に設定できる。

            // 出力サイズの可変のUSBカメラがないためデバッグするには以下のコメントを外す。
            // I have no USB camera of variable output size, uncomment below to debug.
            //size = new Size(168, 126);
            //vformat[0].Caps = new DirectShow.VIDEO_STREAM_CONFIG_CAPS()
            //{
            //    Guid = DirectShow.DsGuid.FORMAT_VideoInfo,
            //    MinOutputSize = new DirectShow.SIZE() { cx = 160, cy = 120 },
            //    MaxOutputSize = new DirectShow.SIZE() { cx = 320, cy = 240 },
            //    OutputGranularityX = 4,
            //    OutputGranularityY = 2
            //};

            // VIDEO_STREAM_CONFIG_CAPSは現在では非推奨。まずは固定サイズを探す
            // VIDEO_STREAM_CONFIG_CAPS is deprecated. First, find just the fixed size.
            for (var i = 0; i < formats.Length; i++)
            {
                var item = formats[i];

                // VideoInfoのみ対応する。(VideoInfo2はSampleGrabber未対応のため)
                // VideoInfo only... (SampleGrabber do not support VideoInfo2)
                // https://msdn.microsoft.com/ja-jp/library/cc370616.aspx
                if (item.MajorType != DirectShow.DsGuid.GetNickname(DirectShow.DsGuid.MEDIATYPE_Video))
                {
                    continue;
                }
                if (string.IsNullOrEmpty(format.SubType) == false && format.SubType != item.SubType)
                {
                    continue;
                }
                if (item.Caps.Guid != DirectShow.DsGuid.FORMAT_VideoInfo)
                {
                    continue;
                }

                if (item.Size.Width == format.Size.Width && item.Size.Height == format.Size.Height)
                {
                    SetVideoOutputFormat(pin, i, format.Size, format.TimePerFrame);
                    return;
                }
            }

            // 固定サイズが見つからなかった。可変サイズの範囲を探す。
            // Not found fixed size, search for variable size.
            for (var i = 0; i < formats.Length; i++)
            {
                var item = formats[i];

                // VideoInfoのみ対応する。(VideoInfo2はSampleGrabber未対応のため)
                // VideoInfo only... (SampleGrabber do not support VideoInfo2)
                // https://msdn.microsoft.com/ja-jp/library/cc370616.aspx
                if (item.MajorType != DirectShow.DsGuid.GetNickname(DirectShow.DsGuid.MEDIATYPE_Video))
                {
                    continue;
                }
                if (string.IsNullOrEmpty(format.SubType) == false && format.SubType != item.SubType)
                {
                    continue;
                }
                if (item.Caps.Guid != DirectShow.DsGuid.FORMAT_VideoInfo)
                {
                    continue;
                }

                if (item.Caps.OutputGranularityX == 0)
                {
                    continue;
                }
                if (item.Caps.OutputGranularityY == 0)
                {
                    continue;
                }

                for (var w = item.Caps.MinOutputSize.cx;
                     w < item.Caps.MaxOutputSize.cx;
                     w += item.Caps.OutputGranularityX)
                {
                    for (var h = item.Caps.MinOutputSize.cy;
                         h < item.Caps.MaxOutputSize.cy;
                         h += item.Caps.OutputGranularityY)
                    {
                        if (w == format.Size.Width && h == format.Size.Height)
                        {
                            SetVideoOutputFormat(pin, i, format.Size, format.TimePerFrame);
                            return;
                        }
                    }
                }
            }

            // サイズが見つかなかった場合はデフォルトサイズとする。
            // Not found, use default size.
            SetVideoOutputFormat(pin, 0, Size.Empty, 0);
        }