VcamSource 接口
在VcamSource的數(shù)據(jù)源接口中,我們提供了6個(gè)必要的接口 :
gshort vcam_source_start(VcamSource* self);
void vcam_source_get_mediatype(VcamSource* self, VcamMediaInfo* info);
void vcam_source_pull_sample(VcamSource* self, GstSample* sample);
void vcam_source_pull_preroll(VcamSource* self, GstSample* sample);
void vcam_source_pull_sample2(VcamSource* self, GstMapInfo* map);
void vcam_source_pull_preroll2(VcamSource* self, GstMapInfo* map);
start接口用來(lái)啟動(dòng)gstreamer的pipleLine, 它應(yīng)該在dll被啟動(dòng)的時(shí)候調(diào)用枕赵,并且在dll退出的時(shí)候調(diào)用unref.
vcam_source_get_mediatype用來(lái)獲取媒體類(lèi)型饰剥,用于directshow組件的連接湃密。
其余4個(gè)都是獲取數(shù)據(jù)接口占调。我們主要使用vcam_source_pull_sample2來(lái)獲取自動(dòng)生成的數(shù)據(jù)正什。
我們需要將庫(kù)和頭文件引入directshow項(xiàng)目中,同時(shí)將該項(xiàng)目的靜態(tài)圖,加入連接配置:
gst-vcam集成VcamSource
dllmain的修改
在dllmain.cpp中引入頭文件VcamSource.h, 在入口函數(shù)dllmain處裹唆,我們需要調(diào)用gstrreamer的初始化函數(shù)誓斥,確保只調(diào)用一次。
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
gst_init(NULL, NULL);
return DllEntryPoint((HINSTANCE)(hModule), ul_reason_for_call, lpReserved);
}
gst-vcam.h的修改
增加一個(gè)私有屬性许帐, VcamSource指針劳坑,用來(lái)維護(hù)對(duì)vcamsoure的引用,另外增加析構(gòu)函數(shù)的聲明:
class CVCam : public CSource
{
......
CVCam::~CVCam();
protected:
CVCamStream* stream = nullptr;
//reference to gstreamer source
VcamSource* source=nullptr;
};
CVCam類(lèi)的修改
修改CVCam,在返回cvcam的時(shí)候成畦,同時(shí)創(chuàng)建一個(gè)VcamSource的實(shí)例距芬,這個(gè)實(shí)例有CVCam保存:
CVCam::CVCam(LPUNKNOWN lpunk, HRESULT* phr, const GUID id) :
CSource(NAME("GST Virtual CAM"), lpunk, id)
{
ASSERT(phr);
.......
source =(VcamSource*) g_object_new(VCAM_TYPE_SOURCE, NULL);
vcam_source_start(source);
}
新增一個(gè)析構(gòu)函數(shù),用來(lái)在cvcam退出時(shí)循帐,減少VcamSource的引用:
CVCam::~CVCam()
{
g_object_unref(source);
}
CVCamStream類(lèi)的修改
在CVCamStream類(lèi)中框仔,我們首先需要完成fillBuffer的工作,source接口提供了vcam_source_pull_sample2方法拄养,方便我們來(lái)獲取gstreamer生成的數(shù)據(jù)离斩。
HRESULT CVCamStream::FillBuffer(IMediaSample* pms) {
REFERENCE_TIME rtNow;
REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame; //獲取每幀播放間隔
rtNow = m_rtLastTime; //獲取上次計(jì)算的最后時(shí)間
m_rtLastTime += avgFrameTime; //計(jì)算本幀結(jié)束時(shí)間
pms->SetTime(&rtNow, &m_rtLastTime); //這只本真起始時(shí)間和結(jié)束時(shí)間
pms->SetSyncPoint(TRUE); //按本幀時(shí)間同步
BYTE* pData;
long lDataLen;
pms->GetPointer(&pData); //獲取buffer數(shù)據(jù)塊指針
/***
在本初填充真實(shí)數(shù)據(jù)
**/
GstMapInfo map;
vcam_source_pull_sample2(parent->source, &map);
if (map.data == NULL) {
return ERROR_EMPTY;
}
int leinght= map.size;
if (pms->GetSize() < map.size) leinght = pms->GetSize();
for (int i= 0; i < leinght; ++i) {
pData[i] = map.data[i];
}
for (int i = leinght; i < pms->GetSize(); ++i) {
pData[i] = rand();
}
//g_object_unref(map);
return NOERROR;
}
這里通過(guò)GstMapInfo map獲取來(lái)在gstreamer的數(shù)據(jù),然后把他填充到directshow的buffer里瘪匿。二外做的循環(huán)跛梗,時(shí)為了測(cè)試數(shù)據(jù)幀大小不一致時(shí),使用隨機(jī)數(shù)填充棋弥,方便界面發(fā)現(xiàn)茄袖。實(shí)際驗(yàn)證時(shí)可去除。
除了FillBuffer外嘁锯,另外兩個(gè)重要修改的方法時(shí)GetStreamCaps和GetMediaType,這里暫時(shí)不調(diào)用vcam_source_get_mediatype聂薪,減少驗(yàn)證復(fù)雜性:
HRESULT STDMETHODCALLTYPE CVCamStream::GetStreamCaps(int iIndex,
AM_MEDIA_TYPE** pmt, BYTE* pSCC)
{
if (iIndex < 0)
return E_INVALIDARG;
*pmt = CreateMediaType(&m_mt); //創(chuàng)建媒體類(lèi)型
DECLARE_PTR(VIDEOINFOHEADER, pvi, (*pmt)->pbFormat); //創(chuàng)建format類(lèi)型
//設(shè)置format
pvi->bmiHeader.biWidth = 320;
pvi->bmiHeader.biHeight = 240;
pvi->AvgTimePerFrame = 333333;
pvi->bmiHeader.biCompression = MAKEFOURCC('Y', 'U', 'Y', '2');
//pvi->bmiHeader.biCompression = BI_RGB;
pvi->bmiHeader.biBitCount = 16;
//pvi->bmiHeader.biBitCount = 24;
pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pvi->bmiHeader.biPlanes = 1;
//pvi->bmiHeader.biSizeImage = pvi->bmiHeader.biWidth *
// pvi->bmiHeader.biHeight * 2;
pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
pvi->bmiHeader.biClrImportant = 0;
SetRectEmpty(&(pvi->rcSource));
SetRectEmpty(&(pvi->rcTarget));
//設(shè)置meida Type
(*pmt)->majortype = MEDIATYPE_Video;
(*pmt)->subtype = MEDIASUBTYPE_YUY2;
//(*pmt)->subtype = MEDIASUBTYPE_RGB24;
(*pmt)->formattype = FORMAT_VideoInfo;
(*pmt)->bTemporalCompression = FALSE;
(*pmt)->bFixedSizeSamples = FALSE;
(*pmt)->lSampleSize = pvi->bmiHeader.biSizeImage;
(*pmt)->cbFormat = sizeof(VIDEOINFOHEADER);
//創(chuàng)建VIDEO_STREAM_CONFIG_CAPS結(jié)構(gòu)體
DECLARE_PTR(VIDEO_STREAM_CONFIG_CAPS, pvscc, pSCC);
//設(shè)置VIDEO_STREAM_CONFIG_CAPS
pvscc->guid = FORMAT_VideoInfo; //媒體類(lèi)型為FORMAT_VideoInfo
pvscc->VideoStandard = AnalogVideo_None; //不是模擬視頻
pvscc->InputSize.cx = pvi->bmiHeader.biWidth; //輸入寬度
pvscc->InputSize.cy = pvi->bmiHeader.biHeight; //輸入高度
pvscc->MinCroppingSize.cx = pvi->bmiHeader.biWidth; //最小可裁剪寬度 相當(dāng)于不允許水平裁剪
pvscc->MinCroppingSize.cy = pvi->bmiHeader.biHeight;//最小可裁剪高度
pvscc->MaxCroppingSize.cx = pvi->bmiHeader.biWidth;//最大可裁剪寬度
pvscc->MaxCroppingSize.cy = pvi->bmiHeader.biHeight;//最大可裁剪高度
pvscc->CropGranularityX = pvi->bmiHeader.biWidth; //水平裁剪增量
pvscc->CropGranularityY = pvi->bmiHeader.biHeight; //水平裁剪增量
pvscc->CropAlignX = 0; //水平對(duì)其
pvscc->CropAlignY = 0; //垂直對(duì)齊
pvscc->MinOutputSize.cx = pvi->bmiHeader.biWidth; //最小輸出寬度
pvscc->MinOutputSize.cy = pvi->bmiHeader.biHeight; //最小輸出高度度
pvscc->MaxOutputSize.cx = pvi->bmiHeader.biWidth; // 最大輸出寬度
pvscc->MaxOutputSize.cy = pvi->bmiHeader.biHeight; //最大輸出高度度
pvscc->OutputGranularityX = 0; //水平輸出變化增量
pvscc->OutputGranularityY = 0; //垂直輸出變化增量
pvscc->StretchTapsX = 0; //不允許tretching
pvscc->StretchTapsY = 0; //不允許tretching
pvscc->ShrinkTapsX = 0; //不允許Shrink
pvscc->ShrinkTapsY = 0; //不允許Shrink
pvscc->MinFrameInterval = pvi->AvgTimePerFrame; //最小幀間隔=平均幀播放時(shí)間
pvscc->MaxFrameInterval = pvi->AvgTimePerFrame; //最大幀間隔=平均幀播放時(shí)間
pvscc->MinBitsPerSecond = pvi->bmiHeader.biWidth * pvi->bmiHeader.biHeight
* 2 * 8 * (10000000 / pvi->AvgTimePerFrame); //最小輸出數(shù)據(jù)bit單位
pvscc->MaxBitsPerSecond = pvi->bmiHeader.biWidth * pvi->bmiHeader.biHeight
* 2 * 8 * (10000000 / pvi->AvgTimePerFrame); // 最大輸出數(shù)據(jù)bit單位
return S_OK;
}
上面的媒體類(lèi)型和format格式家乘,對(duì)應(yīng)在gstramer重,如下:
gst-launch-1.0 -v videotestsrc ! video/x-raw,width=320,height=240,FORMAT=YUY2,framerate=30/1 ! autovideosink
完成后藏澳,build gst-vcam項(xiàng)目仁锯,生成 gstvcam.dll ; 使用regsvr32 gstvcam.dll 進(jìn)行注冊(cè)翔悠,生成gst-vcam虛擬攝像頭信息:
使用graphedit, 創(chuàng)建一個(gè)測(cè)試graph,可以看到业崖,AVI Decompressor被用來(lái)作為轉(zhuǎn)化器:
同時(shí),使用gst-launch-1.0工具和grapEdit啟動(dòng)流畫(huà)面:
基本顯示一致蓄愁,只有一個(gè)小區(qū)域顏色不一致双炕。