Thread di streaming e applicazione
[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation anziché DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.
Qualsiasi applicazione DirectShow contiene almeno due thread importanti: il thread dell'applicazione e uno o più thread di streaming. Gli esempi vengono recapitati nei thread di streaming e le modifiche dello stato si verificano nel thread dell'applicazione. Il thread di streaming principale viene creato da un filtro di origine o parser. Altri filtri possono creare thread di lavoro che forniscono esempi e questi sono considerati anche thread di streaming.
Alcuni metodi vengono chiamati nel thread dell'applicazione, mentre altri vengono chiamati su un thread di streaming. Ad esempio:
- Thread di streaming: IMemInputPin::Receive, IMemInputPin::ReceiveMultiple, IPin::EndOfStream, IMemAllocator::GetBuffer.
- Thread applicazione: IMediaFilter::P ause, IMediaFilter::Run, IMediaFilter::Stop, IMediaSeeking::SetPositions, IPin:: BeginFlush, IPin:: EndFlush.
- Entrambi: IPin::NewSegment.
La presenza di un thread di streaming separato consente ai dati di scorrere il grafico mentre il thread dell'applicazione attende l'input dell'utente. Il pericolo di più thread, tuttavia, è che un filtro può creare risorse quando si sospende (nel thread dell'applicazione), usarli all'interno di un metodo di streaming e eliminarli quando si arresta (anche nel thread dell'applicazione). Se non si è attenti, il thread di streaming potrebbe provare a usare le risorse dopo che vengono distrutte. La soluzione consiste nel proteggere le risorse usando sezioni critiche e sincronizzare i metodi di streaming con le modifiche allo stato.
Un filtro richiede una sezione critica per proteggere lo stato del filtro. La classe CBaseFilter include una variabile membro per questa sezione critica, CBaseFilter::m_pLock. Questa sezione critica è denominata blocco del filtro. Inoltre, ogni pin di input richiede una sezione critica per proteggere le risorse usate dal thread di streaming. Queste sezioni critiche sono denominate blocchi di streaming; è necessario dichiararli nella classe pin derivata. È più semplice usare la classe CCritSec , che esegue il wrapping di un oggetto Windows CRITICAL_SECTION e può essere bloccato usando la classe CAutoLock . La classe CCritSec fornisce anche alcune funzioni di debug utili. Per altre informazioni, vedere Funzioni di debug della sezione critica.
Quando un filtro si arresta o scarica, deve sincronizzare il thread dell'applicazione con il thread di streaming. Per evitare il deadlocking, deve prima sbloccare il thread di streaming, che potrebbe essere bloccato per diversi motivi:
- È in attesa di ottenere un esempio all'interno del metodo IMemAllocator::GetBuffer , perché tutti gli esempi dell'allocatore sono in uso.
- È in attesa che un altro filtro venga restituito da un metodo di streaming, ad esempio Receive.
- È in attesa all'interno di uno dei propri metodi di streaming, affinché alcune risorse diventino disponibili.
- È un filtro del renderer in attesa dell'ora di presentazione dell'esempio successivo
- È un filtro del renderer in attesa all'interno del metodo Receive durante la pausa.
Pertanto, quando il filtro si arresta o scarica, deve eseguire le operazioni seguenti:
- Rilasciare qualsiasi esempio che contiene per qualsiasi motivo. In questo modo viene sbloccato il metodo GetBuffer .
- Tornare da qualsiasi metodo di streaming il più rapidamente possibile. Se un metodo di streaming è in attesa di una risorsa, deve interrompere immediatamente l'attesa.
- Iniziare a rifiutare esempi in Ricezione, in modo che il thread di streaming non accinga ad altre risorse. La classe CBaseInputPin gestisce automaticamente questa classe.
- Il metodo Stop deve decommettere tutti gli allocatori del filtro. La classe CBaseInputPin gestisce automaticamente questa classe.
Lo scaricamento e l'arresto di entrambi si verificano nel thread dell'applicazione. Un filtro si arresta in risposta al metodo IMediaControl::Stop . Filter Graph Manager genera il comando stop nell'ordine upstream, a partire dai renderer e lavorando indietro ai filtri di origine. Il comando stop viene eseguito completamente all'interno del metodo CBaseFilter::Stop del filtro. Quando il metodo restituisce, il filtro deve trovarsi in uno stato arrestato.
Lo scaricamento si verifica in genere a causa di un comando di ricerca. Un comando di scaricamento inizia dal filtro di origine o parser e viaggia verso il basso. Lo scaricamento avviene in due fasi: il metodo IPin::BeginFlush informa un filtro per eliminare tutti i dati in sospeso e in ingresso; il metodo IPin::EndFlush segnala il filtro per accettare di nuovo i dati. Lo scaricamento richiede due fasi perché la chiamata BeginFlush si trova nel thread dell'applicazione, durante la quale il thread di streaming continua a recapitare i dati. Di conseguenza, alcuni esempi possono arrivare dopo la chiamata BeginFlush . Il filtro deve eliminarlo. Tutti gli esempi che arrivano dopo la chiamata EndFlush devono essere nuovi e devono essere recapitati.
Le sezioni che seguono contengono esempi di codice che illustrano come implementare i metodi di filtro più importanti, ad esempio Pause, Ricezione e così via, in modo da evitare deadlock e condizioni di gara. Ogni filtro ha tuttavia requisiti diversi, quindi sarà necessario adattare questi esempi al filtro specifico.
Nota
Le classi di base CTransformFilter e CTransInPlaceFilter gestiscono molti dei problemi descritti in questo articolo. Se si scrive un filtro di trasformazione e il filtro non attende gli eventi all'interno di un metodo di streaming o si mantiene sugli esempi all'esterno di Ricezione, queste classi di base devono essere sufficienti.