Sdílet prostřednictvím


Vytváření topologií přehrávání

Toto téma popisuje, jak vytvořit topologii pro přehrávání zvuku nebo videa. Pro základní přehrávání můžete vytvořit částečnou topologii, ve které jsou zdrojové uzly připojené přímo k výstupním uzlům. Není nutné vkládat žádné uzly pro přechodné transformace, jako jsou dekodéry nebo převaděče barev. Mediální relace použije zavaděč topologie k rozlišení topologie a zavaděč topologie vloží požadované transformace.

Vytvoření topologie

Tady jsou celkové kroky pro vytvoření topologie částečného přehrávání ze zdroje médií:

  1. Vytvořte zdroj médií. Ve většině případů použijete k vytvoření zdroje médií řešitel zdroje. Další informace najdete v překladači zdroje.
  2. Získejte popisovač prezentace zdroje médií.
  3. Vytvořte prázdnou topologii.
  4. Popisovač prezentace slouží k vytvoření výčtu popisovačů datových proudů. Pro každý popisovač datových proudů:
    1. Získejte hlavní typ média streamu, například zvuk nebo video.
    2. Zkontrolujte, jestli je aktuálně vybraný proud. (Volitelně můžete vybrat nebo zrušit výběr datového proudu na základě typu média.)
    3. Jika je datový proud vybrán, vytvořte aktivační objekt pro mediální přijímač na základě typu média vybraného datového proudu.
    4. Přidejte zdrojový uzel pro stream a výstupní uzel pro jímku médií.
    5. Připojte zdrojový uzel k výstupnímu uzlu.

Aby se tento proces snadněji sledoval, je ukázkový kód v tomto tématu uspořádaný do několika funkcí. Funkce nejvyšší úrovně má název CreatePlaybackTopology. Přebírá tři parametry:

Funkce vrátí ukazatel na částečnou topologii přehrávání v parametru ppTopology.

//  Create a playback topology from a media source.
HRESULT CreatePlaybackTopology(
    IMFMediaSource *pSource,          // Media source.
    IMFPresentationDescriptor *pPD,   // Presentation descriptor.
    HWND hVideoWnd,                   // Video window.
    IMFTopology **ppTopology)         // Receives a pointer to the topology.
{
    IMFTopology *pTopology = NULL;
    DWORD cSourceStreams = 0;

    // Create a new topology.
    HRESULT hr = MFCreateTopology(&pTopology);
    if (FAILED(hr))
    {
        goto done;
    }




    // Get the number of streams in the media source.
    hr = pPD->GetStreamDescriptorCount(&cSourceStreams);
    if (FAILED(hr))
    {
        goto done;
    }

    // For each stream, create the topology nodes and add them to the topology.
    for (DWORD i = 0; i < cSourceStreams; i++)
    {
        hr = AddBranchToPartialTopology(pTopology, pSource, pPD, i, hVideoWnd);
        if (FAILED(hr))
        {
            goto done;
        }
    }

    // Return the IMFTopology pointer to the caller.
    *ppTopology = pTopology;
    (*ppTopology)->AddRef();

done:
    SafeRelease(&pTopology);
    return hr;
}

Tato funkce provádí následující kroky:

  1. Voláním MFCreateTopology vytvořte topologii. Na začátku topologie neobsahuje žádné uzly.
  2. Volání IMFPresentationDescriptor::GetStreamDescriptorCount získat počet datových proudů v prezentaci.
  3. Pro každý proud volejte funkci definovanou aplikací AddBranchToPartialTopology ke větvi v topologii. Tato funkce se zobrazí v další části.

Připojení streamů k jímce médií

Pro každý vybraný datový proud přidejte zdrojový uzel a výstupní uzel a pak oba uzly propojte. Zdrojový uzel představuje datový proud. Výstupní uzel představuje Enhanced Video Renderer (EVR) nebo Stream Audio Renderer (SAR).

Funkce AddBranchToPartialTopology, která je znázorněná v dalším příkladu, přebírá následující parametry:

  • Ukazatel na rozhraní IMFTopology topologie.
  • Ukazatel na rozhraní IMFMediaSource zdroje médií.
  • Ukazatel na rozhraní IMFPresentationDescriptor popisovače prezentace.
  • Index datového proudu založený na nule.
  • Držitel video okna. Tento popisovač slouží pouze pro stream videa.
//  Add a topology branch for one stream.
//
//  For each stream, this function does the following:
//
//    1. Creates a source node associated with the stream. 
//    2. Creates an output node for the renderer. 
//    3. Connects the two nodes.
//
//  The media session will add any decoders that are needed.

HRESULT AddBranchToPartialTopology(
    IMFTopology *pTopology,         // Topology.
    IMFMediaSource *pSource,        // Media source.
    IMFPresentationDescriptor *pPD, // Presentation descriptor.
    DWORD iStream,                  // Stream index.
    HWND hVideoWnd)                 // Window for video playback.
{
    IMFStreamDescriptor *pSD = NULL;
    IMFActivate         *pSinkActivate = NULL;
    IMFTopologyNode     *pSourceNode = NULL;
    IMFTopologyNode     *pOutputNode = NULL;

    BOOL fSelected = FALSE;

    HRESULT hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD);
    if (FAILED(hr))
    {
        goto done;
    }

    if (fSelected)
    {
        // Create the media sink activation object.
        hr = CreateMediaSinkActivate(pSD, hVideoWnd, &pSinkActivate);
        if (FAILED(hr))
        {
            goto done;
        }

        // Add a source node for this stream.
        hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pSourceNode);
        if (FAILED(hr))
        {
            goto done;
        }

        // Create the output node for the renderer.
        hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode);
        if (FAILED(hr))
        {
            goto done;
        }

        // Connect the source node to the output node.
        hr = pSourceNode->ConnectOutput(0, pOutputNode, 0);
    }
    // else: If not selected, don't add the branch. 

done:
    SafeRelease(&pSD);
    SafeRelease(&pSinkActivate);
    SafeRelease(&pSourceNode);
    SafeRelease(&pOutputNode);
    return hr;
}

Funkce provede následující:

  1. Volá IMFPresentationDescriptor::GetStreamDescriptorByIndex a předává index streamu. Tato metoda vrátí ukazatel na popisovač datového proudu pro tento datový proud spolu s logickou hodnotou označující, zda je datový proud vybrán.
  2. Pokud datový proud není vybraný, funkce se ukončí a vrátí S_OK, protože aplikace nemusí vytvořit větev topologie pro datový proud, pokud není vybraná.
  3. Pokud je vybraný datový proud, funkce dokončí větev topologie následujícím způsobem:
    1. Vytvoří aktivační objekt pro jímku zavoláním funkce CreateMediaSinkActivate definované aplikací. Tato funkce se zobrazí v další části.
    2. Přidá zdrojový uzel do topologie. Kód pro tento krok je uveden v tématu Vytváření zdrojových uzlů.
    3. Přidá výstupní uzel do topologie. Kód pro tento krok se zobrazí v tématu Vytváření výstupních uzlů.
    4. Připojí dva uzly voláním IMFTopologyNode::ConnectOutput na zdrojovém uzlu. Propojením uzlů aplikace označuje, že nadřazený uzel by měl poskytovat data do podřízeného uzlu. Zdrojový uzel má jeden výstup a výstupní uzel má jeden vstup, takže oba indexy datových proudů jsou nulové.

Pokročilejší aplikace můžou místo výchozí konfigurace zdroje vybrat nebo zrušit výběr datových proudů. Zdroj může mít více datových proudů a každý z nich může být ve výchozím nastavení vybraný. Popisovač prezentace zdroje médií má výchozí sadu výběrů streamů. V jednoduchém videosouboru s jedním zvukovým streamem a streamem videa bude zdroj médií ve výchozím nastavení obvykle vybírat oba streamy. Soubor ale může mít několik zvukových proudů pro různé jazyky nebo několik datových proudů videa kódovaných v různých přenosových rychlostech. V takovém případě se některé streamy ve výchozím nastavení nevyberou. Aplikace může změnit výběr voláním IMFPresentationDescriptor::SelectStream a IMFPresentationDescriptor::DeselectStream v popisovači prezentace.

Vytvoření jímky médií

Další funkce vytvoří aktivační objekt pro mediální jímku EVR nebo SAR.

//  Create an activation object for a renderer, based on the stream media type.

HRESULT CreateMediaSinkActivate(
    IMFStreamDescriptor *pSourceSD,     // Pointer to the stream descriptor.
    HWND hVideoWindow,                  // Handle to the video clipping window.
    IMFActivate **ppActivate
)
{
    IMFMediaTypeHandler *pHandler = NULL;
    IMFActivate *pActivate = NULL;

    // Get the media type handler for the stream.
    HRESULT hr = pSourceSD->GetMediaTypeHandler(&pHandler);
    if (FAILED(hr))
    {
        goto done;
    }

    // Get the major media type.
    GUID guidMajorType;
    hr = pHandler->GetMajorType(&guidMajorType);
    if (FAILED(hr))
    {
        goto done;
    }
 
    // Create an IMFActivate object for the renderer, based on the media type.
    if (MFMediaType_Audio == guidMajorType)
    {
        // Create the audio renderer.
        hr = MFCreateAudioRendererActivate(&pActivate);
    }
    else if (MFMediaType_Video == guidMajorType)
    {
        // Create the video renderer.
        hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate);
    }
    else
    {
        // Unknown stream type. 
        hr = E_FAIL;
        // Optionally, you could deselect this stream instead of failing.
    }
    if (FAILED(hr))
    {
        goto done;
    }
 
    // Return IMFActivate pointer to caller.
    *ppActivate = pActivate;
    (*ppActivate)->AddRef();

done:
    SafeRelease(&pHandler);
    SafeRelease(&pActivate);
    return hr;
}

Tato funkce provádí následující kroky:

  1. Volá IMFStreamDescriptor::GetMediaTypeHandler na popisovači datového proudu. Tato metoda vrátí ukazatel rozhraní MMFMediaTypeHandler.

  2. Volání na IMFMediaTypeHandler::GetMajorType . Tato metoda vrátí identifikátor GUID hlavního typu streamu.

  3. Pokud je typ datového proudu audio, funkce volá MFCreateAudioRendererActivate vytvořit aktivační objekt zvukového rendereru. Pokud je typ streamu video, funkce volá MFCreateVideoRendererActivate vytvořit aktivační objekt rendereru videa. Obě tyto funkce vrátí ukazatel na rozhraní MMFActivate. Tento ukazatel slouží k inicializaci výstupního uzlu jímky, jak je znázorněno dříve.

Pro jakýkoli jiný typ datového proudu tento příklad vrátí kód chyby. Případně můžete jednoduše zrušit výběr streamu.

Další kroky

Chcete-li přehrát jeden multimediální soubor najednou, zařaďte topologii do fronty na mediatické relaci voláním IMFMediaSession::SetTopology. Mediální relace použije zavaděč topologie k určení topologie. Úplný příklad najdete v tématu Jak přehrávat mediální soubory pomocí media Foundation.

Přehrávání nechráněných mediálních souborů

Mediální relace

topologie