Tworzenie topologii odtwarzania
W tym temacie opisano sposób tworzenia topologii na potrzeby odtwarzania audio lub wideo. W przypadku odtwarzania podstawowego można utworzyć topologię częściową, w której węzły źródłowe są połączone bezpośrednio z węzłami wyjściowymi. Nie trzeba wstawiać żadnych węzłów dla przekształceń pośrednich, takich jak dekodatory lub konwertery kolorów. Sesja medialna użyje ładowarki topologii, aby rozwiązać topologię, a ładowarka topologii wstawi wymagane przekształcenia.
- Tworzenie topologii
- łączenie strumieni z ujściami multimediów
- Tworzenie odbiornika multimediów
- następne kroki
- Tematy pokrewne
Tworzenie topologii
Poniżej przedstawiono ogólne kroki tworzenia topologii częściowego odtwarzania ze źródła multimediów:
- Utwórz źródło multimediów. W większości przypadków użyjesz narzędzia rozpoznawania źródła do utworzenia źródła multimediów. Aby uzyskać więcej informacji, zobacz Source Resolver.
- Pobierz opis prezentacji źródła multimediów.
- Utwórz pustą topologię.
- Użyj deskryptora prezentacji, aby wyliczyć deskryptory strumienia. Dla każdego deskryptora strumienia:
- Pobierz główny typ multimediów strumienia, taki jak audio lub wideo.
- Sprawdź, czy strumień jest aktualnie wybrany. (Opcjonalnie możesz zaznaczyć lub odznaczyć strumień w zależności od typu nośnika).
- Jeśli strumień zostanie wybrany, utwórz obiekt aktywacji dla odbiornika multimediów na podstawie typu nośnika.
- Dodaj węzeł źródłowy dla strumienia i węzeł wyjściowy dla odbiornika multimediów.
- Połącz węzeł źródłowy z węzłem wyjściowym.
Aby ułatwić wykonanie tego procesu, przykładowy kod w tym temacie jest zorganizowany w kilka funkcji. Funkcja najwyższego poziomu nosi nazwę CreatePlaybackTopology
. Przyjmuje trzy parametry:
- Wskaźnik do interfejsu IMFMediaSource źródła multimediów.
- Wskaźnik do interfejsu IMFPresentationDescriptor deskryptora prezentacji. Pobierz ten wskaźnik, wywołując IMFMediaSource::CreatePresentationDescriptor. W przypadku źródeł z wieloma prezentacjami, deskryptory prezentacji dla kolejnych prezentacji są dostarczane w zdarzeniu MENewPresentation.
- Uchwyt do okna aplikacji. Jeśli źródło ma strumień wideo, wideo zostanie wyświetlone w tym oknie.
Funkcja zwraca wskaźnik do topologii częściowego odtwarzania w parametrze 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;
}
Ta funkcja wykonuje następujące czynności:
- Wywołaj MFCreateTopology, aby utworzyć topologię. Początkowo topologia nie zawiera żadnych węzłów.
- Aby uzyskać liczbę strumieni w prezentacji, wywołaj IMFPresentationDescriptor::GetStreamDescriptorCount.
- Dla każdego strumienia wywołaj funkcję
AddBranchToPartialTopology
zdefiniowaną przez aplikację do gałęzi w topologii. Ta funkcja jest wyświetlana w następnej sekcji.
Łączenie strumieni z ujściami multimediów
Dla każdego wybranego strumienia dodaj węzeł źródłowy i węzeł wyjściowy, a następnie połącz dwa węzły. Węzeł źródłowy reprezentuje strumień. Węzeł wyjściowy reprezentuje Ulepszony moduł renderowania wideo (EVR) lub moduł renderowania audio strumieniowego (SAR).
Funkcja AddBranchToPartialTopology
pokazana w następnym przykładzie przyjmuje następujące parametry:
- Wskaźnik do interfejsu IMFTopology topologii.
- Wskaźnik do interfejsu IMFMediaSource z źródła multimediów.
- Wskaźnik do interfejsu IMFPresentationDescriptor deskryptora prezentacji.
- Indeks strumienia oparty na zerach.
- Uchwyt do okna wideo. Ten uchwyt jest używany tylko dla strumienia wideo.
// 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;
}
Funkcja wykonuje następujące czynności:
- Wywołuje IMFPresentationDescriptor::GetStreamDescriptorByIndex i przekazuje indeks strumienia. Ta metoda zwraca wskaźnik do deskryptora strumienia dla tego strumienia wraz z wartością logiczną wskazującą, czy strumień jest wybrany.
- Jeśli strumień nie jest zaznaczony, funkcja kończy działanie i zwraca S_OK, ponieważ aplikacja nie musi tworzyć gałęzi topologii dla strumienia, chyba że została wybrana.
- W przypadku wybrania strumienia funkcja kończy gałąź topologii w następujący sposób:
- Tworzy obiekt aktywacji dla ujścia, wywołując funkcję CreateMediaSinkActivate zdefiniowaną przez aplikację. Ta funkcja jest wyświetlana w następnej sekcji.
- Dodaje węzeł źródłowy do topologii. Kod tego kroku jest wyświetlany w temacie Tworzenie węzłów źródłowych.
- Dodaje węzeł wyjściowy do topologii. Kod tego kroku jest wyświetlany w temacie Tworzenie węzłów wyjściowych.
- Łączy dwa węzły, wywołując IMFTopologyNode::ConnectOutput w węźle źródłowym. Łącząc węzły, aplikacja wskazuje, że węzeł nadrzędny powinien dostarczać dane do węzła podrzędnego. Węzeł źródłowy ma jedno dane wyjściowe, a węzeł wyjściowy ma jedno dane wejściowe, więc oba indeksy strumienia są zerowe.
Bardziej zaawansowane aplikacje mogą wybierać lub odznaczać strumienie, zamiast korzystać z domyślnej konfiguracji źródła. Źródło może mieć wiele strumieni, a dowolna z nich może być domyślnie wybrana. Deskryptor prezentacji źródła multimediów ma domyślny zestaw wyborów strumienia. W prostym pliku wideo z jednym strumieniem audio i strumieniem wideo źródło multimediów zwykle wybiera oba strumienie domyślnie. Jednak plik może mieć wiele strumieni audio dla różnych języków lub wiele strumieni wideo zakodowanych w różnych szybkościach transmisji bitów. W takim przypadku niektóre strumienie zostaną domyślnie niezaznaczone. Aplikacja może zmienić wybór, wywołując IMFPresentationDescriptor::SelectStream i IMFPresentationDescriptor::DeselectStream na deskryptorze prezentacji.
Tworzenie odbiornika multimediów
Następna funkcja tworzy obiekt aktywacji dla ujścia multimediów EVR lub 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;
}
Ta funkcja wykonuje następujące czynności:
Wywołuje IMFStreamDescriptor::GetMediaTypeHandler w deskryptorze strumienia. Ta metoda zwraca wskaźnik interfejsu IMFMediaTypeHandler.
Wywołuje metodę IMFMediaTypeHandler::GetMajorType. Ta metoda zwraca identyfikator GUID typu głównego dla strumienia.
Jeśli typ strumienia to dźwięk, funkcja wywołuje MFCreateAudioRendererActivate w celu utworzenia obiektu aktywacji modułu renderowania audio. Jeśli typ strumienia to wideo, funkcja wywołuje MFCreateVideoRendererActivate w celu utworzenia obiektu aktywacji modułu renderowania wideo. Obie te funkcje zwracają wskaźnik do interfejsu IMFActivate. Ten wskaźnik służy do inicjowania węzła wyjściowego odbiornika, jak pokazano wcześniej.
W przypadku dowolnego innego typu strumienia ten przykład zwraca kod błędu. Alternatywnie możesz po prostu usunąć zaznaczenie strumienia.
Następne kroki
Aby odtworzyć jeden plik multimedialny naraz, ustaw topologię w kolejce na sesji multimedialnej, wywołując IMFMediaSession::SetTopology. Sesja multimedialna użyje loadera topologii, aby rozwiązać topologię. Aby zapoznać się z kompletnym przykładem, zobacz Jak odtwarzać pliki multimedialne za pomocą Media Foundation.
Tematy pokrewne