Webカメラでの画像取得方法

設備監視などで活用可能なコンパクトなWebカメラ

1.仕様

  • 20×20×80のサイズでコンパクト、取付は1/4ネジの為三脚での固定が可能。
  • 画素数最大2592×1944(MPEG)。取得可能な形式はMPEG、NV12、YUY2。
  • UVCカメラであるためOpenCVでも画像取得が可能。
  • 定価 32,780円だが大手ECサイトでは2万円前後。
  • オートフォーカス機能あり。40㎜~無限遠
焦点設定値1(最近接)
焦点設定値1023(無限遠)

2.OpenCVでの画像取得

OpenCVでの画像取得が可能です。
但しデバイスの選択がインデックスでしかできない(配線の繋ぎ直しで変化する可能性あり)と多くのカメラプロパティを制御できない点が課題となります。(画像サイズ、露光時間は可能)

画像取得のコード

#include <opencv2/opencv.hpp>

#pragma comment(lib,"opencv_world454d.lib")

int main()
{
	//キャプチャーデバイスを取得
	cv::VideoCapture cap = cv::VideoCapture(0);
	cv::Mat mat;
	while(true){
		
		//カメラ画像データの取得
		cap.read(mat);

		//ウィンドウへの画像表示
		cv::imshow("MyWindow", mat);

		//30ms待機、またEscキーでループ終了
		if (cv::waitKey(30) == 27)
			break;
	}
	//デバイスの開放
	cap.release();

	//ウィンドウを閉じる
	cv::destroyAllWindows();
}

3.DirectShowでのカメラプロパティ設定

カメラのプロパティはDirectShowを使用して取得、変更します。画像の取得も可能ですが、MicrosoftがMediaFoundationでの画像取得を推奨しているのでそちらの方法で取得します。

本カメラでは以下のプロパティの設定が可能です。

  • brightness(明るさ)
  • contrast(コントラスト)
  • hue(色相)
  • saturation(色彩)
  • sharpness(シャープネス)
  • gamma(ガンマ補正値)
  • whitebalance(ホワイトバランス)
  • whitebalance_automatic(ホワイトバランス自動設定)
  • backlight-compensation(逆光補正)
  • gain(ゲイン値)
  • exposure(露光値)
  • exposure_automatic(露光値自動設定)
  • focus(フォーカス)
  • focus_automatic(オートフォーカス設定)

また本カメラで使用可能なビデオフォーマットも以下のようになり、
フォーマットを得る関数であるIMFMediaTypeHandler::GetMediaTypeByIndex(DWORD &pType)で得られます。

const int EF_NV12_1920X1080 = 0; //NV12 
const int EF_MJPEG_1920X1080 = 1; //MJPEG
const int EF_NV12_2592X1944 = 2; //NV12
const int EF_MJPEG_2592X1944 = 3; //MJPEG
const int EF_NV12_2048X1536 = 4; //NV12
const int EF_MJPEG_2048X1536 = 5; //MJPEG
const int EF_NV12_1600X1200 = 6; //NV12
const EF_MJPEG_1600X1200 = 7; //MJPEG
const int EF_NV12_1280X960 = 8; //NV12
const int EF_MJPEG_1280X960 = 9; //MJPEG
const EF_NV12_1280X720 = 10; //NV12
const int EF_MJPEG_1280X720 = 11; //MJPEG
const int EF_NV12_1024X768 = 12; //NV12
const int EF_MJPEG_1024X768 = 13; //MJPEG
const int EF_NV12_800X600 = 14; //NV12
const int EF_MJPEG_800X600 = 15; //MJPEG
const int EF_NV12_600X480 = 16; //NV12
const int EF_MJPEG_600X480 = 17; //MJPEG
const int EF_NV12_640X360 = 18; //NV12
const int EF_MJPEG_640X360 = 19; //MJPEG
const int _EF_NV12_1920X1080 = 20; ??
const int _EF_MJPEG_1920X1080 = 21; ??
const int EF_YUY2_1920X1080 = 22; //以下YUY2
const int EF_YUY2_1600X1200 = 23; 
const int EF_YUY2_1280X960 = 24; 
const int EF_YUY2_1280X720 = 25;
const int EF_YUY2_1024X768 = 26;
const int EF_YUY2_800X600 = 27;
const int EF_YUY2_640X480 = 28;
const int EF_YUY2_640X360 = 29;
    DirectShow制御の為のクラス
    #pragma once
    #include <stdio.h>
    #include <string>
    #include <dshow.h>
    #include <vector>
    #include <iostream>
    #include <iomanip>
    #include <fstream>
    #include <algorithm>
    
    struct video_formats
    {
        int width;
        int height;
        double fps;
        std::string type;
        bool flag = false;
    };
    
    class  ClsDirectShow
    {
    public:
        static IEnumMoniker* video_init(ICreateDevEnum* pDevEnum);
        static void get_devices_list(IEnumMoniker* pClassEnum);
        static void get_videoformats_list(int device_num, IEnumMoniker* pClassEnum);
        static void get_camera_settings(int device_num, IEnumMoniker* pClassEnum);
    private:
        static void get_config(IBaseFilter* pbf);
        static video_formats get_format_type(VIDEOINFOHEADER* video);
        static void get_user_controls(IBaseFilter* pbf);
        static void get_camera_controls(IBaseFilter* pbf);
    };
    
    #include "ClsDirectShow.h"
    
    //選択したデバイスを返します
    IEnumMoniker* ClsDirectShow::video_init(ICreateDevEnum* pDevEnum)
    {
        if (FAILED(CoInitialize(NULL)))
        {
            printf("error: COM init error");
            return NULL;
        }
       
        HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 
    CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
    
        if (SUCCEEDED(hr))
        {
            // Create an enumerator for the category.
            IEnumMoniker* pClassEnum = NULL;
            hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
            if (hr == S_FALSE)
            {
                return NULL;
            }
            return pClassEnum;
        }
        return NULL;
    }
    
    //接続しているビデオデバイスを取得し列挙します
    void ClsDirectShow::get_devices_list(IEnumMoniker* pClassEnum)
    {
        ULONG cFetched;
        IMoniker* pMoniker = NULL;
        int n = 0;
        pClassEnum->Reset();
    
        while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
        {
            IPropertyBag* pP = NULL;
            VARIANT var;
            var.vt = VT_BSTR;
            BSTR device_name;
            BSTR device_path;
    
            pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pP);
            pP->Read(L"FriendlyName", &var, 0);
            device_name = var.bstrVal;
            VariantClear(&var);
    
            pP->Read(L"DevicePath", &var, 0);
            device_path = var.bstrVal;
            VariantClear(&var);
    
            std::wcout << device_name << ": (" << device_path << "):" << std::endl;
            std::wcout << "        /dev/video" << n << std::endl;
            n++;
        }
        std::wcout << std::endl;
        return;
    }
    
    //使用可能なビデオフォーマットのリストを列挙します
    void ClsDirectShow::get_videoformats_list(int device_num, IEnumMoniker* pClassEnum)
    {
        ULONG cFetched;
        IMoniker* pMoniker = NULL;
        int n = 0;
        pClassEnum->Reset();
        while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
        {
            if (device_num == n)
            {
                IBaseFilter* pbf = NULL;
                pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pbf);
                get_config(pbf);
                return;
            }
            n++;
        }
    }
    
    //カメラ、ユーザー制御のプロパティの設定値を取得する
    void ClsDirectShow::get_camera_settings(int device_num, IEnumMoniker* pClassEnum)
    {
        ULONG cFetched;
        IMoniker* pMoniker = NULL;
        int n = 0;
        pClassEnum->Reset();
    
        while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
        {
            if (device_num == n)
            {
                IBaseFilter* pbf = NULL;
                pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pbf);
                get_user_controls(pbf);
                get_camera_controls(pbf);
                return;
            }
            n++;
        }
    }
    //ユーザー制御のプロパティの設定値を取得する
    void ClsDirectShow::get_user_controls(IBaseFilter* pbf)
    {
        std::vector<std::string> proc_user = { "brightness",
                                              "contrast",
                                              "hue",
                                              "saturation",
                                              "sharpness",
                                              "gamma",
                                              "colorEnable",
                                              "whitebalance",
                                              "backlight-compensation",
                                              "gain" };
    
        IAMVideoProcAmp* pProcAmp = 0;
        HRESULT hr = pbf->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
    
        if (FAILED(hr))
            return;
    
        std::cout << "User Controls" << std::endl;
        std::cout << std::endl;
    
        for (int proc_amp = 0; proc_amp < 10; proc_amp++)
        {
            long Min, Max, Step, Default, Flags, AutoFlags, Val;
    
            // Get the range and default value.
            hr = pProcAmp->GetRange(proc_amp, &Min, &Max, &Step, &Default, &AutoFlags);
            if (SUCCEEDED(hr))
            {
                // Get the current value.
                hr = pProcAmp->Get(proc_amp, &Val, &Flags);
            }
            if (SUCCEEDED(hr))
            {
                std::string str_proc = "";
    
                if (AutoFlags == 3)
                {
                    int auto_val = Flags;
                    if (Flags == 2)
                    {
                        auto_val = 0;
                    }
                    str_proc = "";
                    for (int i = int(proc_user[proc_amp].size()) + 10; i < 22; i++)
                    {
                        str_proc += " ";
                    }
    
                    std::cout << "\t" << str_proc << proc_user[proc_amp] << "_automatic (bool)"
                        << "\t: default=" << 1 << " value=" << auto_val << std::endl;
                }
    
                str_proc = "";
                for (int i = int(proc_user[proc_amp].size()); i < 22; i++)
                {
                    str_proc += " ";
                }
    
                std::cout << "\t" << str_proc << proc_user[proc_amp] << " (int) \t: min=" << Min << " max=" << Max << " step=" << Step << " default=" << Default << " value=" << Val << std::endl;
            }
        }
    
        std::cout << std::endl;
    }
    
    //カメラ制御のプロパティの設定値を取得する
    void ClsDirectShow::get_camera_controls(IBaseFilter* pbf)
    {
        std::vector<std::string> proc_contrl = { "pan",
                                                "tilt",
                                                "roll",
                                                "zoom",
                                                "exposure",
                                                "iris",
                                                "focus" };
    
        IAMCameraControl* pCamCtl = 0;
        HRESULT hr = pbf->QueryInterface(IID_IAMCameraControl, (void**)&pCamCtl);
    
        if (FAILED(hr))
            return;
    
        std::cout << "Camera Controls" << std::endl;
        std::cout << std::endl;
    
        for (int camctl_num = 0; camctl_num < 7; camctl_num++)
        {
            long Min, Max, Step, Default, Flags, AutoFlags, Val;
    
            hr = pCamCtl->GetRange(camctl_num, &Min, &Max, &Step, &Default, &AutoFlags);
            if (SUCCEEDED(hr))
            {
                hr = pCamCtl->Get(camctl_num, &Val, &Flags);
            }
            if (SUCCEEDED(hr))
            {
                std::string str_proc = "";
    
                if (AutoFlags == 3)
                {
                    int auto_val = Flags;
                    if (Flags == 2)
                    {
                        auto_val = 0;
                    }
                    str_proc = "";
                    for (int i = int(proc_contrl[camctl_num].size()) + 10; i < 22; i++)
                    {
                        str_proc += " ";
                    }
    
                    std::cout << "\t" << str_proc << proc_contrl[camctl_num] << "_automatic (bool)"
                        << "\t: default=" << 1 << " value=" << auto_val << std::endl;
                }
    
                str_proc = "";
                for (int i = int(proc_contrl[camctl_num].size()); i < 22; i++)
                {
                    str_proc += " ";
                }
    
                std::cout << "\t" << str_proc << proc_contrl[camctl_num] << " (int) \t: min=" << Min << " max=" << Max << " step=" << Step << " default=" << Default << " value=" << Val << std::endl;
            }
        }
        std::cout << std::endl;
    }
    //
    void ClsDirectShow::get_config(IBaseFilter* pbf)
    {
        HRESULT a;
        ICaptureGraphBuilder2* pCapture = NULL;
        a=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void**)&pCapture);
        IAMStreamConfig* pConfig = NULL;
        HRESULT hr = pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, 0, pbf, IID_IAMStreamConfig, (void**)&pConfig);
    
        int iCount = 0;
        int iSize = 0;
        hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
        std::vector<video_formats> format_list;
        video_formats ret;
    
        if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
        {
            for (int iFormat = 0; iFormat < iCount; iFormat++)
            {
                VIDEO_STREAM_CONFIG_CAPS scc;
                AM_MEDIA_TYPE* pmtConfig;
                hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
                VIDEOINFOHEADER* pVih2;
                
                if ((SUCCEEDED(hr) && pmtConfig->majortype == MEDIATYPE_Video) && (pmtConfig->formattype == FORMAT_VideoInfo) && (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && (pmtConfig->pbFormat != NULL))
                {
                    pVih2 = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
                    ret = get_format_type(pVih2);
                    if (ret.flag)
                    {
                        format_list.push_back(ret);
                    }
                }
            }
        }
        pConfig->Release();
        pCapture->Release();
       
        if (int(format_list.size() > 0))
        {
            std::string type = "";
            int type_cnt = 0;
            for (int i = 0; i < int(format_list.size()); i++)
            {
                if (i == 0)
                {
                    std::cout << "ioctl: VIDIOC_ENUM_FMT" << std::endl;
                    std::cout << "	Type: Video Capture" << std::endl;
                    std::cout << std::endl;
                }
    
                if (type != format_list[i].type)
                {
                    type = format_list[i].type;
                    std::cout << "	[" << type_cnt << "]: '" << type << "' (" << type << ")" << std::endl;
                    type_cnt++;
                }
                
                std::cout << "		Size: Discrete " << format_list[i].width << "x" << format_list[i].height << std::endl;
                std::cout << std::fixed;
                std::cout << "		      Interval: Discrete " << std::setprecision(3) << 1 / format_list[i].fps << "s (" << std::setprecision(3) << format_list[i].fps << " fps)" << std::endl;
            }
            std::cout << std::endl;
        }
    }
    
    video_formats ClsDirectShow::get_format_type(VIDEOINFOHEADER* video)
    {
        double ns = 100 * 1.0e-9;
        double frame = 1 / (double(video->AvgTimePerFrame) * ns);
        int width = video->bmiHeader.biWidth;
        int height = video->bmiHeader.biHeight;
        std::string format;
        std::vector<std::string> format_types;
        std::string line;
        std::string file_path;
        video_formats v_formats;
    
        char Path[MAX_PATH + 1];
        char drive[MAX_PATH + 1], dir[MAX_PATH + 1], fname[MAX_PATH + 1], ext[MAX_PATH + 1];
    
        GetModuleFileName(NULL, Path, MAX_PATH);
        _splitpath_s(Path, drive, dir, fname, ext); // パス名を構成要素に分解します
        // printf("完全パス : %s\n", Path);
        // printf("ドライブ : %s\n", drive);
        // printf("ディレクトリ パス : %s\n", dir);
        // printf("ベース ファイル名 (拡張子なし) : %s\n", fname);
        // printf("ファイル名の拡張子 : %s\n", ext);
    
        file_path = std::string(dir) + "\\format_types.txt";
        std::replace(file_path.begin(), file_path.end(), '\\', '/');
    
        std::ifstream input_file(file_path.c_str());
        while (getline(input_file, line))
        {
            format_types.push_back(std::string(line));
        }
        input_file.close();
    
        for (int i = 0; i < (int)format_types.size(); i++)
        {
            char c1 = (byte)format_types[i][0];
            char c2 = (byte)format_types[i][1];
            char c3 = (byte)format_types[i][2];
            char c4 = (byte)format_types[i][3];
            if (video->bmiHeader.biCompression == MAKEFOURCC(c1, c2, c3, c4))
            {
                format = format_types[i];
                break;
            }
        }
    
        v_formats.width = width;
        v_formats.height = height;
        v_formats.fps = frame;
        v_formats.flag = true;
    
        if (format != "")
        {
            v_formats.type = format;
        }
        else
        {
            v_formats.type = std::to_string(video->bmiHeader.biCompression);
        }
        return v_formats;
    }
    実行ファイル
    #include <iostream>
    #include "ClsDirectShow.h"
    
    int main()
    {
        //デバイス列挙情報の取得
        IEnumMoniker* pEnumMoniker = ClsDirectShow::video_init(NULL);
      //デバイスリストをコンソールに表示する
        ClsDirectShow::get_devices_list(pEnumMoniker);
        //カメラのプロパティを取得しコンソールに表示する
        ClsDirectShow::get_camera_settings(0, pEnumMoniker);
      //使用可能なビデオフォーマットをコンソールに表示する
        ClsDirectShow::get_videoformats_list(0, pEnumMoniker);
    }
    実行結果

    4.MediaFoundationによる画像の取得→OpenCV Matへの変換

    MediaFoundationは画像データの取得ができます。また画像サイズやビデオ形式の変更も対応できます。
    以下コードでは画像データを取得し、OpenCVのMatオブジェクトへの変換をしています。

    int main()
    {
    	HRESULT hr = CoInitialize(NULL);
    
    	//Microsoft Media Foundation の初期化
    	MFStartup(MF_VERSION);
    
    	IMFSourceReader* reader;
    
    	//デバイスの取得
    	IMFMediaSource* source;
    	std::wstring cameraName = L"ELECOM 5MP Webcam";
    	if (SUCCEEDED(CreateVideoCaptureDevice(cameraName, &source))) {
    		std::cout << "Succeed creating source." << std::endl;
    	}
     //キャプチャの作成
    	CreateVideoCaptureDevice(&source);
    	IMFMediaType* type = NULL;
     //ビデオタイプの取得
    	GetCurrentType(source, &type);
     //ピクセルサイズの取得
    	UINT32 uwidth= 0;
    	UINT32 uheight = 0;
    	GetFrameSize(type, &uwidth, &uheight);
     //ビデオフォーマットの取得
    	VideoFormatType format;
    	GetVideoFormat(type, &format);
     
     //ビデオフォーマットを"NV12"に設定する
    	PROPVARIANT val2;
    	PropVariantInit(&val2);
    	GUID guid = MFVideoFormat_NV12;
    	val2.vt = VT_CLSID;
    	val2.puuid = &guid;
    	hr = type->SetItem(MF_MT_SUBTYPE, val2);
     if (FAILED(hr)) {
    		std::cout << "Error setting item." << std::endl;
    		return 0;
    	}
      //ソースリーダーを作成する
    	hr = CreateSourceReader(source, &reader);
    	if (SUCCEEDED(hr))
    		std::cout << "Succeed creating reader." << std::endl;
     //静止画の画像データを取得する
    	auto data = Capture(reader);
    
     //OpenCV Matデータへ変換する NV12の場合
    	int width = uwidth;
    	int height = uheight;
    	cv::Mat bitmap = cv::Mat(height, width, CV_8UC3);
    
    	tbb::parallel_for(tbb::blocked_range<int>(0, height),
    		[&](tbb::blocked_range<int> r) {
    			for (int i = r.begin(); i < r.end(); ++i)
    			{
    
    				uchar* src_y = (uchar*)&data[i * width];
    				uchar* src_u = (uchar*)&data[width * height + i / 2 * width];
    				uchar* src_v = (uchar*)&data[width * height + i / 2 * width + 1];
    				uchar* dst = bitmap.ptr(i);
    				for (int j = 0; j < width; j++)
    				{
    					//R
    					dst[2] = std::min(std::max((CONVERT_R(src_y[0], src_v[0])), 0), 255);
    					//G
    					dst[1] = std::min(std::max(CONVERT_G(src_y[0], src_u[0], src_v[0]), 0), 255);
    					//B
    					dst[0] = std::min(std::max(CONVERT_B(src_y[0], src_u[0]), 0), 255);
    
    					dst = dst + 3;
    					src_y = src_y + 1;
    					if (j % 2 == 1) {
    						src_v = src_v + 2;
    						src_u = src_u + 2;
    					}
    				}
    			}
    		});
    
    	cv::imwrite("test.bmp", bitmap);
    
    	reader->Release();
    	MFShutdown();
    	CoUninitialize();
    	return 0;
    }
    使用した関数
    //デバイス名からキャプチャーデバイスを取得する
    HRESULT CreateVideoCaptureDevice(std::wstring& deviceName, IMFMediaSource** ppSource)
    {
    	*ppSource = NULL;
    
    	UINT32 count = 0;
    	IMFActivate** ppDevices = NULL;
    	IMFAttributes* pConfig = NULL;
    
    	// Create an attribute store to hold the search criteria.
    	HRESULT hr = MFCreateAttributes(&pConfig, 1);
    	// Set the device type to video.
    	if (SUCCEEDED(hr))
    	{
    		hr = pConfig->SetGUID(
    			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
    			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
    		);
    
    	}
    
    	// Enumerate the devices,
    	if (SUCCEEDED(hr))
    	{
    		hr = MFEnumDeviceSources(pConfig, &ppDevices, &count);
    	}
    
    	if (SUCCEEDED(hr))
    	{
    		if (count > 0)
    		{
    			for (int i = 0; i < count; i++) {
    
    				wchar_t* buffer;
    				uint32_t length;
    				hr = ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &buffer, &length);
    
    				if (SUCCEEDED(hr)) {
    					if (buffer != NULL) {
    						if (buffer == deviceName) {
    							hr = ppDevices[i]->ActivateObject(IID_PPV_ARGS(ppSource));
    							std::cout << "DeviceName: ";
    							char deviceName[1000];
    							size_t origsize = wcslen(buffer) + 1;
    							size_t strLength = 10;
    							const wchar_t* test=L"test";
    							
    							errno_t err=wcstombs_s(&strLength, deviceName, origsize, buffer, 1000);
    							std::cout << deviceName << std::endl;
    							break;
    						}
    					}
    				}
    			}
    		}
    		else
    		{
    			//hr = MF_E_NOT_FOUND;
    		}
    	}
    	std::cout << "kokomade" << std::endl;
    	for (DWORD i = 0; i < count; i++)
    	{
    		ppDevices[i]->Release();
    	}
    	CoTaskMemFree(ppDevices);
    	return hr;
    }
    //ソースからビデオフォーマットタイプを取得する
    static HRESULT GetCurrentType(IMFMediaSource* source, IMFMediaType** type)
    {
    	HRESULT hr;
    	BOOL selected;
    	IMFPresentationDescriptor* presDesc = NULL;
    	IMFStreamDescriptor* strmDesc = NULL;
    	IMFMediaTypeHandler* handler = NULL;
    
    	*type = NULL;
    
    	hr = source->CreatePresentationDescriptor(&presDesc);
    	if (FAILED(hr)) goto done;
    
    	hr = presDesc->GetStreamDescriptorByIndex(0, &selected, &strmDesc);
    	if (FAILED(hr)) goto done;
    
    	hr = strmDesc->GetMediaTypeHandler(&handler);
    	if (FAILED(hr)) goto done;
    
    	hr = handler->GetCurrentMediaType(type);
    	if (FAILED(hr)) goto done;
    
    done:
    	SafeRelease(&presDesc);
    	SafeRelease(&strmDesc);
    	SafeRelease(&handler);
    
    	return hr;
    }
    //ビデオフォーマットタイプから画像サイズ(幅、高さ)を取得する
    static HRESULT GetFrameSize(IMFMediaType* type,UINT32* width, UINT32* height)
    {
    	HRESULT hr;
    	PROPVARIANT var;
    
    	*width = 0;
    	*height = 0;
    	PropVariantInit(&var);
    	hr = type->GetItem(MF_MT_FRAME_SIZE, &var);
    	if (FAILED(hr)) return hr;
    
    	Unpack2UINT32AsUINT64(var.uhVal.QuadPart, width, height);
    	PROPVARIANT var1;
    	PropVariantInit(&var1);
    
    	hr = type->GetItem(MF_MT_DEFAULT_STRIDE, &var1);
    	INT32* stride = NULL;
    	return hr;
    }
    //ソースからリーダーオブジェクトを作成する
    HRESULT CreateSourceReader(IMFMediaSource* source, IMFSourceReader** reader)
    {
    	IMFSourceReader* p;
    	HRESULT hr;
    
    	*reader = NULL;
    	hr = MFCreateSourceReaderFromMediaSource(source, NULL, &p);
    	if (FAILED(hr)) {
    		printf("Failed create IMFSourceReader object\n");
    		return hr;
    	}
    
    	*reader = p;
    	return S_OK;
    }
    //画像データ取得しをRGB形式のバイト列に変換する
    std::vector<BYTE> Capture(IMFSourceReader* reader)
    {
    	DWORD flags;
    	IMFSample* sample = NULL;
    
    	DWORD streamIndex = 0;
    	LONGLONG timeStamp = 0;
    	REFPROPVARIANT varPosition{};
    	HRESULT hr;
    
    	while (true)
    	{
    		hr = reader->ReadSample((DWORD)MF_SOURCE_READER_ANY_STREAM, 0, &streamIndex, &flags, &timeStamp, &sample);
    
    		if (FAILED(hr)) {
    			std::cout << "Failed reading sample." << std::endl;
    			return std::vector<BYTE>();
    		}
    		else {
    			std::cout << "Succeed reading sample." << std::endl;
    		}
    
    		if (sample == nullptr) {
    			std::cout << "Sample is nullptr" << std::endl;
    			//return std::vector<BYTE>();
    		}
    		else {
    			std::cout << "Sample isnot nullptr" << std::endl;
    			break;
    		}
    	}
    
    	IMFMediaBuffer* buffer;
    	hr = sample->ConvertToContiguousBuffer(&buffer);
    	if (SUCCEEDED(hr))
    		std::cout << "Succeed getting buffers" << std::endl;
    
    	BYTE* p;
    	DWORD size;
    	buffer->Lock(&p, NULL, &size);
    	std::vector<BYTE> data(size);
    	memcpy(data.data(), p, size);
    	buffer->Unlock();
    
    	buffer->Release();
    	sample->Release();
    	return data;
    }

    5. 参考情報