【问题标题】:DirectShow camera stream driverDirectShow 摄像头流驱动程序
【发布时间】:2016-10-05 09:01:39
【问题描述】:

我是 DirectShow 编程的新手,我正在尝试创建一个示例抓取器应用程序,以便频繁地从视频捕获设备抓取帧(即每 100 毫秒)。

我的源代码基于 Windows SDK 示例中提供的 SampleGrabber 应用程序。

一般来说,驱动程序使用我的 PC 网络摄像头工作得很好。但是,我在使用华硕 T100 平板电脑时确实遇到了一些问题。在这种情况下,我在设置相机分辨率后尝试使用 ConnectFilters 功能时收到错误“libtbd 错误数据未正确标记”。我试图为相机设置的分辨率是 1280x720,我知道该设备可以支持它。

下面我附上我关于捕获功能的部分代码:

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);

下面是设置相机分辨率的函数:

// 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);
    }
}

以前有人遇到过这种问题吗?捕获过滤器设置是否有任何错误?

任何想法都会非常有帮助。

更新 1

我正在添加应用程序执行输出的屏幕截图。 Output

更新 2

我尝试使用 OpenCV 3.1 设置分辨率,但我遇到了完全相同的问题。平板电脑正在使用 Intel(R) Imaging Signal Processor 2400 驱动程序用于摄像头,这就是问题所在。奇怪的想法是,使用AmCap 我既可以设置相机分辨率,又可以毫无问题地处理相机设备。可以请人帮忙吗?有谁知道 AmCap 使用什么接口与相机通信?

【问题讨论】:

  • 错误信息不属于 DirectShow。哪种方法给出它,或者它是一个消息框?听起来像是华硕软件的问题。
  • 您好,感谢您的回答。我在尝试设置相机分辨率并将派生过滤器连接到我的图表时收到此错误。 SetResolution(width_, height_, pPin); hr = ConnectFilters(pGraph, pPin, pGrabberF);
  • @mike1821 但是你是怎么得到这个错误的?可以给个截图吗?
  • 您好,再次感谢您的反馈。我添加了应用程序执行的屏幕截图。
  • 您没有输出此错误的printf。这意味着视频捕获驱动程序以某种方式发出它。总的来说,您应该忽略它,因为您不应该处理它。您的任务是处理作为 HRESULT 值返回的错误。总而言之,这是相机驱动程序(华硕?)的问题。

标签: c++ windows video camera directshow


【解决方案1】:

我设法解决了这个问题。似乎报告的 libdbd 错误与分辨率更改无关。

问题是我试图通过在 SetFormat() 函数中传递不受支持的视频格式来设置分辨率。详细来说,新的工作 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;

【讨论】:

    猜你喜欢
    • 2010-12-10
    • 1970-01-01
    • 2010-12-07
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 2013-08-17
    • 2019-09-01
    • 2013-03-14
    相关资源
    最近更新 更多