Scrittura di un'origine multimediale personalizzata
Questo argomento descrive come implementare un'origine multimediale personalizzata in Microsoft Media Foundation. Contiene le sezioni seguenti:
- Creazione del descrittore di presentazione
- Avvio dell'origine multimediale
- Sospensione dell'origine multimediale
- Generazione di dati di origine
- Arresto dell'origine multimediale
- Origini attive
- Argomenti correlati
Creazione del descrittore di presentazione
Il metodo IMFMediaSource::CreatePresentationDescriptor restituisce una copia del descrittore di presentazione dell'origine. Per creare il descrittore di presentazione, è necessario conoscere il numero di flussi nel contenuto di origine e i formati possibili di ogni flusso. Per ogni flusso, creare un descrittore di flusso come indicato di seguito:
- Creare una matrice di tipi di supporti. Ogni tipo di supporto nella matrice rappresenta un formato possibile per il flusso. Per altre informazioni sulla creazione di tipi di supporti, vedere Tipi di supporti.
- Chiamare MFCreateStreamDescriptor per creare il descrittore di flusso. Passare la matrice di tipi di supporti. La funzione restituisce un puntatore IMFStreamDescriptor .
- Chiamare IMFStreamDescriptor::GetMediaTypeHandler per ottenere il gestore del tipo di supporto del descrittore di flusso.
- Chiamare IMFMediaTypeHandler::SetCurrentMediaType per impostare il formato di flusso predefinito. Usare uno dei tipi di supporto creati nel passaggio 1. In genere, è consigliabile usare il formato con la massima qualità.
- Facoltativamente, impostare gli attributi nel descrittore di flusso. Per un elenco di attributi che si applicano ai descrittori di flusso, vedere Attributi del descrittore di flusso.
Creare ora il descrittore di presentazione:
- Chiamare MFCreatePresentationDescriptor e passare la matrice di descrittori di flusso. La funzione restituisce un puntatore IMFPresentationDescriptor .
- Scegliere la selezione del flusso predefinita chiamando IMFPresentationDescriptor::SelectStream per selezionare uno o più flussi. È necessario selezionare almeno un flusso nella configurazione predefinita.
- Facoltativamente, impostare gli attributi nel descrittore di presentazione. Per un elenco di attributi che si applicano ai descrittori di flusso, vedere Attributi del descrittore di presentazione.
È necessario creare il descrittore di presentazione una sola volta, all'avvio o dopo che l'origine ha analizzato abbastanza dati di origine per determinare il contenuto. Il metodo CreatePresentationDescriptor deve restituire una copia del descrittore di presentazione. Per creare la copia, chiamare IMFPresentationDescriptor::Clone. La restituzione di una copia impedisce al client di modificare lo stato del descrittore di presentazione originale, ad esempio gli attributi o la selezione del flusso. Tenere tuttavia presente che Clone crea una copia superficiale, in modo che il client possa modificare potenzialmente i descrittori di flusso sottostanti.
Avvio dell'origine multimediale
Il metodo IMFMediaSource::Start avvia l'origine multimediale o cerca una nuova posizione. Una chiamata a Start causa una ricerca quando lo stato precedente è stato sospeso o in esecuzione e viene specificata una nuova ora di inizio. In caso contrario, il metodo Start genera un avvio. Al termine dell'operazione Di avvio , inviare gli eventi seguenti.
- Inviare un evento MENewStream per ogni nuovo flusso, ovvero ogni flusso deselezionato in precedenza ed è ora selezionato. I dati dell'evento sono un puntatore al flusso.
- Inviare un evento MEUpdatedStream per ogni flusso selezionato in precedenza ed è ancora selezionato. I dati dell'evento sono un puntatore al flusso. Non inviare un evento per i flussi deselezionati.
- Se l'origine sta cercando, inviare un evento MESourceSeeked . In caso contrario, inviare un evento MESourceStarted . I dati dell'evento sono l'ora di inizio specificata nel metodo Start . Per l'evento MESourceStarted, se l'ora di inizio è VT_EMPTY, impostare l'attributo MF_EVENT_SOURCE_ACTUAL_START sull'evento. Il valore dell'attributo è l'ora di inizio effettiva.
- Per ogni flusso, se l'origine sta cercando, inviare un evento MEStreamSeeked . In caso contrario, inviare un evento MEStreamStarted . I dati dell'evento sono l'ora di inizio. L'origine multimediale può accodare un evento nel flusso chiamando il metodo IMFMediaEventGenerator::QueueEventGenerator del flusso.
Quando un flusso viene deselezionato, arrestare il flusso. Il flusso non deve accodamento di altri eventi a quel punto.
Il formato dell'ora per il metodo Start viene specificato nel parametro pguidTimeFormat . Il formato dell'ora standard, indicato da GUID_NULL, è di 100 nanosecondi. Un'origine multimediale deve supportare questo formato ora.
Riercare
Quando si cerca, la posizione iniziale richiesta potrebbe non rientrare in un limite di esempio esatto. Inoltre, per il contenuto compresso, la posizione iniziale potrebbe essere compresa tra fotogrammi chiave. Un flusso deve fornire campioni dal primo punto necessario per produrre un campione non compresso nella posizione iniziale richiesta. Per il video, ciò significa partire dal fotogramma chiave precedente. La pipeline è responsabile dell'eliminazione dei fotogrammi aggiuntivi dal decodificatore, in modo che la riproduzione venga avviata all'ora richiesta.
L'ora di inizio specificata negli eventi di origine (MESourceStarted, MESourceSeeked, MEStreamStarted e MEStreamSeeked) è l'ora di inizio richiesta (il valore specificato nel metodo Start ), indipendentemente dalla posizione di inizio effettiva.
Si supponga, ad esempio, che i primi fotogrammi di un flusso video abbiano le caratteristiche seguenti:
Esempio | 1 | 2 | 3 | 4 |
---|---|---|---|---|
Tempo | 33 msec | 66 msec | 100 msec | 133 msec |
Fotogramma chiave? | Sì | No | No | Sì |
Se il metodo Start viene chiamato con un valore di 100 millisecondi, l'origine deve restituire video a partire dal fotogramma 1, il primo fotogramma chiave prima di questa volta. L'evento di avvio indicherà comunque 100 millisecondi nei dati dell'evento.
Sospensione dell'origine multimediale
Il metodo IMFMediaSource::P ause sospende l'origine multimediale.
Mentre l'origine è sospesa, un flusso può creare nuovi esempi e archiviarli in una coda, ma il flusso non fornisce gli esempi. Ecco alcune eccezioni a questa regola:
- Le origini attive devono eliminare i dati durante la sospensione.
- Se l'origine ottiene dati da una rete, potrebbe sospendere il server.
Se il client chiama IMFMediaStream::RequestSample mentre l'origine è sospesa, la richiesta viene accodata anche fino a quando l'origine non viene avviata nuovamente. Le richieste non devono essere eliminate.
La sospensione è consentita solo dallo stato avviato. In caso contrario, la sospensione deve restituire MF_E_INVALID_STATE_TRANSITION.
Generazione di dati di origine
Media Foundation usa un modello pull, vale a dire che i flussi generano e recapitano campioni in risposta alle richieste dalla pipeline. Un flusso può recapitare campioni quando l'origine multimediale è in esecuzione e il flusso è selezionato. Un flusso recapita i dati solo quando il client richiede un nuovo esempio.
Richieste di esempio
Il client richiede un nuovo esempio chiamando IMFMediaStream::RequestSample. Ecco la sequenza di operazioni:
Il client chiama IMFMediaStream::RequestSample. L'argomento è un puntatore a un oggetto token facoltativo usato dal client per tenere traccia della richiesta. Il client implementa il token. I token devono esporre l'interfaccia IUnknown . Il client può anche passare un puntatore NULL anziché un token.
Se il client ha fornito un token, il flusso multimediale chiama AddRef sul token e inserisce il token in una coda first-in first-out. Il metodo restituisce e i passaggi rimanenti vengono eseguiti in modo asincrono.
Quando sono disponibili altri dati, il flusso multimediale crea un nuovo esempio. Questo passaggio è descritto in modo più dettagliato nella sezione successiva.
Il flusso multimediale estrae il primo token dalla coda.
Se il token non è NULL, il flusso multimediale imposta l'attributo MFSampleExtension_Token nell'esempio multimediale. Il valore dell'attributo è un puntatore al token.
Il flusso multimediale invia un evento MEMediaSample . I dati dell'evento sono un puntatore all'interfaccia IMFSample dell'esempio.
Se il client ha fornito un token, il flusso multimediale chiama Release sull'oggetto token.
Se il flusso multimediale non può soddisfare la richiesta RequestSample del client, esegue il pull del token dalla coda e chiama Release sul token, ma non invia un evento MEMediaSample .
Il client può usare il token per tenere traccia dello stato della richiesta. Quando il client riceve l'evento MEMediaSample , può ottenere il token dall'esempio e abbinarlo alla richiesta originale. Il client può anche usare il token per rilevare se l'origine multimediale ha eliminato la richiesta. Se il conteggio dei riferimenti del token scende a zero e il flusso multimediale non invia un evento MEMediaSample, significa che la richiesta è stata eliminata.
I passaggi elencati di seguito presuppongono che il metodo RequestSample sia implementato come operazione asincrona. Se il metodo è sincrono, non è necessario inserire il token di richiesta in una coda. Tuttavia, se la generazione di dati richiede una quantità significativa di tempo, è consigliabile un approccio asincrono, ad esempio se l'origine legge i dati da un flusso di byte.
Il flusso è responsabile del buffering di tutti i dati accumulati tra le chiamate a RequestSample.
Quando il flusso multimediale raggiunge la fine del flusso, invia un evento MEEndOfStream dopo l'ultimo esempio. Al termine di ogni flusso, l'origine multimediale invia un evento MEEndOfPresentation . Dopo che un flusso multimediale invia l'evento MEEndOfStream, il metodo RequestSample restituisce MF_E_END_OF_STREAM fino al riavvio dell'origine.
Allocazione di esempi
Quando il flusso è pronto per compilare una richiesta di esempio in sospeso, crea un nuovo esempio e aggiunge uno o più buffer multimediali all'esempio. Per altre informazioni sulla creazione di buffer multimediali, vedere Buffer multimediali.
Il flusso deve impostare il timestamp e la durata, se noto. Il timestamp è relativo all'origine. Nella maggior parte dei casi, l'inizio del contenuto corrisponde a un timestamp pari a zero. Ad esempio, se l'origine legge da un file multimediale, l'inizio del file avrà un timestamp pari a zero.
Il timestamp dell'esempio non corrisponde necessariamente all'ora di presentazione. La sessione multimediale viene convertita dall'ora di origine all'ora di presentazione. Per i dati compressi, il flusso deve generare dati a partire dal fotogramma chiave più vicino prima dell'ora di inizio. Ciò consente al decodificatore di recapitare il frame visualizzato all'ora di inizio richiesta. In caso contrario, il decodificatore deve attendere fino al fotogramma chiave seguente.
Se la velocità di riproduzione è più veloce o più lenta di 1,0, la pipeline regola la frequenza dell'orologio della presentazione. L'origine non regola i timestamp nei campioni.
L'origine può impostare informazioni aggiuntive sull'esempio impostando gli attributi. Per un elenco degli attributi di esempio, vedere Attributi di esempio.
Gap nel flusso
Se un flusso contiene una distanza di lunghezza significativa, è consigliabile che il flusso invii un evento MEStreamTick . Questo evento notifica al client che manca un esempio. I dati dell'evento sono il timestamp del campione mancante, in unità di 100 nanosecondi (VT_I8). Questo evento può salvare i componenti downstream dall'attesa di campioni che non arriveranno. Il flusso può inviare tutti gli eventi MEStreamTick necessari per estendere il gap nel flusso.
Arresto dell'origine multimediale
Al termine dell'uso dell'origine multimediale, il client chiama IMFMediaSource::Shutdown. All'interno di questo metodo, l'origine multimediale deve interrompere qualsiasi conteggio di riferimenti circolari. In genere, saranno presenti riferimenti circolari tra l'origine multimediale e i flussi multimediali.
Se si usa la coda di eventi per implementare IMFMediaEventGenerator, chiamare IMFMediaEventQueue::Shutdown nella coda degli eventi. Questo metodo arresta la coda di eventi e segnala qualsiasi chiamante in attesa di un evento.
Dopo l'arresto, tutti i metodi nell'origine restituiscono MF_E_SHUTDOWN, ad eccezione dei metodi IUnknown .
Origini attive
A partire da Windows 7, Media Foundation supporta automaticamente i dispositivi di acquisizione audio e video. Per il video, il dispositivo deve fornire un minidriver di streaming del kernel (KS) nella categoria di acquisizione video. Media Foundation usa il percorso PnP per enumerare il dispositivo. Per l'audio, Media Foundation usa l'API WINDOWS Multimedia Device (MMDevice) per enumerare i dispositivi endpoint audio. Se il dispositivo soddisfa questi criteri, non è necessario implementare un'origine multimediale personalizzata.
Tuttavia, è possibile implementare un'origine multimediale personalizzata per un altro tipo di dispositivo o un'altra origine dati live. Esistono solo alcune differenze tra un'origine live e altre origini multimediali:
- Nel metodo IMFMediaSource::GetCharacteristics restituire il flag MFMEDIASOURCE_IS_LIVE .
- Il primo campione deve avere un timestamp pari a zero.
- Gli eventi e gli stati di streaming vengono gestiti come origini multimediali, ad eccezione dello stato sospeso.
- Durante la sospensione, non accodamento degli esempi. Eliminare tutti i dati generati durante la sospensione.
- Le origini attive in genere non supportano la ricerca, la riproduzione inversa o il controllo della frequenza.
Argomenti correlati