1. はじめに
DirectShowによる仮想カメラ開発の機会がありましたので、参考にした記事等を記載いたします。
ここではDirectShowによる具体的な実装の説明は省かせていただきます。
2. 仮想カメラ開発の先駆者さま方による記事
これをみて勉強しました。
① 日本語で分かりやすい仮想カメラ実装の解説記事
② 海外でポピュラーな仮想カメラ実装の最新コード
Visual Studio 2019 に対応
DirectShowのコア部分たるBaseClassesは開発元のMicrosoftによる更新が滞っており、これまで開発環境を選ぶ状態でした。が!
たまたまBaseClassesをVisual Studio 2019にアップグレードしたものをみつけました。上記の仮想カメラ実装で使われております。
3. 仮想カメラのコードをみてみよう
手っ取り早く実装したい方は、2項 ② の仮想カメラのコードをベースに、以下の項目を弄るとよいでしょう。
① 映像を出力するモジュールの初期化処理
Filters/Filters.cpp
CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
CSourceStream(NAME("Virtual Cam"),phr, pParent, pPinName), m_pParent(pParent)
{
////////////////////
// 映像出力モジュールの初期化処理を書く
////////////////////
// Set the default media type as 320x240x24@15
GetMediaType(4, &m_mt);
}
② 映像を出力するモジュールの更新処理
Filters/Filters.cpp
HRESULT CVCamStream::FillBuffer(IMediaSample *pms)
{
REFERENCE_TIME rtNow;
REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame;
rtNow = m_rtLastTime;
m_rtLastTime += avgFrameTime;
pms->SetTime(&rtNow, &m_rtLastTime);
pms->SetSyncPoint(TRUE);
BYTE *pData;
long lDataLen;
pms->GetPointer(&pData);
////////////////////
// 出力映像の更新
// output : RGB24
// 例. ランダム画像を出力する
lDataLen = pms->GetSize();
for(int i = 0; i < lDataLen; ++i)
pData[i] = rand();
// 例. おわり
////////////////////
return NOERROR;
} // FillBuffer
②仮想カメラの横幅、高さ、FPS
Filters/Filters.cpp
// See Directshow help topic for IAMStreamConfig for details on this method
HRESULT CVCamStream::GetMediaType(int iPosition, CMediaType *pmt)
{
if(iPosition < 0) return E_INVALIDARG;
if(iPosition > 8) return VFW_S_NO_MORE_ITEMS;
if(iPosition == 0)
{
*pmt = m_mt;
return S_OK;
}
DECLARE_PTR(VIDEOINFOHEADER, pvi, pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)));
ZeroMemory(pvi, sizeof(VIDEOINFOHEADER));
pvi->bmiHeader.biCompression = BI_RGB;
pvi->bmiHeader.biBitCount = 24;
pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
////////////////////
// 第一引数 iPositionによって横幅、高さを設定する
pvi->bmiHeader.biWidth = 80 * iPosition;
pvi->bmiHeader.biHeight = 60 * iPosition;
////////////////////
pvi->bmiHeader.biPlanes = 1;
pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
pvi->bmiHeader.biClrImportant = 0;
pvi->AvgTimePerFrame = 1000000;
SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered.
SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle
pmt->SetType(&MEDIATYPE_Video);
pmt->SetFormatType(&FORMAT_VideoInfo);
pmt->SetTemporalCompression(FALSE);
// Work out the GUID for the subtype from the header info.
const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader);
pmt->SetSubtype(&SubTypeGUID);
pmt->SetSampleSize(pvi->bmiHeader.biSizeImage);
return NOERROR;
} // GetMediaType
(追記予定)
③仮想カメラの名前、識別用ID
(追記予定)
(余談)配布されている汎用仮想カメラの最強は?
OBS Studioの仮想カメラでなんでもできます
OBS Studio v26以降にて標準搭載の仮想カメラ機能により、OBS画面をそのままフィルタに流せます。普通の仮想カメラの用途ならこれで十分。
OBSで仮想カメラ4個ほしい!
OBS Studio 25.08 + obs-virtualcam 2.0.5
obs-virtualcam のソースコードについても仮想カメラ実装例として参考になるかと思います。
以上
時間ができたら追記いたします。