Video Capture mit directshow



  • Hallo zusammen,

    ich arbeite zur Zeit daran eine kleine Konsolen Applikation zu basteln, die meinen directshow Stream eines Framegrabbers auffängt und anzeigt.

    Die MSDN Dokumentation hab ich mir dabei als Anhaltspunkt zur Hilfe gezogen.

    https://msdn.microsoft.com/de-de/library/windows/desktop/dd377468(v=vs.85).aspx

    Der nachfolgende Code ist größtenteils nur kopiert. Leider bekomme ich jedesmal einen Fehler, wenn ich versuche einen capture filter zu erstellen. Die Methode "BindToObject" liefert mit an der entsprechenden Stelle jedesmal den Wert "E_FAIL". Wohingegen ich hier "S_OK" erwarte.

    Ist gut möglich, dass hier ein simpler Fehler im Code steckt, da ich kein C++ Profi bin. Ich komme einfach nicht weiter.

    Habe die Stelle im Code mit "HIER" kommentiert.

    IEnumMoniker *pEnum = NULL;
    ICaptureGraphBuilder2 *pBuild = NULL;
    IGraphBuilder *pGraph = NULL;
    IBaseFilter *pCap = NULL;
    IMoniker *pMoniker = NULL;
    HRESULT hr = NULL;
    ICreateDevEnum *pDevEnum = NULL;
    
    HRESULT InitCaptureGraphBuilder(
      IGraphBuilder **ppGraph,  // Receives the pointer.
      ICaptureGraphBuilder2 **ppBuild  // Receives the pointer.
    );
    HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum);
    void DisplayDeviceInformation(IEnumMoniker *pEnum);
    
    void wmain(){
    	hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    	hr = InitCaptureGraphBuilder(&pGraph, &pBuild);
    	if(FAILED(hr)){
    		cout <<"CaptureGraphBuilder fehlgeschlagen";
    	}
        if (SUCCEEDED(hr))
        {
            hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
            if (SUCCEEDED(hr))
            {
                DisplayDeviceInformation(pEnum);
               // pEnum->Release();
            }    
        }
    	//HIER
    	hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
    	if (SUCCEEDED(hr))
    	{
    	  hr = pGraph->AddFilter(pCap, L"Capture Filter");
    	}
    
    	hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, 
        pCap, NULL, NULL);
    }  
    
    HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
    {
        // Create the System Device Enumerator.
         hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,  
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
    
        if (SUCCEEDED(hr))
        {
            // Create an enumerator for the category.
            hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
            if (hr == S_FALSE)
            {
                hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
            }
           // pDevEnum->Release();
        }
        return hr;
    }
    
    void DisplayDeviceInformation(IEnumMoniker *pEnum)
    {
    
        while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
        {
            IPropertyBag *pPropBag;
            HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
            if (FAILED(hr))
            {
                pMoniker->Release();
                continue;  
            } 
    
            VARIANT var;
            VariantInit(&var);
    
            // Get description or friendly name.
            hr = pPropBag->Read(L"Description", &var, 0);
            if (FAILED(hr))
            {
                hr = pPropBag->Read(L"FriendlyName", &var, 0);
            }
            if (SUCCEEDED(hr))
            {
                printf("%S\n", var.bstrVal);
                VariantClear(&var); 
            }
    
            hr = pPropBag->Write(L"FriendlyName", &var);
    
            // WaveInID applies only to audio capture devices.
            hr = pPropBag->Read(L"WaveInID", &var, 0);
            if (SUCCEEDED(hr))
            {
                printf("WaveIn ID: %d\n", var.lVal);
                VariantClear(&var); 
            }
    
            hr = pPropBag->Read(L"DevicePath", &var, 0);
            if (SUCCEEDED(hr))
            {
                // The device path is not intended for display.
                printf("Device path: %S\n", var.bstrVal);
                VariantClear(&var); 
            }
    
            pPropBag->Release();
            pMoniker->Release();
        }
    }
    
    HRESULT InitCaptureGraphBuilder(
      IGraphBuilder **ppGraph,  // Receives the pointer.
      ICaptureGraphBuilder2 **ppBuild  // Receives the pointer.
    )
    {
        if (!ppGraph || !ppBuild)
        {
            return E_POINTER;
        }
        IGraphBuilder *pGraph2 = NULL;
        ICaptureGraphBuilder2 *pBuild2 = NULL;
    
        // Create the Capture Graph Builder.
         hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, 
            CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild2 );
        if (SUCCEEDED(hr))
        {
            // Create the Filter Graph Manager.
            hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
                IID_IGraphBuilder, (void**)&pGraph2);
            if (SUCCEEDED(hr))
            {
                // Initialize the Capture Graph Builder.
                pBuild2->SetFiltergraph(pGraph2);
    
                // Return both interface pointers to the caller.
                *ppBuild = pBuild2;
                *ppGraph = pGraph2; // The caller must release both interfaces.
                return S_OK;
            }
            else
            {
               // pBuild->Release();
            }
        }
        return hr; // Failed
    }
    

    Bin für jegliche Tips bzgl. dem Code und rundum directshow dankbar.

    Liebe Grüße
    saladin



  • Nutz doch VFW



  • Du arbeitest mit einem globalen Objekt, dass Du längst freigegeben hast und daher nicht mehr existiert:

    saladin schrieb:

    void DisplayDeviceInformation(IEnumMoniker *pEnum)
    {
        while (pEnum->Next(1, &pMoniker, NULL) == S_OK) // Moniker holen
        {
            .
            .
            .
            pMoniker->Release(); // Moniker wieder freigeben
        }
    }
    

    Achromat schrieb:

    Der einzigste Weg ist es lauffähige DxShow Beispiele ...

    HILFE!!!



  • Hat damit leider nichts zu tun. Hab schon sämtliche Releases auskommentiert.

    Mox schrieb:

    Du arbeitest mit einem globalen Objekt, dass Du längst freigegeben hast und daher nicht mehr existiert:

    saladin schrieb:

    void DisplayDeviceInformation(IEnumMoniker *pEnum)
    {
        while (pEnum->Next(1, &pMoniker, NULL) == S_OK) // Moniker holen
        {
            .
            .
            .
            pMoniker->Release(); // Moniker wieder freigeben
        }
    }
    

    Achromat schrieb:

    Der einzigste Weg ist es lauffähige DxShow Beispiele ...

    HILFE!!!



  • Ein Beispiel auf CodeProject habe ich tatsächlich gefunden. Allerdings mag das Sample meine Kamera auch nicht.

    Die Samples von directshow selbst sind, soweit ich weis leider nicht mehr verfügbar.

    Directshow arbeitet meines Erachtens nur anständig mit Geräten, die auch einen Direktshow stream liefern (bzgl. VideoCapture). Mein Rechner ist ausgestattet mit einem Framegrabber und einer CableLink Camera.

    Gibts es Tools mit denen ich prüfen kann, ob mein Framegrabber auch tatsächlich einen directshow stream liefert ?

    Achromat schrieb:

    Hallo,

    direct Show und auch WIA ist gegenüber VFW ein schwerer Fehlschlag, hier wurde versucht und einzig dafür ist DxShow erstellt worden, minderwertige 640pixel Sensoren als Full HD Sensoren verkaufen zu können indem über sogenannte Filter Bilder gesammelt und vergrößert werden ohne das es dafür eine Physikalische Grundlage gäbe.

    Das DirectShow ist derart verworren, das nur für dessen Handhabung ca. 6 Monate
    intensive Beschäftigung damit nötig ist.

    Der einzigste Weg ist es lauffähige DxShow Beispiele aus www.CodeProject.com
    zu kompilieren und schrittweise damit glücklich zu werden.

    Nutze VFW seit Win3.11 macht es den Entwickler glücklich, es gibt keine HD USB WebCams.



  • Zeigen, damit wir vom selben Code reden. Und gebe einen IBinCtx an, das kann nicht schaden:

    IBindCtx* pbc = nullptr;
    CreateBindCtx(0, &pbc);
    hr = pMoniker->BindToObject(pbc, 0, IID_IBaseFilter, (void**)&pCap);
    pbc->Release();
    


  • Das heißt CameraLink nicht CableLink, ist ein Industriestandard.

    Diese Kameras kommen in DxShow nicht oft vor.
    Du musst schon die FirmenSoftware des Grabbers installieren.



  • saladin schrieb:

    Gibts es Tools mit denen ich prüfen kann, ob mein Framegrabber auch tatsächlich einen directshow stream liefert ?

    Du siehst anhand Deines Enumerators, was Dir zur Verfügung steht. Hast Du Dir die Ausgaben Deines Programmes überhaupt mal angesehen?



  • Sorry ^^... meinte natürlich CameraLink.... Das sind schon mal sehr gute Hinweise... Die Software des Grabbers ist natürlich schon installiert. Aber ich möchte eine eigene Applikation basteln.

    Aber danke erstmal für die Referenzen. Da werd ich mich erst mal einlesen.

    Vielen Dank

    Achromat schrieb:

    Das heißt CameraLink nicht CableLink, ist ein Industriestandard.
    Meist von MicroEnable Dalsa und andere verwendet.

    Diese Kameras kommen in DxShow nicht vor!

    Du musst schon die FirmenSoftware des Grabbers installieren.

    Wie die unterschiedlichen Camera-Systeme zu handhaben sein könnten, siehst Du hier http://flexxvision.de/kameras.html Dort gibt es auch ein SDK um mit deren
    Wrapper auf verschiedene Methoden zugreifen zu können. Man kann es
    auch selber machen wenn man ein langlebiger ist.

    Jedoch dann mit der Firmware der Grabber-hersteller, wo Du dann deine JAI oder ´Dalsa Kamera eintragen musst.

    Vergiss es mit der Hand -"logisch" auf DirectShow zuzugreifen, ohne ein funktionierendes Example aus dem Netz zu besitzen.

    Grüßsschen
    Karsten



  • Klaro...

    Hier die Konsolenausgabe:
    http://www.bilder-upload.eu/show.php?file=a62221-1464880395.png

    Hier die Demo, dass mein HRESULT Objekt auf Fail gesetzt wird:
    http://www.bilder-upload.eu/show.php?file=22fd68-1464880492.png

    Mox schrieb:

    saladin schrieb:

    Gibts es Tools mit denen ich prüfen kann, ob mein Framegrabber auch tatsächlich einen directshow stream liefert ?

    Du siehst anhand Deines Enumerators, was Dir zur Verfügung steht. Hast Du Dir die Ausgaben Deines Programmes überhaupt mal angesehen?



  • Mox schrieb:

    Du siehst anhand Deines Enumerators, was Dir zur Verfügung steht.
    Hast Du Dir die Ausgaben Deines Programmes überhaupt mal angesehen?

    saladin schrieb:

    Klaro...

    Hier die Konsolenausgabe:
    http://www.bilder-upload.eu/show.php?file=a62221-1464880395.png

    Hier die Demo, dass mein HRESULT Objekt auf Fail gesetzt wird:
    http://www.bilder-upload.eu/show.php?file=22fd68-1464880492.png

    Wirklich??

    Die erste Frage wäre ob beim enummerieren das gewünschte Gerät dabei.

    Wenn das Gerät dabei ist, müsste man sich diesen Moniker merken und ihn danach
    für die weiteren Funktionen verwenden.

    Hier wird über alles enummeriert und alle Moniker werden danach released.

    Es macht keinen Sinn Release auszukommentieren 😉

    Der gesuchte Moniker in

    DisplayDeviceInformation(pEnum)
    

    darf auch nicht überschrieben werden...

    Zuerst muss man mal feststellen ob das Gerät da ist:

    // Get description or friendly name.
    		hr = pPropBag->Read(L"Description", &var, 0);
    		if (FAILED(hr))
    		{
    			hr = pPropBag->Read(L"FriendlyName", &var, 0);
    		}
    		if (SUCCEEDED(hr))
    		{
    			cout << var.bstrVal << endl;
    			wstring vgl(var.bstrVal);
    			if(vgl.compare(TEXT("Basler Camera xxx")) == 0)
    			  gefunden = true;
    			VariantClear(&var);
    		}
    

    Wenn gefunden true ist sollte dieser Moniker verwendet werden ...


Log in to reply