使用Gstreamer 作為數(shù)據(jù)源輸出視頻數(shù)據(jù) VI 集成gstreamer

VcamSource 接口

在VcamSource的數(shù)據(jù)源接口中,我們提供了6個必要的接口 :

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接口用來啟動gstreamer的pipleLine, 它應(yīng)該在dll被啟動的時候調(diào)用,并且在dll退出的時候調(diào)用unref.
vcam_source_get_mediatype用來獲取媒體類型,用于directshow組件的連接。
其余4個都是獲取數(shù)據(jù)接口。我們主要使用vcam_source_pull_sample2來獲取自動生成的數(shù)據(jù)。

我們需要將庫和頭文件引入directshow項目中,同時將該項目的靜態(tài)圖,加入連接配置:


image.png

image.png

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的修改

增加一個私有屬性, VcamSource指針,用來維護對vcamsoure的引用,另外增加析構(gòu)函數(shù)的聲明:

class CVCam : public CSource
{
......
       CVCam::~CVCam();
protected:
    CVCamStream* stream = nullptr;
        //reference to gstreamer source
    VcamSource* source=nullptr;

};

CVCam類的修改

修改CVCam,在返回cvcam的時候,同時創(chuàng)建一個VcamSource的實例,這個實例有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òu)函數(shù),用來在cvcam退出時,減少VcamSource的引用:

CVCam::~CVCam()
{   
    g_object_unref(source);
}

CVCamStream類的修改

在CVCamStream類中,我們首先需要完成fillBuffer的工作,source接口提供了vcam_source_pull_sample2方法,方便我們來獲取gstreamer生成的數(shù)據(jù)。

HRESULT CVCamStream::FillBuffer(IMediaSample* pms) {
    REFERENCE_TIME rtNow;

    REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame;  //獲取每幀播放間隔

    rtNow = m_rtLastTime;  //獲取上次計算的最后時間
    m_rtLastTime += avgFrameTime;  //計算本幀結(jié)束時間
    pms->SetTime(&rtNow, &m_rtLastTime);  //這只本真起始時間和結(jié)束時間
    pms->SetSyncPoint(TRUE);  //按本幀時間同步

    BYTE* pData;
    long lDataLen;
    pms->GetPointer(&pData);  //獲取buffer數(shù)據(jù)塊指針
   /***
      在本初填充真實數(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;
}

這里通過GstMapInfo map獲取來在gstreamer的數(shù)據(jù),然后把他填充到directshow的buffer里。二外做的循環(huán),時為了測試數(shù)據(jù)幀大小不一致時,使用隨機數(shù)填充,方便界面發(fā)現(xiàn)。實際驗證時可去除。

除了FillBuffer外,另外兩個重要修改的方法時GetStreamCaps和GetMediaType,這里暫時不調(diào)用vcam_source_get_mediatype,減少驗證復(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)建媒體類型
    DECLARE_PTR(VIDEOINFOHEADER, pvi, (*pmt)->pbFormat); //創(chuàng)建format類型

        //設(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;  //媒體類型為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;  //水平對其
    pvscc->CropAlignY = 0;  //垂直對齊

    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;   //最小幀間隔=平均幀播放時間
    pvscc->MaxFrameInterval = pvi->AvgTimePerFrame; //最大幀間隔=平均幀播放時間
    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;
}

上面的媒體類型和format格式,對應(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項目,生成 gstvcam.dll ; 使用regsvr32 gstvcam.dll 進行注冊,生成gst-vcam虛擬攝像頭信息:


image.png

使用graphedit, 創(chuàng)建一個測試graph,可以看到,AVI Decompressor被用來作為轉(zhuǎn)化器:


image.png

同時,使用gst-launch-1.0工具和grapEdit啟動流畫面:
image.png

基本顯示一致,只有一個小區(qū)域顏色不一致。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容