Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen



  • Ja, CoInitilizeEx rufe ich in in der main auf:

    int main() {
    	HRESULT result;
    	IDeckLink* deckLink = nullptr;
    	IDeckLinkIterator* deckLinkIterator = nullptr;
    
    	//initializing COM
    	if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
    		std::cout << "COM can't be initialized" << std::endl;
    		return 1;
    	}
    
    
    	InitializeDecklink* init = new InitializeDecklink(deckLink);
    	init->InitDeckLink();
    	init->PrintDevice();
    	delete init;
    	
    	ControlVideo* control = new ControlVideo(deckLink);
    	control->ListDisplayMode();
    	delete control;
    
    	CoUninitialize();
    
    	return 0;
    }
    


  • @makopo
    An welcher Stelle schlägt denn was fehlt? Gibt es da einen HRESULT Rückgabecode?



  • @Quiche-Lorraine Der Debugger meldet oberflächlich in Zeile 18 der ControlVideo-Klasse das m_deckLink und m_deckLinkInput NULL sind. Wenn man genauer in Meldung schaut steht dort das der virtual function pointer von IUnknown den Speicher nicht lesen kann.

    Ich bin habe noch keine wirkliche Erfahrung mit der COM-Programmierung (das ganze ist ein Projekt aus dem Studium). Nach allem was ich bisher gelesen habe, muss man ja für jedes weitere Interface das man benutzen möchte, QueryInterface() ausführen. Die Beispiele die ich im Web gefunen habe sind genauso implementiert. Von daher weiß ich nicht wie man da weiter vorgehen kann.
    Bzgl. des virtual function pointers und dem read memory denied hatte ich noch gelesen das ein virtueller Destruktor eingebunden werden sollte. Aber das führt zu dem gleichen Fehler.

    Wenn noch jemand Tipps für gute Dokus oder Literatur zu COM hat gerne her damit. Ein paar Tutorials habe ich schon durchgearbeitet.



  • @Quiche-Lorraine Also CoInitializeEx() und CoCreateInstance() funktionieren.

    Ich hatte testweise jeweils für m_deckLink und m_deckLinkInput ein CoCreateInstance() erstellt und im Konstruktor von ControlVideo aufgerufen. Also:

    CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&m_deckLink);
    CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&m_deckLinkInput);
    

    Danach wurde auch in Zeile 21 S_OK zurückgegeben. Aber das kann ja nicht Sinn der Sache sein, das ich für jede Variable die mit dem nullptr intialisiert CoCreateInstance() aufrufe.



  • @makopo

    Probiere doch mal folgendes:

    int main() {
    	HRESULT result;
    	IDeckLink* deckLink = nullptr;
    	IDeckLinkIterator* deckLinkIterator = nullptr;
    
    	//initializing COM
    	if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
    		std::cout << "COM can't be initialized" << std::endl;
    		return 1;
    	}
    
    
    	InitializeDecklink* init = new InitializeDecklink(deckLink);
    	init->InitDeckLink();
    	init->PrintDevice();
    	delete init;
    	
    	//ControlVideo* control = new ControlVideo(deckLink); 
           ControlVideo* control = new ControlVideo(init->m_deckLinkIterator)
    	control->ListDisplayMode();
    	delete control;
    
    	CoUninitialize();
    
    	return 0;
    }
    

    Du bestimmt nämlich einen CLSID_CDeckLinkIterator Zeiger und dieser steht in m_deckLinkIterator. In deckLink steht dagegen immer noch der Nullpointer.

    Bitte lese dich zusätzlich in RAII / std::unique_ptr / std::make_unique ein.



  • @Quiche-Lorraine Danke für den Hinweis. Da wo es geht, habe ich die RAW Pointer durch die Smart Pointer ersetzt. Ich habe da aber noch eine Fehlermeldung die mich ratlos macht.
    m_deckLinkIterator ist bei mir private und ich habe einen Getter erstellt der mir den Wert zurück gibt. Wenn ich den aber mit

    auto control = std::make_unique<ControlVideo>(init->getDeckLinkIterator());
    	control->ListDisplayMode();
    

    den Getter aufrufe und auf der Konsole ausgebe, erhalte ich als Ergebnis trotzdem NULL. Mit dem Debugger erhalte ich den Fehlercode C2664 "ControlVideo::ControlVideo(ATL::CComPtr<InitializeDecklink>)" : Konvertierung von Argument 1 von "_Ty" in "ATL::CComPtr<InitializeDecklink>" nicht möglich.
    Ich habe aber einen zweiten Konstruktor erstellt, der InitializeDecklink entgegen nimmt. Daher verstehe ich das Problem nicht.

    ControlVideo::ControlVideo(CComPtr<IDeckLink> deckLink) 
    	: m_deckLink(deckLink), m_deckLinkInput(nullptr), m_referenceCounter(1), m_previewFrame(deckLink) {
    
    	if (m_deckLinkInput) {
    		std::runtime_error("No DeckLink Input Interface found.");
    	}
    }
    
    ControlVideo::ControlVideo(CComPtr<InitializeDecklink>init) 
    	: m_deckLink(nullptr), m_deckLinkInput(nullptr), m_referenceCounter(1), m_previewFrame(nullptr) {}
    

    Macht das mit dem Getter Aufruf so wie ich das mache überhaupt Sinn? m_deckLinkIterator ja auch mit NULL initialisiert. Dachte erst an einen Setter, um der mit NULL initialisierten m_deckLinkIterator den Rückgabewert aus CoCreateInstance zuzuweisen, aber das funktioniert auch nicht so wirklich.



  • @makopo

    Mit dem Debugger erhalte ich den Fehlercode C2664 "ControlVideo::ControlVideo(ATL::CComPtr<InitializeDecklink>)" : Konvertierung von Argument 1 von "_Ty" in "ATL::CComPtr<InitializeDecklink>" nicht möglich.

    Da hat der Compiler auch recht. Ein Blick in die MSDN Doku zu ATL::CComPtr verrät: A smart pointer class for managing COM interface pointers. Und da InitializeDecklink kein COM Interface Pointer ist, erscheint die Fehlermeldung.

    Denn die entscheidende Frage für dich ist:

    • Wie gibt man einen COM Pointer frei?
    • Wie gibt man ein new char Pointer frei?
    • Wie gibt man einen char char[256] Pointer frei?
    • Wie soll ein CComPtr, std::unique_ptr dies erkennen?

    Macht das mit dem Getter Aufruf so wie ich das mache überhaupt Sinn?

    Aus meiner Sicht eher weniger und gerade deine m_referenceCounter Variable macht mir da Sorgen.

    Ich würde die Klasse InitializeDecklink zu einer Verwaltungsklasse für IDeckLinkIterator entwickeln. Diese Klasse bestimmt den IDeckLinkIterator Zeiger, gibt diesen auch wieder frei und bietet Funktionen zur Manipulation an (ggf. mittels std::function). Einen direkten Zugriff auf den COM Zeiger erlaubt die Klasse nicht.

    Die Klasse ControlVideo nutzt die InitializeDecklink Klasse entweder als Member, Referenz oder ggf. auch als Zeiger und nutzt nur deren Funktionen.



  • @Quiche-Lorraine sagte in Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen:

    Wie gibt man einen COM Pointer frei?
    Wie gibt man ein new char Pointer frei?
    Wie gibt man einen char char[256] Pointer frei?
    Wie soll ein CComPtr, std::unique_ptr dies erkennen?

    Keine Ahnung ob ich deine Fragen richtig verstehe... Wenn ich den COM-Pointer (bzw. einen anderen Smart-Pointer) nutze, muss ich mir um die Speicherfreigabe keine Gedanken machen, da dieser automatisch freigegeben wird. Wenn man den Speicher vor der Funktionsende freigeben will, könnte man noch noch ptr.reset() aufrufen. Wenn du die Fragen aber schon so stellst, werden die nicht so simpel zu beantworten sein...

    @Quiche-Lorraine sagte in Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen:

    Aus meiner Sicht eher weniger und gerade deine m_referenceCounter Variable macht mir da Sorgen.

    Macht dir die referenceCounter Variable Sorgen weil die AddRef() und Release()-Methoden bei den SmartPointern inklusive und im Grunde überflüssig sind?

    Tut mir Leid das ich so viel nachfrage. Ich sitze seit Tagen an der Problematik und verstehe einfach nicht was da los ist. Also C++ Anfänger direkt mit COM-Programmierung zu starten ist anscheinend nicht ganz so sinnvoll...



  • @makopo

    Wenn du die Fragen aber schon so stellst, werden die nicht so simpel zu beantworten sein...

    Nee, leider nicht. Ein new char Pointer wird mittels delete freigegeben, ein new char[256] mittels delete[] und ein COM Pointer mittels Release().

    Dein Code würde nur dann Sinn machen, wenn die Klasse InitializeDecklink ein COM Interface wäre. Dann würde deine Klasse aber wohl eher IInitializeDecklink heißen.

    Aber...

    Also C++ Anfänger direkt mit COM-Programmierung zu starten ist anscheinend nicht ganz so sinnvoll...

    aus meiner Sicht ist COM-Programmierung leider nichts für Anfänger. Dafür ist sehr viel Spezialwissen notwendig.

    Ich möchte es mal so formulieren. Lerne erst einmal ein Programm zu entwickeln. Danach solltest du ab einer gewissen Größe Funktionen in DLLs auslagern. Im Zuge der weiteren Entwicklung entstehen dann weitere Programm- und DLL-Versionen. Und erst wenn du viele Programm und DLL-Versionen hast und die ersten DLL-Hell Probleme auftauchen, kannst du dir COM anschauen.



  • @Quiche-Lorraine
    Danke für die Infos.

    Das Ganze ist ein Projekt fürs Studium. Da kann ich mir leider nicht aussuchen, ob ich erst was anderes lerne oder direkt mit COM einsteige. Leider sind die Materialien nicht so wirklich umfangreich. Wenn man es zumindest mit anderen Programmiersprachen vergleicht.



  • Oha, warum? Da ist man doch mehr mit dem Framework als mit dem eigentlichen Programmieren beschäftigt.



  • @makopo
    Also das Problem ist dass ich nicht ganz verstehe was du da machen willst.
    Grundsätzlich lässt sich CComPtr aber durchaus schön verwenden um COM Objekte zu verwalten. Also das Ding kümmert sich darum korrekt AddRef und Release aufzurufen und das alles.

    CComPtr funktioniert aber natürlich nur mit COM Objekten.



  • Ich weiß nicht ob ich es verständlicher als im ersten Beitrag erklären kann, versuche es aber nochmal. Ich erstelle in der main-Funktion mehrere Objekte über die ich Funktionen der einzelnen Klassen aufrufen möchte. Aktuell erhalte ich in der Klasse ControlVideo beim debuggen die Meldung das m_deckLink den Wert Null hat, was zum Programmabbruch führt. Dies passiert in Zeile 4 des zweites Codeblocks im ersten Post. Letztlich ist das ja aber auch logisch, weil IDeckLink* deckLink ohne Wert initialisiert ist.

    Also scheint die Frage zu sein, wie kann deckLink ein anderer Wert als Null zugewiesen werden? Ich habe das jetzt so verstanden, das dies über CoCreateInstance() und der Initialisierung des COM-Objekts erfolgt (in diesem Fall DeckLinkIterator).

    Aber wie bekomme ich das umgesetzt? Quiche-Lorraine meinte, man kann das über eine abstrakte Klasse lösen. Das würde aber doch bedeuten das ich das Interface in jeder weiteren Klasse einbinden muss. Und das ist komplett konträr zum Beispielcode in der Entwicklerdoku. Dort gibt es eine Funktion die das COM-Objekt erstellt und diese Funktion ebenfalls in der main aufruft:

    HRESULT GetDeckLinkIterator(IDeckLinkIterator **deckLinkIterator)
    {
    	HRESULT result = S_OK;
    
    	// Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
    	result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)deckLinkIterator);
    	if (FAILED(result))
    	{
    		fprintf(stderr, "A DeckLink iterator could not be created.  The DeckLink drivers may not be installed.\n");
    	}
    
    	return result;
    }
    

    Das COM-Objekt wird aber scheinbar nicht an die Klassen weitergegeben, wie beispielsweise in dem folgenden Konstruktor zu sehen ist. Dieser Konstruktor ist ähnlich aufgebaut wie mein Konstruktor wie mein Konstruktor in der Klasse ControlVideo.

    DeckLinkInputDevice::DeckLinkInputDevice(IDeckLink* device)
    	: m_deckLink(device), m_deckLinkInput(NULL), m_cancelCapture(false), m_refCount(1)
    {
    	m_deckLink->AddRef();
    }
    

    Mich vewirrt das in der Entwicklerdoku im Grunde einfach nur steht, das man in der main-Methode einfach nur die Funktion CoCreateInstance() aufrufen soll und fertig. Er scheint ja aber doch noch ein wenig mehr dazu zu gehören. Oder irre ich mich wieder? 😅



  • @makopo sagte in Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen:

    Ich weiß nicht ob ich es verständlicher als im ersten Beitrag erklären kann, versuche es aber nochmal. Ich erstelle in der main-Funktion mehrere Objekte über die ich Funktionen der einzelnen Klassen aufrufen möchte. Aktuell erhalte ich in der Klasse ControlVideo beim debuggen die Meldung das m_deckLink den Wert Null hat, was zum Programmabbruch führt. Dies passiert in Zeile 4 des zweites Codeblocks im ersten Post. Letztlich ist das ja aber auch logisch, weil IDeckLink* deckLink ohne Wert initialisiert ist.

    Ja, klar.

    Also scheint die Frage zu sein, wie kann deckLink ein anderer Wert als Null zugewiesen werden? Ich habe das jetzt so verstanden, das dies über CoCreateInstance() und der Initialisierung des COM-Objekts erfolgt (in diesem Fall DeckLinkIterator).

    Aber wie bekomme ich das umgesetzt?

    Naja ... ich weiss halt nicht wo der DeckLinkIterator herkommen soll. Ein Iterator entsteht normalerweise nicht aus dem Nichts, den bekommt man normalerweise von dem Ding über das man drüber iterieren möchte.
    Das kann dann so einfach sein wie

    HRESULT hr = ding->GetIterator(&m_deckLink);
    if (FAILED(hr)) { /*handle error*/ }
    

    Quiche-Lorraine meinte, man kann das über eine abstrakte Klasse lösen. Das würde aber doch bedeuten das ich das Interface in jeder weiteren Klasse einbinden muss.

    Ich müsste jetzt den ganzen Thread lesen um zu verstehen wie das gemeint war. Aber ich würde sagen: vergiss das erstmal.

    Und das ist komplett konträr zum Beispielcode in der Entwicklerdoku. Dort gibt es eine Funktion die das COM-Objekt erstellt und diese Funktion ebenfalls in der main aufruft:

    HRESULT GetDeckLinkIterator(IDeckLinkIterator **deckLinkIterator)
    {
    	HRESULT result = S_OK;
    
    	// Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
    	result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)deckLinkIterator);
    	if (FAILED(result))
    	{
    		fprintf(stderr, "A DeckLink iterator could not be created.  The DeckLink drivers may not be installed.\n");
    	}
    
    	return result;
    }
    

    OK, das sieht halbwegs vernünftig aus. Wenn der DeckLinkIterator implizit weiss worüber er drüber iterieren soll, dann sollte das so passen.

    Das COM-Objekt wird aber scheinbar nicht an die Klassen weitergegeben, wie beispielsweise in dem folgenden Konstruktor zu sehen ist. Dieser Konstruktor ist ähnlich aufgebaut wie mein Konstruktor wie mein Konstruktor in der Klasse ControlVideo.

    DeckLinkInputDevice::DeckLinkInputDevice(IDeckLink* device)
    	: m_deckLink(device), m_deckLinkInput(NULL), m_cancelCapture(false), m_refCount(1)
    {
    	m_deckLink->AddRef();
    }
    

    Ich seh in dem Beispiel keinen Iterator. Da wird ein IDeckLink übergeben. IDeckLink != IDeckLinkIterator.

    Mich vewirrt das in der Entwicklerdoku im Grunde einfach nur steht, das man in der main-Methode einfach nur die Funktion CoCreateInstance() aufrufen soll und fertig. Er scheint ja aber doch noch ein wenig mehr dazu zu gehören. Oder irre ich mich wieder? 😅

    Also...
    Um COM zu verwenden musst du als erstes mal CoInitializeEx aufrufen. Und danach kannst du COM Objekt erzeugen. Eine Möglichkeit dazu ist CoCreateInstance. Damit kann man quasi ein COM Objekt "aus dem Nichts" erzeugen. Für DeckLinkIterator funktioniert das wohl so.

    Viele COM Schnittstellen bieten dann aber auch Funktionen an um COM Objekte zu erzeugen. IDeckLinkIterator::Next scheint genau so eine Funktion zu sein. Das erzeugt dir ein DeckLink Objekt und gibt dir nen IDeckLink zurück. Zumindest sehen die Beispiele die ich im Netz finde sehr danach aus.

    Und dann kommt es halt einfach drauf an was du jetzt mit dem Ding weiter machen willst.



  • @hustbaer

    @hustbaer sagte in Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen:

    Naja ... ich weiss halt nicht wo der DeckLinkIterator herkommen soll. Ein Iterator entsteht normalerweise nicht aus dem Nichts, den bekommt man normalerweise von dem Ding über das man drüber iterieren möchte.

    Ich hätte vielleicht schreiben sollen, das ich das Programm mit einer Library (DeckLink SDK) für Videohardware programmiere und das der dort über ein Interface bereitgestellt wird.

    Ich denke ich habe den Fehler gefunden. Ich hatte Next() in einer separaten Funktion aufgerufen, weil dort noch alle am PC angeschlossenen DeckLink Geräte ausgegeben werden. In der main habe ich den DeckLinkIterator aber null zugewiesen, so dass der Wert aus CoCreateInstance denke ich mal überschrieben wurde.
    Ich rufe den Code aus den einzelnen Funktionen nun direkt in der int main() auf und es funktioniert. Die deckLink Variable ist nicht mehr Null.

    So sieht es jetzt aus:

    int main() {
    	HRESULT result = S_OK;
    	CComPtr<IDeckLink> deckLink = nullptr;
    	CComPtr<IDeckLinkIterator> deckLinkIterator = nullptr;
    
    	//initializing COM
    	if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
    		std::cout << "COM is initialized" << std::endl;
    	}
    
    //#### HRESULT InitDeckLink(IDeckLinkIterator* deckLink) {####
    	if (SUCCEEDED(CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&deckLinkIterator))) {
    		std::cout << "DeckLink Driver is installed." << std::endl;
    	}
    	else {
    		std::cout << "DeckLink Driver is not installed." << std::endl;
    	}
    
    // #### HRESULT PrintDevice(IDeckLinkIterator* deckLinkIterator, IDeckLink* deckLink) ####
    	while (deckLinkIterator->Next(&deckLink) == S_OK) {
    
    		BSTR modelName;
    		StringConverter sc;
    
    		int numDevices = 0;
    		++numDevices;
    
    		//prints detected devices to the console
    		if (deckLink->GetModelName(&modelName) == S_OK) {
    			std::cout << "Detected devices: " << numDevices << std::endl;
    			std::cout << sc.convertBSTR(modelName) << std::endl;
    		}
    		deckLink = nullptr;
    	}
    	deckLinkIterator = nullptr;
    
    	return result;
    
    //InitDeckLink(deckLinkIterator); // Aufruf InitDeckLink mit CoCreateInstance()
    //PrintDevice(deckLinkterator, deckLink); // Aufruf PrintDevice Funktion mit Next() 
    
    	auto control = std::make_unique<ControlVideo>(deckLink);
    	control->Feedback(); //testfunktion
    	
    	CoUninitialize();
    
    	return 0;
    }
    

    Ich finde es so ziemlich hässlich, weil ich gerne für jede Funktion eine Methode hätte, aber so geht es erstmal. Wenn es daran liegt ein ziemlich peinlicher und frustierender Fehler der mich Tage gekostet hat... 😅



  • Öhm du kannst doch die IDeckLinkIterator instanz als parameter an die Funktionen übergeben.



  • @makopo
    Ich würde erstmal das Erzeugen des DeckLink COM Objekts in eine Hilfsfunktion auslagern:

    CComPtr<IDeckLink> CreateDeckLinkInstance() {
    ...
    }
    

    Das ganze DeckLinkIterator Zeugs wird dann nur innerhalb dieser Funktion benötigt.
    Diese Funktion kannst du dann in main einfach aufrufen wo du das ControlVideo Dings erzeugst.

    	HRESULT const hrCoInit = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    	if (FAILED(hrCoInit)) {
    		std::cout << "COM initialization failed: " << hrCoInit << std::endl;
    		return hrCoInit;
    	}
    
    	auto control = std::make_unique<ControlVideo>(CreateDeckLinkInstance());
    	control->Feedback();
    	// ...
    

    Und nochmal zu dem Code den du gezeigt hast: Du sagst der funktioniert, aber der kann gar nicht funktionieren. Du hast da ja ein return result; drinnen bevor die ControlVideo Instanz erzeugt wird. -> Bin verwirrt.



  • @hustbaer

    Ja, stimmt, so funktioniert der Code nicht. Ich weiß auch nicht mehr wie das return result da reingekommen ist. Getestet hatte ich es aber ohne und so läuft es dann ja.

    Danke für deinen Hinweis die Hilfsfunktion direkt an ControlVideo zu übergeben. Da wäre ich so gar nicht drauf gekommen... 🙈



  • Hallo,

    ich habe noch eine Frage zum Thema.
    Bisher hatte ich in der main-Methode zentral eine DeckLink Instanz mit CoCreateInstance erzeugt. Hat super funktioniert. Nun erstelle ich mit Qt die GUI und die Initialisierung der DeckLink Instanz in der main macht in meinen Augen keinen Sinn mehr.
    Statt die Objekte von z.B. ControlVideo in der main zu erzeugen, mache ich das jetzt in den einzelnen Funktionen. Ich habe z.B. eine Funktion QStartVideo(), in der ich ein Objekt von ControlVideo erstelle und damit die Funktion StartVideo() aufrufe, welche den Stream startet. ControlVideo übergebe ich hier meine Hilfsfunktion CreateDeckLinkInstance(), um StartVideo() mit der DeckLink Instanz zu initialisieren.

    StartVideo:

    HRESULT ControlVideo::StartVideo(BMDDisplayMode displayMode, BMDPixelFormat pixelFormat,
    	BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType,
    	unsigned int channelCount, bool enableFormatDetection) {
    
    	HRESULT result = S_OK;
    
    	if (m_deckLinkInput->EnableVideoInput(displayMode, pixelFormat, videoInputFlags) == S_OK) {
    		std::cout << "Video input is enabled." << std::endl;
    	}
    
    	if (m_deckLinkInput->StartStreams() == S_OK) {
    		std::cout << "Stream has started." << std::endl;
    	}
    	else {
    		std::cout << "Something goes wrong in the startVideo method.";
    	}
    
    	return result;
    }
    

    QStartVideo:

    void QVideoMeter::QStartVideo() {
    
        CComPtr<IDeckLinkIterator> deckLinkIterator = nullptr;
        CComPtr<IDeckLink> deckLink = nullptr;
        CComPtr<InitializeDeckLink> init;
        
        auto control = std::make_unique<ControlVideo>(init->CreateDeckLinkInstance(deckLinkIterator, deckLink));
        
        //'p' avoid the call of Release()
        while (deckLinkIterator->Next(&deckLink.p) == S_OK) {
    
            HRESULT inputVideoData = control->StartVideo(bmdModeHD1080p50, bmdFormat8BitYUV, bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2, false);
    
            if (inputVideoData == S_OK) {
                ui.startBtn->setText("Running");
            }
        }
    }
    

    Hilfsfunktion:

    CComPtr<IDeckLink> InitializeDeckLink::CreateDeckLinkInstance(CComPtr<IDeckLinkIterator> deckLinkIterator, CComPtr<IDeckLink> deckLink) {
    
    	if (FAILED(CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&deckLinkIterator))) {
    		std::cout << "DeckLink Driver is not installed." << std::endl;
    	}
    	return deckLink;
    }
    

    Problem was ich sehe: wenn ich in der Hilfsfunktion deckLink zurückgebe, dies in QStatVideo aber mit NULL initialisiert wird, kann das Erzeugen der DeckLink Instanz nicht funktioniert oder? Denn wenn ich das Programm ausführe wird eine Exception ausgelöst und es kommt die Fehlermeldung das deckLinkInput NULL ist.

    Konstruktor ControlVideo:

    /**
    * Contructor with initializer list
    */
    ControlVideo::ControlVideo(CComPtr<IDeckLink> deckLink)
    	: m_deckLink(deckLink), m_deckLinkInput(deckLink),
    	m_inputCallback(nullptr), m_referenceCounter(1) {
    
    	if (!m_deckLink) {
    		throw std::runtime_error("No DeckLink Interface found.");
    	}
    
    	if (!m_deckLinkInput) {
    		throw std::runtime_error("No DeckLink Input Interface found.");
    	}
    }
    

    Hat jemand einen Tipp? Ich stehe da leider komplett auf dem Schlauch.



  • Habe das Problem durch die folgende Anpassung der Hilfsfunktion behoben:

    CComPtr<IDeckLink> InitializeDeckLink::CreateDeckLinkInstance() {
    
        CComPtr<IDeckLink> deckLink = nullptr;
        CComPtr<IDeckLinkIterator> deckLinkIterator = nullptr;
    
        HRESULT result = S_OK;
        result = CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&deckLinkIterator);
    
        if (FAILED(result)) {
            std::cout << "DeckLink Driver is not installed." << std::endl;
            QMessageBox::warning(nullptr, "DeckLink Treiber nicht installiert", "Bitte installieren Sie den aktuellen DeckLink Treiber von Blackmagic.");
        }
    
        if (deckLinkIterator->Next(&deckLink) != S_OK) {
            std::cout << "No DeckLink device detected." << std::endl;
            QMessageBox::warning(nullptr, "Kein Gerät erkannt", "Bitte verbinden Sie Ihren PC mit geeigneter Blackmagic Hardware (z.B. UltraStudio Recorder).");
        }
        return deckLink;
    
    }
    

Anmelden zum Antworten