Membri di overflow di Stack Hi,QueryInterface non riesce con E_NOINTERFACE su C#
Sono un principiante della programmazione C#. Sto sviluppando uno streaming di base della fotocamera e continuo a catturare l'applicazione. Una volta che l'utente si ferma, lo visualizzerò su overlay usando il concetto di mixaggio bitmap di VMR9.
Cosa ho fatto?
- sto facendo uso di C# libreria DirectShow da here
- Prima vengo tutte le interfacce filtri necessari. Trova il dispositivo di acquisizione allegato. Chiamato Render stream con filtro sorgente e vmr9 per pin PREVIEW. Filtro di origine, sample grabber e renderer nullo per STILL PIN.
- Ho tre pulsanti di menu -> ferma, mostra sovrapposizione e nascondi overlay.
- Sto facendo uso del campione di bitmap fornito in quella libreria.
- Ogni volta che l'utente preme il menu Take Still, l'immagine verrà salvata sul desktop e verrà ridimensionata a una risoluzione ridotta e visualizzata sul video overlay.
- Mostra Overlay e nasconde le chiamate overlay ShowHideBitmap() che eseguono l'operazione dell'interrogazione dell'interfaccia VMR9BitmapMixer dal filtro vmr9, riempie la struttura VMR9AlphaBitmap e quindi chiama la funzione IVMRMixerBitmap9.SetAlphaBitmap.
Quale problema devo affrontare?
- Dopo aver preso ancora, se chiamo ShowHideBitmap() opzione di menu attraverso, l'immagine viene aggiornato perfettamente su sovrapposizione.
- Questa è un'altra opzione che esegue l'aggiornamento automatico dell'overlay non appena viene salvato il fermo immagine. Creo il thread basato su eventi e lo ho fatto per attendere l'evento di aggiornamento creato utilizzando EventWaitHandle. Prima di tornare dalla funzione BufferCB di samplegrabber, ho impostato questo evento di aggiornamento. Che a sua volta procede con thread in attesa. All'interno del filo chiamo la funzione ShowHideBitmap. In questo scenario, ricevo il messaggio di errore come segue.
Unable to case COM object of type 'DirectShowLib.VideoMixingRenderer9' to interface type 'DirectShowLib.IVMRMixerBitmap9'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{ced175e5-1935-4820-81bd-ff6ad00c9108}' failed due to the following error: No such interface supported (Exception from HRESULT: 0X80040002 (E_NOINTERFACE)
Ecco il blocco di codice di funzione ShowHideBitmap
//Declarations
private static IBaseFilter vmr9 = null;
private static IVMRMixerBitmap9 vmr9mixerBitmap = null;
private IVMRWindowlessControl9 vmr9windowlessCtrl = null;
private static void ShowHideBitmap(Boolean bEnable)
{
int hr = 0;
VMR9AlphaBitmap alphaBmp;
if (!bEnable)
{
if (vmr9mixerBitmap != null)
{
// Get current Alpha Bitmap Parameters
hr = vmr9mixerBitmap.GetAlphaBitmapParameters(out alphaBmp);
DsError.ThrowExceptionForHR(hr);
// Disable them
alphaBmp.dwFlags = VMR9AlphaBitmapFlags.Disable;
// Update the Alpha Bitmap Parameters
hr = vmr9mixerBitmap.UpdateAlphaBitmapParameters(ref alphaBmp);
DsError.ThrowExceptionForHR(hr);
// Create a surface from our alpha bitmap
surface.Dispose();
vmr9mixerBitmap = null;
//Release this alpha bitmap source.
if (alphaBitmap != null)
{
alphaBitmap.Dispose();
}
}
return;
}
else
{
try
{
alphaBitmap = BitmapGenerator.GenerateAlphaBitmap();
// Create a surface from our alpha bitmap
if(surface == null)
surface = new Surface(device, alphaBitmap, Pool.SystemMemory);
// Get the unmanaged pointer
unmanagedSurface = surface.GetObjectByValue(DxMagicNumber);
if (vmr9mixerBitmap == null)
vmr9mixerBitmap = (IVMRMixerBitmap9)vmr9;
// Set Alpha Bitmap Parameters for using a Direct3D surface
alphaBmp = new VMR9AlphaBitmap();
alphaBmp.dwFlags = VMR9AlphaBitmapFlags.EntireDDS;
alphaBmp.pDDS = unmanagedSurface;
alphaBmp.rDest = GetDestRectangle();
alphaBmp.fAlpha = 1.0f;
// Set Alpha Bitmap Parameters
hr = vmr9mixerBitmap.SetAlphaBitmap(ref alphaBmp);
DsError.ThrowExceptionForHR(hr);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Ed ecco il filo di attesa per l'evento di aggiornamento.
Thread overlayupdatethreadhandle = new Thread(new ThreadStart(overlayupdatethread));
overlayupdatethreadhandle.Start();
private void overlayupdatethread()
{
do
{
overlayupdateeventhandle.WaitOne();
ShowHideBitmap(GlobalVar.m_ShowOverlay);
} while (true);
}
ho provato ad aggiornare questo overlay usando il timer che è stato eseguito a sfondo con intervalli di 100 ms. L'uso del timer funzionava bene, ma per questa operazione, l'uso del timer è di cattiva scelta. Quindi mi sono trasferito con il concetto di threading.
Perché l'interfaccia di ricezione non riesce durante la chiamata da thread e funziona correttamente quando si chiama dalle opzioni di menu? Dovrei prendermi cura di qualche cosa speciale? Ho anche provato un thread parametrico, ma senza fortuna.
Grazie in anticipo per il vostro aiuto.
MODIFICA: se ShowHideBitmap viene chiamato dal thread principale, ogni cosa funziona correttamente. Se ShowHideBitmap viene chiamato dal thread worker, l'oggetto COM crea Exception.Come gestire questa operazione cross-thread?
+1. bella domanda. Commenta come non sono completamente sicuro ... Una sorta di aspettativa: la maggior parte degli oggetti COM dovrebbe essere chiamata da un singolo thread ... la documentazione probabilmente chiamerebbe esplicitamente se è possibile chiamarla da più thread. (Ricordo anche vagamente che potrebbe essere necessario inizializzare COM su altro thread prima di accedere all'oggetto cross thread) ... –
Ciao Alexei, sì hai ragione. La chiamata di oggetti COM da più thread diversi dal thread principale sta creando questo errore. Ho anche provato a inizializzare questa interfaccia vmr9mixerBitmap come thread principale e usando la stessa funzione ShowHideBitmap (invece di creare in questa funzione), ma il risultato è lo stesso. Inizializza COM, vuoi dire che dovrei avere un'interfaccia nel thread principale e usare la stessa interfaccia attraverso il thread? C'è una spiegazione dettagliata di questo oggetto COM a cui si accede attraverso il thread? – Spark
Le interfacce VMR sottostanti possono essere passate tra thread anche violando le regole COM. Nel codice nativo però, non gestito. In C# COM l'interoperabilità non è consapevole di questi trucchi sporchi e suppongo che questo possa essere un problema: quando tenta di passare l'interfaccia tramite il marshalling, non è in grado di farlo, perde le interfacce e non le hai disponibili sul thread di lavoro. –