Un'introduzione a Media Foundation: comprendere l'API attraverso una lente COM
· Aggiornato il: · Go Komura · Media Foundation, COM, C++, Sviluppo Windows
Quando inizi a lavorare con Media Foundation, è facile pensare: “Pensavo di usare il video e l’audio di Windows API, e all’improvviso tutto riguarda COM.” CoInitializeEx, MFStartup, IMFSourceReader, IMFMediaType, IMFTransform, IMFActivate, HRESULT, GUIDs - arrivano tutti insieme, l’atmosfera cambia improvvisamente Win32 / COM, e cosa sia effettivamente Media Foundation diventa difficile da vedere.
Piuttosto che coprire tutto Media Foundation come un dizionario, questo articolo si concentra su tre cose.
- Perché COM appare naturalmente quando usi Media Foundation?
- Dove si intensifica esattamente il sapore del COM?
- Da dove dovresti iniziare: Source Reader / Sink Writer / Media Session / MFT?
Gli esempi di codice sono basati su C++, ma il modo di pensare è essenzialmente lo stesso quando si toccano i wrapper da .NET e simili.
Sommario
- Prima la conclusione (in una riga)
- Le tabelle di orientamento da considerare per prime
- 2.1. Cosa toccare per quello che vuoi fare
- 2.2. Dove si mette la faccia COM
- 2.3. Termini per comprendere il significato del primo
- Il quadro generale di Media Foundation (diagramma)
- Dove Media Foundation indossa la sua faccia COM
- 4.1.
CoInitializeExeMFStartupAffiancati durante l’inizializzazione - 4.2. I trasferimenti di oggetti sono incentrati sull’interfaccia
- 4.3. Vengono visualizzati gli oggetti di attivazione
- 4.4. Impostazioni e tipo Centro informazioni su
IMFAttributese GUIDs - 4.5. Anche l’asincronia, i callback e il threading vengono gestiti nel modo COM
- 4.6. Ma Media Foundation ≠ COM
- 4.1.
- Una guida approssimativa alla scelta
- 5.1. A partire dal Source Reader
- 5.2. Scrittura su file con Sink Writer
- 5.3. Gestire la riproduzione e la sincronizzazione con Media Session
- 5.4. Inserimento di componenti personalizzati con MFTs
- Una lista di controllo pratica
- Estratti di codice
- 7.1 Inizializzazione
- 7.2 Creazione di un Source Reader in modalità sincrona
- 7.3 Creazione di un Source Reader in modalità asincrona
- 7.4 Enumerazione e istanziazione di MFTs con
MFTEnumEx
- Conclusione
- Riferimenti
1. Prima la conclusione (in una riga)
- Media Foundation è una piattaforma per la gestione di video e audio - l’API nel suo complesso non è, di per sé, pura COM
- Tuttavia, i confini tra origine / trasformazione / sink / attivazione / attributi / callback sono espressi come interfacce COM, quindi quando lo usi,
IUnknown,HRESULT, GUIDs e gli argomenti dell’appartamento emergono naturalmente - È più semplice iniziare con Source Reader / Sink Writer, passare a Media Session quando hai bisogno del controllo della riproduzione e a MFTs quando hai bisogno di trasformazioni personalizzate
In breve, Media Foundation è una piattaforma di elaborazione multimediale le cui superfici di confine sono profondamente intrise di COM.
Se lo interiorizzi in anticipo, la domanda “perché improvvisamente assume una faccia da COM?” diventa molto più chiaro.
2. Le tabelle di orientamento da considerare per prime
2.1. Cosa toccare per quello che vuoi fare
Osservando prima questa tabella è più facile scegliere il punto di ingresso.
| Cosa vuoi fare | Toccare prima | COM intensità | Note |
|---|---|---|---|
| Ottieni fotogrammi / campioni da un file o da una fotocamera | Source Reader | Medio | Si prende cura dei decoder per te quando necessario |
| Scrivi l’audio / video generato in un file | Sink Writer | Medio | Può raggruppare il codificatore e il dissipatore multimediale per te |
| Gestisci riproduzione, arresto, ricerca, sincronizzazione A / V, controllo qualità | Media Session | Alto | Richiede la comprensione di topologie e sessioni |
| Collega trasformazioni personalizzate o componenti simili a codec | MFT | Alto | Pensaci su IMFTransform |
| Ispeziona i candidati elencati, quindi crea un’istanza solo di ciò che ti serve | IMFActivate |
Alto | Ciò che ottieni potrebbe essere un oggetto di attivazione, non la cosa reale |
2.2. Dove si mette la faccia COM
| Punto | Cosa appare | Cosa capire prima |
|---|---|---|
| Inizializzazione | CoInitializeEx, MFStartup |
L’inizializzazione COM e l’inizializzazione Media Foundation sono separate |
| Creazione e trasferimento di oggetti | IMFSourceReader, IMFMediaType, IMFTransform |
La maggior parte sono puntatori all’interfaccia + HRESULT |
| Impostazioni | IMFAttributes, GUIDs |
Impostazioni e informazioni sul tipo espresse come chiave / valore + GUIDs |
| Enumerazione / creazione differita | IMFActivate, ActivateObject |
I risultati dell’enumerazione potrebbero non essere gli oggetti reali |
| Asincronia | IMFSourceReaderCallback, code di lavoro |
Devi essere consapevole dei richiami e degli appartamenti |
| Controllo della riproduzione | Topologie, Media Session | Il flusso complessivo della pipeline è un concetto specifico di Media Foundation |
2.3. Termini per comprendere il significato del primo
| Termine | Significato qui |
|---|---|
| Fonte multimediale | Il punto di ingresso che inserisce i dati multimediali nella pipeline: file, reti, dispositivi di acquisizione, ecc. |
| MFT | Media Foundation Trasforma. Il modello comune per decodificatori, codificatori, convertitori video e così via |
| Lavandino multimediale | Dove vanno i dati multimediali: visualizzazione dello schermo, uscita audio, uscita file, ecc. |
| Media Session | Il meccanismo che gestisce il flusso dell’intera pipeline; gestisce la riproduzione e la sincronizzazione |
| Topologia | Lo schema di collegamento che descrive come sono cablati source / transform / sink |
| Oggetto di attivazione | Un oggetto helper per creare successivamente l’oggetto reale; rappresentato da IMFActivate |
| Attributi | Un archivio chiave / valore con chiave GUIDs; utilizzato pesantemente in tutto il Media Foundation |
Avere questi come vocabolario in anticipo riduce drasticamente l’attrito della lettura della documentazione.
3. Il quadro generale di Media Foundation (diagramma)
Visto in generale, Media Foundation è la storia di una pipeline mediatica. L’aspetto COM è importante, ma è più facile organizzarsi guardando prima il quadro generale.
flowchart TB
subgraph Pipeline["Modello utilizzando l'intera pipeline"]
Source1["Fonte multimediale"] --> Transform1["MFT"]
Transform1 --> Sink1["Dissipatore multimediale"]
Session["Media Session"] --- Source1
Session --- Transform1
Session --- Sink1
end
subgraph Direct["Modello in cui l'app gestisce direttamente i dati"]
Source2["Fonte multimediale"] --> Reader["Source Reader (+ decodificatore)"]
Reader --> App["App"]
App --> Writer["Sink Writer (+ codificatore)"]
Writer --> Sink2["Dissipatore multimediale"]
end
In generale, Media Foundation ha due modalità di utilizzo.
- Il modello che utilizza l’intera pipeline
- Collega sorgente / trasformazione / sink e Media Session gestisce il flusso di dati e la sincronizzazione A / V
- Il modello in cui l’app gestisce direttamente i dati
- Estrai i dati da una fonte con Source Reader e li inserisci in un sink con Sink Writer
Quest’ultimo è il punto di ingresso più semplice quando si desidera elaborare da soli fotogrammi e campioni. D’altra parte, se vuoi che la riproduzione e la sincronizzazione siano gestite dalla piattaforma, la prima è la strada giusta.
La cosa da tenere a mente è che Media Foundation è, in sostanza, una piattaforma di elaborazione multimediale: è un po’ diversa dalla sensazione di frugare direttamente in una pila di oggetti COM.
Ma una volta che inizi a guardare i confini tra i suoi componenti, la faccia di COM improvvisamente si intensifica. Il capitolo successivo esamina questi punti in ordine.
4. Dove Media Foundation mette la sua faccia da COM
4.1. CoInitializeEx e MFStartup affiancati durante l’inizializzazione
È qui che la maggior parte delle persone avverte per la prima volta la stranezza. Prima di parlare di apertura di un file o di acquisizione da una fotocamera, vengono visualizzati CoInitializeEx e MFStartup.
CoInitializeExinizializza la libreria COMMFStartupinizializza la piattaforma Media Foundation
In altre parole, l’inizializzazione COM da sola non è sufficiente: è necessaria anche l’inizializzazione lato Media Foundation. Qui ti viene in mente: “questa non è solo un’API video; sotto c’è un sostanziale contratto basato su COM.”
In pratica decidere a questo punto quanto segue rende tutto più semplice in seguito.
- Quale thread utilizza Media Foundation?
- Il thread sarà STA o MTA?
- A chi spettano le responsabilità di
MFStartup/MFShutdowneCoInitializeEx/CoUninitialize?
Se si va avanti con questo design lasciato vago, le cose diventano confuse in seguito riguardo ai callback e all’integrazione dell’UI.
4.2. I trasferimenti di oggetti sono incentrati sull’interfaccia
Mentre leggi Media Foundation API, la maggior parte dei valori restituiti e dei parametri out sono interfacce COM.
IMFSourceReaderIMFMediaTypeIMFTransformIMFActivateIMFSampleIMFMediaBuffer
Ciò che lo differenzia è che non solo i dati stessi, ma anche le informazioni sul tipo e gli oggetti delle impostazioni sono espressi come interfacce.
Ad esempio:
IMFTransformè l’interfaccia che rappresenta un MFTIMFAttributesè un archivio chiave / valoreIMFMediaTypeereditaIMFAttributesed è “una descrizione di un formato multimediale”
Anche qualcosa di simile ai dati di impostazione come un media type viene considerato un’interfaccia COM. È qui che il contesto di IUnknown, QueryInterface, AddRef / Release e HRESULT confluisce in modo naturale.
flowchart TD
IUnknown["IUnknown"]
IUnknown --> IMFAttributes["IMFAttributes"]
IMFAttributes --> IMFMediaType["IMFMediaType"]
IMFAttributes --> IMFActivate["IMFActivate"]
IUnknown --> IMFSourceReader["IMFSourceReader"]
IUnknown --> IMFTransform["IMFTransform"]
A questo punto puoi vedere: “Media Foundation è un’API multimediale, ma il modo in cui esprime i suoi confini è molto COM.”
4.3. Vengono visualizzati gli oggetti di attivazione
La COM-ness di Media Foundation si mostra più fortemente negli oggetti di attivazione.
IMFActivate è un oggetto di supporto per creare successivamente l’oggetto reale. Intuitivamente, è più semplice vederlo come qualcosa di simile alla class factory di COM.
Quando viene visualizzato, il valore restituito di un’API di enumerazione potrebbe non essere “un oggetto immediatamente utilizzabile” ma, innanzitutto, un array di IMFActivate*.
Quindi istanzia solo ciò di cui hai bisogno con ActivateObject.
sequenceDiagram
participant App as App
participant Enum as Enumeration API
participant Act as IMFActivate
participant Obj as IMFTransform / sink, etc.
App->>Enum: Call the enumeration
Enum-->>App: Array of IMFActivate*
App->>Act: Inspect the attributes
App->>Act: ActivateObject(...)
Act-->>App: The real COM object
Questa forma si adatta bene al progetto di Media Foundation di scoprire i componenti scambiabili in un secondo momento e comporli.
Inoltre, poiché un oggetto di attivazione può esso stesso portare attributi, il flusso tende ad essere: “ispezionare prima gli attributi dei candidati”, “configurare se necessario”, “istanziare in seguito”. Anche questo è molto simile a COM.
4.4. Impostazioni e tipo Centro informazioni su IMFAttributes e GUIDs
Lavorando con Media Foundation, c’è un punto in cui le impostazioni improvvisamente sembrano nient’altro che GUIDs. Al centro c’è IMFAttributes, un archivio chiave / valore con chiave GUIDs. È utilizzato in modo estremamente intenso in Media Foundation.
Particolarmente importante è IMFMediaType, che eredita IMFAttributes e trasporta le informazioni sul formato multimediale come attributi.
Ad esempio:
- Tipo principale (audio o video)
- Sottotipo (H.264, AAC, RGB32, PCM, ecc.)
- Dimensioni del telaio
- Frequenza dei fotogrammi
- Frequenza di campionamento
- Conteggio canali
flowchart LR
MediaType["IMFMediaType"] --> Major["MF_MT_MAJOR_TYPE"]
MediaType --> Subtype["MF_MT_SUBTYPE"]
MediaType --> Detail["Dimensioni / FPS / frequenza di campionamento, ecc."]
È facile percepirlo come “una foresta di GUIDs”, ma ciò che sta realmente accadendo è abbastanza chiaro.
- Conserva le impostazioni in un archivio di attributi
- Esprimi anche i tipi di media come negozi di attributi
- Negoziare i formati tra sorgente / trasformazione / sink controllando tali attributi
È semplicemente che le interfacce in stile COM e GUIDs vengono utilizzate per esprimere impostazioni e digitare informazioni.
4.5. Anche l’asincronia, i callback e il threading vengono gestiti nel modo COM
Ciò che è facile non notare nel lavoro Media Foundation del mondo reale è l’elaborazione asincrona e il modello di threading.
Ad esempio, Source Reader utilizza per impostazione predefinita la modalità sincrona. In modalità sincrona, ReadSample si blocca.
A seconda dello stato del file, della rete o del dispositivo, l’attesa può diventare visibilmente lunga.
Per utilizzare la modalità asincrona, si passa un callback durante la creazione del lettore di origine.
Si prepara un oggetto che implementa IMFSourceReaderCallback, lo si imposta sull’attributo MF_SOURCE_READER_ASYNC_CALLBACK e quindi si crea il lettore.
Un po’ più importante è ancora la questione dell’appartamento. L’elaborazione asincrona di Media Foundation utilizza code di lavoro e i thread delle code di lavoro sono MTA. Pertanto l’implementazione diventa più semplice se il lato applicativo funziona anche nel MTA.
sequenceDiagram
participant App as App thread
participant Reader as Source Reader
participant Queue as MF work queue (MTA)
participant Cb as IMFSourceReaderCallback
App->>Reader: ReadSample(...)
Reader-->>App: Returns immediately
Reader->>Queue: Processes internally
Queue->>Cb: OnReadSample(...)
Per quanto riguarda i callback, queste sono le cose da guardare.
- Non toccare gli oggetti STA del thread dell’UI direttamente dal lato callback
- Rendere l’implementazione del callback thread-safe
- Se sono necessari aggiornamenti dell’UI, eseguire il marshalling solo dei risultati nel thread dell’UI
- Fissa nella tua mente, fin dall’inizio, “su quale thread arrivano i callback Media Foundation?”
Media Foundation non assorbe le circostanze degli oggetti STA per te. Quindi è più semplice mantenere le cose organizzate inclinando il lavoratore Media Foundation verso MTA e costruendo un ponte esplicito verso l’UI.
4.6. Ma Media Foundation ≠ COM
Dopo aver letto fin qui, è facile pensare “quindi Media Foundation è solo COM dopo tutto.” Ma questo non è del tutto corretto.
Media Foundation contiene concetti specifici della piattaforma che le generalità di COM non coprono.
MFStartup/MFShutdown- Media Session
- Topologie
- Il caricatore di topologia
- L’orologio della presentazione
- Source Reader / Sink Writer
Questi sono i ruoli di Media Foundation: come eseguire la pipeline multimediale.
Ad esempio, in Media Session, l’applicazione trasmette una topologia parziale e il caricatore di topologia la risolve in una topologia completa compilando le trasformazioni necessarie. Questo non è COM generico: è la funzionalità che Media Foundation ha come piattaforma di elaborazione multimediale.
flowchart LR
Partial["Topologia parziale<br/>Sorgente -> Output"] --> Loader["Caricatore di topologia"]
Loader --> Full["Topologia completa<br/>Sorgente -> Decodificatore MFT -> Uscita"]
Media Foundation utilizza COM per esprimere i contratti tra i suoi componenti e, inoltre, funziona come una piattaforma di elaborazione multimediale. Mantenere questa visualizzazione a due livelli ti impedisce di perderti.
5. Una guida approssimativa alla scelta
Quando si decide il primo punto di ingresso, questo diagramma è solitamente sufficiente.
flowchart TD
Start["Cosa vuoi fare"] --> Q1{"Di cosa hai bisogno prima?"}
Q1 -- "Leggere fotogrammi / campioni" --> A1["Source Reader"]
Q1 -- "Scrivere su un file" --> A2["Sink Writer"]
Q1 -- "È necessario il controllo della riproduzione o la sincronizzazione A / V" --> A3["Media Session"]
Q1 -- "Inserisci una trasformazione personalizzata" --> A4["MFT"]
5.1. A partire da Source Reader
Source Reader è un punto di ingresso molto accessibile quando si desidera estrarre dati da file o dispositivi.
Si adatta a casi come questi.
- Ottenere fotogrammi da un file video
- Decodifica di un file audio per ottenere campioni
- Ottenere fotogrammi da una fotocamera
- Collegamento di una sorgente Media Foundation alla propria pipeline di elaborazione
Il Source Reader carica i decodificatori secondo necessità e trasmette i dati all’applicazione. D’altro canto, non si occupa della gestione dell’orologio di presentazione, della sincronizzazione A / V o del rendering sullo schermo stesso.
Diventa chiaro se lo si considera un punto di ingresso per “ottenere dati”, non per “riprodurli”.
5.2. Scrittura su file con Sink Writer
Sink Writer è il punto di ingresso quando desideri scrivere audio o video su file.
Gli usi tipici includono:
- Salvataggio dei fotogrammi generati in un file video
- Codifica e scrittura di campioni audio
- Conversione dei dati letti in un altro formato e salvataggio
Sink Writer trova e carica gli encoder secondo necessità e gestisce il flusso di dati nel dissipatore multimediale. Viene spesso combinato con il Source Reader, ma i due sono componenti indipendenti: non è necessario utilizzarli in coppia.
5.3. Gestire la riproduzione e la sincronizzazione con Media Session
Se il tuo obiettivo non è “estrarre dati da un file” ma riprodurli correttamente, è più naturale pensare alla sessione multimediale.
Il turno del Media Session arriva quando hai requisiti come questi.
- Gestione del gioco / stop / ricerca
- Lasciare la sincronizzazione audio-video alla piattaforma
- Gestione della pipeline compreso controllo qualità e cambi formato
- Composizione del flusso source / transform / sink utilizzando topologie
L’accesso a questo livello ti avvicina a “Media Foundation corretto” rispetto a Source Reader / Sink Writer. Di conseguenza, si moltiplicano anche i concetti specifici della Media Foundation - topologie, eventi di sessione.
5.4. Inserimento di componenti personalizzati con MFTs
MFT è il modello comune di Media Foundation per le trasformazioni.
Si entra in questo mondo in situazioni come:
- Costruisci il tuo decoder o codificatore
- Collegamento di componenti di elaborazione video o audio nella pipeline
- Enumerare codec e convertitori e sceglierli tu stesso
- Controllo delle cose più approfondito rispetto alla risoluzione automatica predefinita
Nel mondo MFT prevalgono i contratti stile COM: negoziazione IMFTransform, IMFActivate, media type, gestione campioni / buffer.
Pertanto, piuttosto che immergersi direttamente nel MFTs come primo punto di ingresso, è più chiaro determinare prima se ciò di cui hai effettivamente bisogno è il Source Reader / Sink Writer / Media Session.
6. Una lista di controllo pratica
Infine, ecco un riepilogo di una pagina di cosa controllare prima nel lavoro reale.
| Articolo | Cosa controllare | Cosa tende ad accadere se mancato |
|---|---|---|
| Responsabilità di inizializzazione | Decidi dove vengono chiamati CoInitializeEx e MFStartup e chi possiede lo smontaggio |
Inizializzazione mancata, ordine di smontaggio confuso |
| Appartamento | Decidi in anticipo se il thread che tocca MF è STA o MTA | Confusione sui callback, collisioni con l’UI |
| Source Reader modalità | Decidi la sincronizzazione o l’asincrono al momento della creazione | ReadSample si blocca inaspettatamente; impossibile cambiare più tardi |
| Media type trattativa | Enumerare i formati di output e indicare quello effettivamente utilizzato esplicitamente | MF_E_INVALIDMEDIATYPE, formati diversi da quelli previsti |
| Durata degli oggetti | Esplicitare le responsabilità per Release, Unlock, ShutdownObject |
Perdite di memoria, buffer conservati, incoerenza allo spegnimento |
| Oggetti di attivazione | Distinguere se i risultati dell’enumerazione sono oggetti reali o IMFActivate |
Fallendo perché pensavi di poterlo fare QueryInterface |
| Topologia | Scopri se stai gestendo una topologia parziale o completa | Rimanere bloccato supponendo che “dovrebbe connettersi automaticamente” |
| Errore durante il controllo | Controlla HRESULT, flag di streaming ed eventi ogni volta |
Guasti parziali mancanti |
| Integrazione dell’UI | Non toccare mai l’UI direttamente dai callback; marshal risultati solo nel thread dell’UI | Blocchi, gare, bug difficili da diagnosticare |
I tre elementi con la priorità più alta sono:
- Non scegliere la voce API sbagliata
- Determina innanzitutto quale tra Source Reader / Sink Writer / Media Session ti serve effettivamente
- Decidi l’appartamento in anticipo
- Se le code di lavoro dell’UI di STA e di Media Foundation si mescolano, decidere prima l’approccio bridge
- Non essere negligente con la negoziazione media type
- Procedere con “probabilmente è questo formato” diventa molto confuso in seguito
6.3. Smart pointer COM
In questo articolo il codice usa SafeRelease scritto a mano e puntatori non gestiti alle interfacce. Questo perché gli esempi nella documentazione Microsoft sono scritti in questa forma, così si vede dove agiscono AddRef / Release. Tuttavia, questo non è un motivo per non usare smart pointer nel codice reale. Se scrivi nuovo codice C++, è più sicuro orientarsi su uno dei due seguenti.
| Scelta | Implementazione | Note |
|---|---|---|
Microsoft::WRL::ComPtr<T> |
<wrl/client.h> |
Incluso nel Windows SDK, nessuna dipendenza aggiuntiva. Get() restituisce il puntatore non gestito, GetAddressOf() / & per gli argomenti out, As<U>() per scrivere QueryInterface. |
wil::com_ptr<T> |
wil/com.h delle WIL (Windows Implementation Libraries) |
Da installare separatamente, ad esempio tramite NuGet. Include helper che convertono HRESULT in eccezioni. |
Se scrivi con ComPtr, combinazioni come goto done; e SafeRelease non servono più: Release viene chiamato automaticamente all’uscita dallo scope. In questo articolo lasciamo i puntatori non gestiti per rendere visibili le convenzioni COM, ma per codice nuovo consigliamo di iniziare con ComPtr.
7. Estratti di codice
Invece di esempi completi, qui ci sono solo estratti sufficienti per mostrare dove appare la faccia COM.
7.1. Inizializzazione
template <class T>
void SafeRelease(T** pp)
{
if (pp != nullptr && *pp != nullptr)
{
(*pp)->Release();
*pp = nullptr;
}
}
HRESULT InitializeMediaFoundationForCurrentThread()
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
return hr;
}
hr = MFStartup(MF_VERSION);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
return S_OK;
}
void UninitializeMediaFoundationForCurrentThread()
{
MFShutdown();
CoUninitialize();
}
Qui, CoInitializeEx e MFStartup siedono fianco a fianco.
Questo è il primo punto in cui l’atmosfera del COM si addensa improvvisamente mentre si lavora con Media Foundation.
Nelle implementazioni, un altro livello potrebbe già essere responsabile dell’inizializzazione COM. Anche in questo caso, è più sicuro stabilire in anticipo chi ha la responsabilità.
7.2. Creazione di un Source Reader in modalità sincrona
HRESULT ReadOneVideoSample(PCWSTR path)
{
IMFSourceReader* pReader = nullptr;
IMFMediaType* pType = nullptr;
IMFSample* pSample = nullptr;
HRESULT hr = MFCreateSourceReaderFromURL(path, nullptr, &pReader);
if (FAILED(hr)) goto done;
hr = MFCreateMediaType(&pType);
if (FAILED(hr)) goto done;
hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (FAILED(hr)) goto done;
hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
if (FAILED(hr)) goto done;
hr = pReader->SetCurrentMediaType(
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
nullptr,
pType);
if (FAILED(hr)) goto done;
DWORD streamFlags = 0;
LONGLONG timestamp = 0;
hr = pReader->ReadSample(
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
nullptr,
&streamFlags,
×tamp,
&pSample);
if (FAILED(hr)) goto done;
// Extract the IMFMediaBuffer from pSample and process it
done:
SafeRelease(&pSample);
SafeRelease(&pType);
SafeRelease(&pReader);
return hr;
}
Cosa diventa visibile qui:
- Sia il lettore che il media type sono interfacce COM
- Le impostazioni sono basate su GUID
- I valori restituiti sono
HRESULT - In modalità sincrona,
ReadSamplesi blocca
Anche “Voglio solo leggere un fotogramma” assume una faccia pesantemente COM al confine di Media Foundation.
Procedura di negoziazione del media type (è uno degli elementi elencati nella checklist “3 cose da vedere per prime” del capitolo 6)
Il codice sopra dichiara solo “lo voglio in RGB32”, quindi nella pratica servono passaggi prima e dopo. Il flusso indicato dalla documentazione Microsoft per Source Reader è composto da questi 4 passaggi.
- Enumerare i tipi nativi — Chiamare
IMFSourceReader::GetNativeMediaType(streamIndex, typeIndex, &pType)aumentandotypeIndexa partire da 0. Quando si supera il range, viene restituitoMF_E_NO_MORE_TYPES: questo è il segnale di fine enumerazione (sestreamIndexè fuori range, si ottieneMF_E_INVALIDSTREAMNUMBER). Per i file di solito c’è un solo tipo per stream, ma una webcam può averne diversi - Verificare il major type — Dal media type enumerato, leggere
MF_MT_MAJOR_TYPEper capire se è audio o video. Se si procede a tentoni senza questo controllo, si rischia di impostare un formato video su uno stream audio - Compilare e impostare il formato di output desiderato — Creare un nuovo media type con
MFCreateMediaType, impostareMF_MT_MAJOR_TYPEeMF_MT_SUBTYPE, quindi chiamareSetCurrentMediaType. Se si vuole ricevere i dati compressi, passare il tipo ottenuto al passo 1; se si vuole decodificarli, specificare un formato non compresso comeMFVideoFormat_RGB32oMFAudioFormat_PCM. Il Source Reader carica automaticamente il decoder - Rileggere il formato effettivamente confermato — Dopo
SetCurrentMediaType, chiamareGetCurrentMediaTypeper leggere i dettagli del formato effettivo (dimensioni del frame, stride, sample rate, ecc.). Poiché quanto passato al passo 3 è una specifica parziale, i valori finali vanno letti qui
Se si saltano questi 4 passaggi e si procede con “probabilmente è questo formato”, si ottiene MF_E_INVALIDMEDIATYPE o, peggio, si leggono buffer in un formato diverso da quello atteso.
7.3. Creazione di un Source Reader in modalità asincrona
HRESULT CreateSourceReaderAsync(
PCWSTR path,
IMFSourceReaderCallback* pCallback,
IMFSourceReader** ppReader)
{
IMFAttributes* pAttributes = nullptr;
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
if (FAILED(hr))
{
return hr;
}
hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, pCallback);
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromURL(path, pAttributes, ppReader);
}
SafeRelease(&pAttributes);
return hr;
}
In questo caso, per abilitare la modalità asincrona, il callback viene inserito negli attributi prima che venga creato il lettore.
Cioè:
- La richiamata stessa è un’interfaccia COM
- La configurazione asincrona passa attraverso
IMFAttributes - La modalità è fissa al momento della creazione
In pratica, ciò che conta è rendere l’implementazione IMFSourceReaderCallback thread-safe e non trasportare oggetti dell’UI direttamente al suo interno.
7.4. Enumerazione e istanziazione di MFTs con MFTEnumEx
HRESULT FindH264Decoder(IMFTransform** ppTransform)
{
*ppTransform = nullptr;
IMFActivate** ppActivate = nullptr;
UINT32 count = 0;
MFT_REGISTER_TYPE_INFO inputType = {};
inputType.guidMajorType = MFMediaType_Video;
inputType.guidSubtype = MFVideoFormat_H264;
HRESULT hr = MFTEnumEx(
MFT_CATEGORY_VIDEO_DECODER,
MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT,
&inputType,
nullptr,
&ppActivate,
&count);
if (FAILED(hr))
{
return hr;
}
if (count == 0)
{
CoTaskMemFree(ppActivate);
return MF_E_TOPO_CODEC_NOT_FOUND;
}
hr = ppActivate[0]->ActivateObject(
__uuidof(IMFTransform),
reinterpret_cast<void**>(ppTransform));
for (UINT32 i = 0; i < count; ++i)
{
ppActivate[i]->Release();
}
CoTaskMemFree(ppActivate);
return hr;
}
Qui il risultato dell’enumerazione non ritorna come IMFTransform* dall’inizio ma come IMFActivate**.
Solo chiamando ActivateObject ottieni finalmente il vero IMFTransform.
Questo flusso cattura il modo in cui Media Foundation “ha improvvisamente messo su la sua faccia da COM” sentendosi straordinariamente bene.
8. Conclusione
Non è un caso che gli argomenti COM si moltiplichino quando lavori con Media Foundation.
- Media Foundation è una piattaforma di elaborazione multimediale
- I suoi confini - sorgente / trasformazione / sink / attivazione / callback - sono espressi come interfacce COM
- Di conseguenza,
IUnknown,HRESULT, GUIDs, appartamenti e richiamate vengono visualizzati naturalmente - Tuttavia, il cuore di Media Foundation è una pipeline multimediale con Media Session e topologie: non è un semplice rimaneggiamento di COM
In pratica, pensare in questo ordine mantiene le cose ben organizzate.
- Innanzitutto, determina quale tra Source Reader / Sink Writer / Media Session / MFT ti serve effettivamente
- Decidi in anticipo l’appartamento e la politica di richiamata
- Gestire con attenzione la negoziazione media type e la durata degli oggetti
Non è necessario capire tutto dall’inizio. Inizia con l’idea che “Media Foundation è una piattaforma di elaborazione multimediale, con COM profondamente incorporato nelle sue superfici di confine,” e sia la documentazione che il codice diventeranno molto più facili da seguire.
9. Riferimenti
- Media Foundation e COM - Microsoft Learn
- Panoramica dell’architettura Media Foundation - Microsoft Learn
- Inizializzazione Media Foundation - Microsoft Learn
- Source Reader - Microsoft Learn
- Utilizzo di Source Reader per elaborare i dati multimediali - Microsoft Learn
- Utilizzo di Source Reader in modalità asincrona - Microsoft Learn
- Sink Writer - Microsoft Learn
- Oggetti di attivazione - Microsoft Learn
- Informazioni sulle topologie - Microsoft Learn
- IMFAttributes interfaccia - Microsoft Learn
- IMFMediaType interfaccia - Microsoft Learn
- IMFTransform interfaccia - Microsoft Learn
- Funzione MFTEnumEx - Microsoft Learn
- COM STA / MTA Fondamenti per evitare blocchi | KomuraSoftBlog
- Perché dovresti creare un wrapper C++/CLI quando usi C++ DLLs nativo da C# | KomuraSoftBlog
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
Come convertire YUV in RGB con Media Foundation
Due modi per ottenere RGB da YUV in Media Foundation: lasciare che Source Reader emetta RGB32 o convertire NV12 / YUY2 con il passo e la ...
Estrazione di un'immagine fissa da un MP4 in un momento specifico con Media Foundation
Come acquisire il fotogramma più vicino a un determinato tempo in un MP4 con Source Reader, correggere il passo e il RGB32 byte alfa e sa...
Outsourcing e sviluppo su commissione di app Windows: cosa chiarire prima di affidare l'incarico
Prima di affidare in outsourcing o su commissione lo sviluppo di un'app Windows, ecco i punti da chiarire: revisione del software esisten...
Il curioso amore di uno sviluppatore, ovvero: come ho imparato a non preoccuparmi e ad amare Windows
Windows è complicato. Ma questa complicazione è anche quella di un sistema operativo che da decenni porta sulle spalle il lavoro reale.
Cos'è Reg-Free COM - Utilizzo di COM senza registrazione
Una panoramica delle basi di Reg-Free COM, i ruoli dei contesti di attivazione e dei manifest, i vantaggi, le limitazioni e come decidere...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Migrazione ActiveX
Scelte per mantenere, incapsulare o sostituire componenti COM / ActiveX / OCX.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Sviluppo di applicazioni Windows
L'elaborazione multimediale Windows che coinvolge Media Foundation, COM e HRESULT è vicina agli argomenti di implementazione che gestiamo come sviluppo di applicazioni Windows.
Consulenza tecnica e revisione del progetto
Se desideri prima risolvere i limiti dello stile COM e l'ordine di inizializzazione, possiamo iniziare dal lato della progettazione attraverso la consulenza tecnica e la revisione del progetto.
Domande frequenti
Domande che ricorrono nelle consulenze sull’argomento dell’articolo.
- Perché Media Foundation utilizza COM?
- Media Foundation è una piattaforma di elaborazione multimediale, ma i confini tra i suoi componenti (sorgenti, trasformazioni, sink, oggetti di attivazione, attributi e callback) sono espressi come interfacce COM. Ecco perché gli argomenti IUnknown, HRESULT, GUIDs e gli appartamenti emergono naturalmente mentre lo usi. Media Foundation non è puro COM, però: concetti come Media Session, topologie e orologio di presentazione sono funzionalità a livello di piattaforma costruite sulla base dei contratti COM.
- Dovrei iniziare con Source Reader, Sink Writer o Media Session?
- Inizia con Source Reader se desideri ottenere fotogrammi o campioni da un file o da una fotocamera: carica i decodificatori secondo necessità. Utilizza Sink Writer per scrivere l'audio o il video generato su file, raggruppando il codificatore e il dissipatore multimediale. Passare a Media Session solo quando è necessario un adeguato controllo della riproduzione, ricerca o sincronizzazione audio-video, poiché è necessaria la comprensione delle topologie. MFTs arriva per ultimo, quando devi inserire trasformazioni personalizzate.
- Perché mi servono sia CoInitializeEx che MFStartup?
- Perché inizializzano due livelli diversi: CoInitializeEx inizializza la libreria COM per il thread e MFStartup inizializza la piattaforma Media Foundation. COM l'inizializzazione da sola non è sufficiente. In pratica, dovresti anche decidere in anticipo quale thread utilizza Media Foundation, se quel thread è STA o MTA e chi possiede le corrispondenti responsabilità di arresto di MFShutdown e CoUninitialize, perché lasciare questo vago causa confusione sui callback e sull'integrazione dell'UI in un secondo momento.
- Su quali thread vengono eseguiti i callback Media Foundation?
- L'elaborazione asincrona di Media Foundation utilizza code di lavoro e i thread della coda di lavoro sono MTA, quindi i callback come IMFSourceReaderCallback arrivano sui thread MTA. L'implementazione diventa più semplice se il lato applicativo funziona anche nel MTA. Non toccare mai gli oggetti STA del thread dell'UI direttamente da un callback: rendi l'implementazione del callback thread-safe ed esegui il marshalling solo dei risultati nel thread dell'UI quando sono necessari aggiornamenti.
Profilo dell’autore
Pagina di presentazione dell’autore dell’articolo.
Go Komura
Rappresentante di KomuraSoft LLC
Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.