4

Я реализую видеозапись в реальном времени через DirectShow для прямой обработки и отображения. (Приложение «Расширенная реальность»).Как захватить камеры в реальном времени в RGB с DirectShow

Я могу получить доступ к пикселям достаточно легко, но, похоже, я не могу получить SampleGrabber для предоставления данных RGB. Устройство (iSight - запуск VC++ Express в VMWare) сообщает только MEDIASUBTYPE_YUY2.

После обширного Googling я все еще не могу понять, будет ли DirectShow обеспечивать встроенное преобразование цветового пространства для такого рода вещей. Некоторые сайты сообщают, что нет YUV < -> Преобразование RGB, others сообщают, что вам просто нужно вызвать SetMediaType на вашем ISampleGrabber с подтипом RGB.

Любые советы приветствуются, я собираюсь сходить с ума. Код приведен ниже. Обратите внимание, что

  • код работает, за исключением того, что он не обеспечивает данные RGB
  • Я знаю, что я могу реализовать свой собственный фильтр преобразования, но это не представляется возможным, потому что я должен был бы предвидеть все возможные формат устройства, и это относительно небольшой проект

    // Playback 
    IGraphBuilder *pGraphBuilder = NULL; 
    ICaptureGraphBuilder2 *pCaptureGraphBuilder2 = NULL; 
    IMediaControl *pMediaControl = NULL; 
    IBaseFilter *pDeviceFilter = NULL; 
    IAMStreamConfig *pStreamConfig = NULL; 
    BYTE *videoCaps = NULL; 
    AM_MEDIA_TYPE **mediaTypeArray = NULL; 
    
    // Device selection 
    ICreateDevEnum *pCreateDevEnum = NULL; 
    IEnumMoniker *pEnumMoniker = NULL; 
    IMoniker *pMoniker = NULL; 
    ULONG nFetched = 0; 
    
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 
    
    // Create CreateDevEnum to list device 
    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (PVOID *)&pCreateDevEnum); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // Create EnumMoniker to list devices 
    hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumMoniker, 0); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    pEnumMoniker->Reset(); 
    
    // Find desired device 
    while (pEnumMoniker->Next(1, &pMoniker, &nFetched) == S_OK) 
    { 
        IPropertyBag *pPropertyBag; 
        TCHAR devname[256]; 
    
        // bind to IPropertyBag 
        hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropertyBag); 
    
        if (FAILED(hr)) 
        { 
        pMoniker->Release(); 
        continue; 
        } 
    
        VARIANT varName; 
        VariantInit(&varName); 
        HRESULT hr = pPropertyBag->Read(L"DevicePath", &varName, 0); 
    
        if (FAILED(hr)) 
        { 
        pMoniker->Release(); 
        pPropertyBag->Release(); 
        continue; 
        } 
    
        char devicePath[DeviceInfo::STRING_LENGTH_MAX] = ""; 
    
        wcstombs(devicePath, varName.bstrVal, DeviceInfo::STRING_LENGTH_MAX); 
    
        if (strcmp(devicePath, deviceId) == 0) 
        { 
        // Bind Moniker to Filter 
        pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pDeviceFilter); 
    
        break; 
        } 
    
        pMoniker->Release(); 
        pPropertyBag->Release(); 
    } 
    
    if (pDeviceFilter == NULL) goto ReleaseDataAndFail; 
    
    // Create sample grabber 
    IBaseFilter *pGrabberF = NULL; 
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pGrabberF); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    hr = pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // Create FilterGraph 
    hr = CoCreateInstance(CLSID_FilterGraph, 
    NULL, 
    CLSCTX_INPROC, 
    IID_IGraphBuilder, 
    (LPVOID *)&pGraphBuilder); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // create CaptureGraphBuilder2 
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (LPVOID *)&pCaptureGraphBuilder2); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // set FilterGraph 
    hr = pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // get MediaControl interface 
    hr = pGraphBuilder->QueryInterface(IID_IMediaControl, (LPVOID *)&pMediaControl); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // Add filters 
    hr = pGraphBuilder->AddFilter(pDeviceFilter, L"Device Filter"); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    hr = pGraphBuilder->AddFilter(pGrabberF, L"Sample Grabber"); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // Set sampe grabber options 
    AM_MEDIA_TYPE mt; 
    ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); 
    mt.majortype = MEDIATYPE_Video; 
    mt.subtype = MEDIASUBTYPE_RGB32; 
    hr = pGrabber->SetMediaType(&mt); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    hr = pGrabber->SetOneShot(FALSE); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    hr = pGrabber->SetBufferSamples(TRUE); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    // Get stream config interface 
    hr = pCaptureGraphBuilder2->FindInterface(NULL, &MEDIATYPE_Video, pDeviceFilter, IID_IAMStreamConfig, (void **)&pStreamConfig); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    int streamCapsCount = 0, capsSize, bestFit = -1, bestFitPixelDiff = 1000000000, desiredPixelCount = _width * _height, 
    bestFitWidth = 0, bestFitHeight = 0; 
    
    float desiredAspectRatio = (float)_width/(float)_height; 
    
    hr = pStreamConfig->GetNumberOfCapabilities(&streamCapsCount, &capsSize); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    videoCaps = (BYTE *)malloc(capsSize * streamCapsCount); 
    mediaTypeArray = (AM_MEDIA_TYPE **)malloc(sizeof(AM_MEDIA_TYPE *) * streamCapsCount); 
    
    for (int i = 0; i < streamCapsCount; i++) 
    { 
        hr = pStreamConfig->GetStreamCaps(i, &mediaTypeArray[i], videoCaps + capsSize * i); 
        if (FAILED(hr)) continue; 
    
        VIDEO_STREAM_CONFIG_CAPS *currentVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *)(videoCaps + capsSize * i); 
    
        int closestWidth = MAX(currentVideoCaps->MinOutputSize.cx, MIN(currentVideoCaps->MaxOutputSize.cx, width)); 
        int closestHeight = MAX(currentVideoCaps->MinOutputSize.cy, MIN(currentVideoCaps->MaxOutputSize.cy, height)); 
    
        int pixelDiff = ABS(desiredPixelCount - closestWidth * closestHeight); 
    
        if (pixelDiff < bestFitPixelDiff && ABS(desiredAspectRatio - (float)closestWidth/(float)closestHeight) < 0.1f) 
        { 
        bestFit = i; 
        bestFitPixelDiff = pixelDiff; 
        bestFitWidth = closestWidth; 
        bestFitHeight = closestHeight; 
        } 
    } 
    
    if (bestFit == -1) goto ReleaseDataAndFail; 
    
    AM_MEDIA_TYPE *mediaType; 
    hr = pStreamConfig->GetFormat(&mediaType); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    VIDEOINFOHEADER *videoInfoHeader = (VIDEOINFOHEADER *)mediaType->pbFormat; 
    videoInfoHeader->bmiHeader.biWidth = bestFitWidth; 
    videoInfoHeader->bmiHeader.biHeight = bestFitHeight; 
    //mediaType->subtype = MEDIASUBTYPE_RGB32; 
    hr = pStreamConfig->SetFormat(mediaType); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    pStreamConfig->Release(); 
    pStreamConfig = NULL; 
    
    free(videoCaps); 
    videoCaps = NULL; 
    free(mediaTypeArray); 
    mediaTypeArray = NULL; 
    
    // Connect pins 
    IPin *pDeviceOut = NULL, *pGrabberIn = NULL; 
    
    if (FindPin(pDeviceFilter, PINDIR_OUTPUT, 0, &pDeviceOut) && FindPin(pGrabberF, PINDIR_INPUT, 0, &pGrabberIn)) 
    { 
        hr = pGraphBuilder->Connect(pDeviceOut, pGrabberIn); 
        if (FAILED(hr)) goto ReleaseDataAndFail; 
    } 
    else 
    { 
        goto ReleaseDataAndFail; 
    } 
    
    // start playing 
    hr = pMediaControl->Run(); 
    if (FAILED(hr)) goto ReleaseDataAndFail; 
    
    hr = pGrabber->GetConnectedMediaType(&mt); 
    
    // Set dimensions 
    width = bestFitWidth; 
    height = bestFitHeight; 
    _width = bestFitWidth; 
    _height = bestFitHeight; 
    
    // Allocate pixel buffer 
    pPixelBuffer = (unsigned *)malloc(width * height * 4); 
    
    // Release objects 
    pGraphBuilder->Release(); 
    pGraphBuilder = NULL; 
    pEnumMoniker->Release(); 
    pEnumMoniker = NULL; 
    pCreateDevEnum->Release(); 
    pCreateDevEnum = NULL; 
    
    return true; 
    

ответ

4

шток цветового пространства конвертер не поддерживает YUY2 для преобразования RGB. Тем не менее, существует множество приложений и устройств, которые устанавливают какой-то конвертер, и если это будет правильно зарегистрировано, dshow будет использовать его автоматически. Вот почему некоторые люди сообщают, что это просто работает. (конечно, некоторые устройства предлагают RGB, поэтому в этих случаях конвертация не требуется).

Вы можете скачать свободно распространяемый фильтр преобразования YUV, «yuvxfm» от YUV Transform (at the bottom of the page). Зарегистрируйте это в своей системе, и он должен допускать захват в любом разумном формате RGB или YUV.

G

+0

Большое спасибо за ваш информативный ответ. Я попытался добавить фильтр yuvxfm между устройством и образцом захвата, который работал. Тем не менее, я также обнаружил, что если он также работает без него. Я попробовал незарегистрировать yuvxfm и перешел непосредственно из устройства в граббер образца rgb. Я не знаю, почему это не сработало раньше. Я запускаю почти новую установку XP SP3. Также попробовал это на Windows 7, что тоже работает. Итак, где происходит преобразование YUY2 в RGB? Могу ли я зависеть от этого? – Simplex

+0

Да. Его AviDecompressor, который поддерживает YUY2 FourCC. См. Http://msdn.microsoft.com/en-us/library/dd375464%28v=VS.85%29.aspx для списка фильтров, которые предоставляются. – Christopher

+0

AviDecompressor - это оболочка для видео кодеков Windows. Вероятно, у вас установлен кодек VfW, который делает преобразование YUY2, но это зависит от системы. Оберточный фильтр Avi Decompressor может присутствовать без поддержки YUY2 в некоторых системах. –

Смежные вопросы