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. 参考情報