简体   繁体   English

DirectShow摄像头流驱动程序

[英]DirectShow camera stream driver

I am a newbie in DirectShow programming and I am trying to create a sample grabber application in order to frequently grab frames (ie every 100 msec) from a video capture device. 我是DirectShow编程的新手,我试图创建一个示例采集器应用程序,以便经常从视频捕获设备中采集帧(即,每100毫秒)。

My source code is based in the SampleGrabber application which is available in the Windows SDK samples. 我的源代码基于Windows SDK示例中提供的SampleGrabber应用程序。

In general the driver works just fine using my PCs webcam. 通常,使用我的PC网络摄像头,驱动程序工作正常。 However, I do have some problems in using it with an Asus T100 tablet. 但是,在华硕T100平板电脑上使用它时确实存在一些问题。 In this case I am getting an error "libtbd error data is not tagged properly" just when I am trying to use ConnectFilters function, after setting the resolution of the camera. 在这种情况下,设置相机的分辨率后,仅当我尝试使用ConnectFilters函数时,我会收到一条错误消息“ libtbd错误数据未正确标记”。 The resolution I am trying to set to the camera is 1280x720 and I do know that the device can support it. 我要为相机设置的分辨率为1280x720,我知道该设备可以支持它。

Below I am attaching part of my code regarding the capturing function: 下面,我附上有关捕获功能的部分代码:

ICreateDevEnum *pSysDevEnum = 0;
IEnumMoniker *pEnumCams = 0;
IMoniker *pMon = 0;
IBaseFilter *CameraF = 0;

IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEventEx *pEvent = NULL;
IBaseFilter *pGrabberF = NULL;
ISampleGrabber *pSGrabber = NULL;
IBaseFilter *pSourceF = NULL;
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
IBaseFilter *pNullF = NULL;

BYTE *pBuffer = NULL;
HRESULT hr;
AM_MEDIA_TYPE mt;
int count = 0;

printf("Statting with capturing\n");
//Device list
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
    IID_ICreateDevEnum, (void **)&pSysDevEnum);
if (FAILED(hr)) 
    return false;

// Obtain a class enumerator for the video compressor category.
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
    &pEnumCams, 0);
if (hr != S_OK)
    return false;

// Enumerate the monikers. to desired device (0,1,2,...)
for (int i = 0; i <= cur_cam; ++i)
{
    hr = pEnumCams->Next(1, &pMon, NULL);
    if (hr != S_OK)
        return false;
}
//Get BaseFilter of chosen camera
hr = pMon->BindToObject(0, 0, IID_IBaseFilter, (void**)&CameraF);
if (hr != S_OK)
    return false;

//Create the Filter Graph Manager 
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
if (FAILED(hr))
    return false;

//Query for the IMediaControl and IMediaEventEx interfaces
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if (FAILED(hr))
    return false;

hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
if (FAILED(hr))
    return false;

// Add web camera to graph as source filter (because first?)
hr = pGraph->AddFilter(CameraF, L"Capture Source");
if (hr != S_OK)
    return false;

// Create an instance of the Sample Grabber Filter
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
    IID_PPV_ARGS(&pGrabberF));
if (FAILED(hr))
    return false;

// Add it to the filter graph.
hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
if (FAILED(hr))
    return false;

hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pSGrabber));
if (FAILED(hr))
    return false;

//Set the Media Type
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24 ;

hr = pSGrabber->SetMediaType(&mt);
if (FAILED(hr))
    return false;

//Building graph. Connecting Source (CameraF) and Sample Grabber
hr = CameraF->EnumPins(&pEnum);
if (FAILED(hr))
    return false;

while (S_OK == pEnum->Next(1, &pPin, NULL))
{
    hr = SetResolution(width_, height_, pPin);

    if (FAILED(hr))
        std::cout << "Failed to set resolution" << std::endl;

    hr = ConnectFilters(pGraph, pPin, pGrabberF);

    if (SUCCEEDED(hr))
    {
        std::cout << "Success to Connect Filter Graphs" << std::endl;
        break;
    }
    else{
        std::cout << "Failed to Connect Filter Graphs" << std::endl;
    }
}

if (FAILED(hr)){
    std::cout << "Failed A" << std::endl;
    return false;
}


SafeRelease(pPin);

//The following code connects the Sample Grabber to the Null Renderer filter:
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pNullF));
if (FAILED(hr))
    return false;

hr = pGraph->AddFilter(pNullF, L"Null Filter");
if (FAILED(hr))
    return false;

//ConnectFilters SamplerGrabber and Null Filter
hr = ConnectFilters(pGraph, pGrabberF, pNullF);
if (FAILED(hr))
    return false;

hr = pSGrabber->SetBufferSamples(TRUE);
if (FAILED(hr))
    return false;

hr = pSGrabber->SetOneShot(TRUE);//Halt after sample received
if (FAILED(hr))
    return false;

hr = pControl->Run();//Run filter graph
if (FAILED(hr))
    return false;

printf("Wait for a seconds to let cam sensor adopt to light\n");
Sleep(3000);//Wait 3 seconds
printf("OK\n");

//char filename[50];
printf("Go for the  loop");

for (;;){

    long evCode;
    while (1)
    {
        hr = pEvent->WaitForCompletion(INFINITE, &evCode);//Wait for frame
        if (evCode == EC_COMPLETE || evCode == EC_SYSTEMBASE)
            break;
        printf("Not complete. event: %d\n", evCode);
        pControl->Pause();//pause the Graph
        pSGrabber->SetOneShot(TRUE);//Set to halt after first frame
        hr = pControl->Run();//resume filter graph
        if (FAILED(hr))
            return false;
        Sleep(1000);//wait for a second
    }
    printf("out of while  loop");
    //if (hr != S_OK)
    //  return false;
    Sleep(100);
    //there frame got. Graph still running, but Sample Grabber halted

    // Find the required buffer size.
    long cbBufSize;
    hr = pSGrabber->GetCurrentBuffer(&cbBufSize, NULL);
    if (FAILED(hr))
        return false;

    pBuffer = (BYTE*)CoTaskMemAlloc(cbBufSize);
    if (!pBuffer)
    {
        hr = E_OUTOFMEMORY;
        return false;
    }

    hr = pSGrabber->GetCurrentBuffer(&cbBufSize, (long*)pBuffer);
    if (FAILED(hr))
        return false;


    hr = pSGrabber->GetConnectedMediaType(&mt);
    if (FAILED(hr))
        return false;


    // Examine the format block.
    if ((mt.formattype == FORMAT_VideoInfo) &&
        (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) && (mt.pbFormat != NULL))
    {
        VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;
        //sprintf_s(filename, sizeof(filename), "photo%d.bmp",++count);
        time_t t1 = time(NULL);
        SYSTEMTIME st;
        GetSystemTime(&st);

        printf("Save frame to file: %s - %02ld,%02ld.%03ld seconds\n", FileName, st.wMinute,st.wSecond, st.wMilliseconds );
        hr = WriteBitmap(FileName, &pVih->bmiHeader, mt.cbFormat - SIZE_PREHEADER,pBuffer, cbBufSize);
    }
    else
    {
        // Invalid format.
        hr = VFW_E_INVALIDMEDIATYPE;
        printf("Invalid frame format\n");
    }

    CoTaskMemFree(pBuffer);

    if ((GetAsyncKeyState(VK_ESCAPE) & 0x01))
        break;
    else if ((GetAsyncKeyState(VK_SPACE) & 0x01))
        CameraProperties(CameraF);

}

SafeRelease(pEnum);
SafeRelease(pNullF);
SafeRelease(pSourceF);
SafeRelease(pSGrabber);
SafeRelease(pGrabberF);
SafeRelease(pControl);
SafeRelease(pEvent);
SafeRelease(pGraph);

And below is the function which sets the camera resolution: 下面是设置相机分辨率的功能:

// Set the grabbing size
// First we iterate through the available media types and 
// store the first one that fits the requested size.
// If we have found one, we set it.
// In any case we query the size of the current media type
// to have this information for clients of this class.

HRESULT hr;

IAMStreamConfig *pConfig;
IEnumMediaTypes *pMedia;
AM_MEDIA_TYPE *pmt = NULL, *pfnt = NULL;

hr = pPin->EnumMediaTypes(&pMedia);
if (SUCCEEDED(hr))
{

    while (pMedia->Next(1, &pmt, 0) == S_OK)
    {
        if (pmt->formattype == FORMAT_VideoInfo)
        {
            VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)pmt->pbFormat;
            // printf("Size %i  %i\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight );
            if (vih->bmiHeader.biWidth == width_ && vih->bmiHeader.biHeight == height_)
            {
                pfnt = pmt;
                printf("found mediatype with %i %i\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight );
                break;
            }
            DeleteMediaType(pmt);
        }
    }
    pMedia->Release();
}
hr = pPin->QueryInterface(IID_IAMStreamConfig, (void **)&pConfig);
if (SUCCEEDED(hr))
{
    if (pfnt != NULL)
    {
        hr = pConfig->SetFormat(pfnt);
        DeleteMediaType(pfnt);
    }
    hr = pConfig->GetFormat(&pfnt);
    if (SUCCEEDED(hr))
    {

        m_nWidth = ((VIDEOINFOHEADER *)pfnt->pbFormat)->bmiHeader.biWidth;
        m_nHeight = ((VIDEOINFOHEADER *)pfnt->pbFormat)->bmiHeader.biHeight;

        DeleteMediaType(pfnt);
    }
}

Did anyone face this kind of problem before? 有人遇到过这种问题吗? Is there any mistakes in the capturing filters setup? 捕获过滤器设置中是否有任何错误?

Any ideas would be extremely helpful. 任何想法都将非常有帮助。

UPDATE 1 更新1

I am adding a screenshot of the application execution output. 我正在添加应用程序执行输出的屏幕截图。 Output 输出量

UPDATE 2 更新2

I tried to set the resolution using OpenCV 3.1, but I had the exact same problem. 我尝试使用OpenCV 3.1设置分辨率,但是我遇到了完全相同的问题。 The tablet is using the Intel(R) Imaging Signal Processor 2400 driver for the camera and this is the where the problem is located. 平板电脑正在使用英特尔(R)图像信号处理器2400驱动程序作为相机,这就是问题所在。 The strange think is that using AmCap I am able to both set the camera resolution and handle the camera device without any problems. 奇怪的是,使用AmCap,我既可以设置相机分辨率,又可以处理相机设备而没有任何问题。 Can please someone help? 可以请人帮忙吗? Does anyone knows what interface AmCap is using for communicating with the camera? 有谁知道AmCap使用什么接口与相机通讯?

I managed to resolve this issue. 我设法解决了这个问题。 It seems that the reported libdbd error was not related to the resolution change. 似乎报告的libdbd错误与分辨率更改无关。

The problem was that I was trying to set resolution by passing an unsupported video format in the SetFormat() function. 问题是我试图通过在SetFormat()函数中传递不受支持的视频格式来设置分辨率。 In detail the new working SetResolution() function became: 详细地,新的有效SetResolution()函数变为:

// Set the grabbing size
// First we iterate through the available media types and 
// store the first one that fits the requested size.
// If we have found one, we set it.
// In any case we query the size of the current media type
// to have this information for clients of this class.

HRESULT hr;

IAMStreamConfig *pConfig=NULL;
//IEnumMediaTypes *pMedia;
BYTE *pSCC = NULL;
AM_MEDIA_TYPE *pmt = NULL, *pfnt = NULL, *mfnt=NULL;

//hr = pPin->EnumMediaTypes(&pMedia);
int iCount, iSize;

hr = pPin->QueryInterface(IID_IAMStreamConfig, (void **)&pConfig);

hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
pSCC = new BYTE[iSize];
int i = 0;
if (SUCCEEDED(hr))
{
    while (i<=iCount)
    {
        pConfig->GetStreamCaps(i++, &pfnt, pSCC);

        VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)pfnt->pbFormat;
        printf("Size %i  %i\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight );
        if (vih->bmiHeader.biWidth == width_ && vih->bmiHeader.biHeight == height_)
        {
            //pfnt = mfnt;
            printf("Found mediatype with %i %i - %x\n", vih->bmiHeader.biWidth, vih->bmiHeader.biHeight, pfnt->formattype );
            hr = pConfig->SetFormat(pfnt);
            //break;
        }

    }
}

//DeleteMediaType(pfnt);
delete[] pSCC;
pConfig->Release();
return hr;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM