Kayıttan Yürütme Topolojileri Oluşturma
Ses veya video oynatma için bir topoloji nasıl oluşturulur, bu konuda anlatılmaktadır. Temel çalma için, kaynak düğümlerin doğrudan çıkış düğümlerine bağlandığı kısmi bir topoloji oluşturabilirsiniz. Ara dönüşümler için kod çözücüler veya renk dönüştürücüleri gibi herhangi bir düğüm eklemeniz gerekmez. Medya Oturumu topolojiyi çözümlemek için topoloji yükleyicisini kullanır ve topoloji yükleyicisi gerekli dönüşümleri ekler.
- Topolojiyi Oluşturma
- Akışları Medya Havuzlarına Bağlama
- Medya Alıcısı Oluşturma
- Sonraki Adımlar
- İlgili konular
Topoloji oluşturma
Bir medya kaynağından kısmi oynatma topolojisi oluşturmanın genel adımları şunlardır:
- Medya kaynağını oluşturun. Çoğu durumda, medya kaynağını oluşturmak için kaynak çözümleyiciyi kullanırsınız. Daha fazla bilgi için bkz. Kaynak Çözümleyicisi.
- Medya kaynağının sunu tanımlayıcısını alın.
- Boş bir topoloji oluşturun.
- Akış tanımlayıcılarını numaralandırmak için sunu tanımlayıcısını kullanın. Her akış tanımlayıcısı için:
- Akışın ses veya video gibi ana medya türünü alın.
- Akışın seçili olup olmadığını denetleyin. (İsteğe bağlı olarak, medya türüne göre bir akışı seçebilir veya seçimini kaldırabilirsiniz.)
- Akış seçiliyse, akışın medya türüne göre medya havuzu için bir etkinleştirme nesnesi oluşturun.
- Akış için bir kaynak düğüm ve medya havuzu için bir çıkış düğümü ekleyin.
- Kaynak düğümü çıkış düğümüne bağlayın.
Bu işlemin daha kolay izlenmesini sağlamak için, bu konudaki örnek kod çeşitli işlevler halinde düzenlenmiştir. Üst düzey işlev CreatePlaybackTopology
olarak adlandırılır. Üç parametre alır:
- Medya kaynağının bir IMFMediaSource arabirimine işaretçi.
- Sunu tanımlayıcısının IMFPresentationDescriptor arabirimine yönelik bir işaretçi. IMFMediaSource::CreatePresentationDescriptorçağırarak bu işaretçiyi alın. Birden çok sunuya sahip kaynaklar için, sonraki sunuların sunu tanımlayıcıları MENewPresentation olayında sunulur.
- Uygulama penceresinin tutma yeri. Kaynağın video akışı varsa, video bu pencerede görüntülenir.
İşlev, ppTopology parametresinde yer alan kısmi oynatım topolojisine bir işaretçi döndürür.
// 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;
}
Bu işlev aşağıdaki adımları gerçekleştirir:
- Topolojiyi oluşturmak için MFCreateTopology çağırın. Başlangıçta, topoloji herhangi bir düğüm içermez.
- Sunudaki akış sayısını almak için IMFPresentationDescriptor::GetStreamDescriptorCount çağrısı yapın.
- Her akış için uygulama tanımlı
AddBranchToPartialTopology
işlevini topolojideki bir dala çağırın. Bu işlev sonraki bölümde gösterilir.
Akışları Medya Havuzlarına Bağlama
Seçilen her akış için bir kaynak düğüm ve bir çıkış düğümü ekleyin ve ardından iki düğümü bağlayın. Kaynak düğüm akışı temsil eder. Çıkış düğümü, Gelişmiş Video İşleyicisi (EVR) veya Streaming Audio Renderer (SAR) öğesini temsil eder.
Sonraki örnekte gösterilen AddBranchToPartialTopology
işlevi aşağıdaki parametreleri alır:
- Topolojinin IMFTopology arabirimine bir işaretçi.
- Medya kaynağının IMFMediaSource arabirimine bir işaretçi.
- Sunu tanımlayıcısının IMFPresentationDescriptor arabirimine yönelik bir işaretçi.
- Akışın sıfır tabanlı dizini.
- Video penceresinin tutamacı. Bu kol yalnızca video yayını için kullanılır.
// 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;
}
işlevi aşağıdakileri yapar:
- IMFPresentationDescriptor::GetStreamDescriptorByIndex çağrısı ve akış dizininden geçer. Bu yöntem, akışın seçili olup olmadığını gösteren boole değeriyle birlikte bu akış için akış tanımlayıcısına bir işaretçi döndürür.
- Akış seçili değilse işlevden çıkar ve S_OK döndürür, çünkü uygulamanın seçilmediği sürece bir akış için topoloji dalı oluşturması gerekmez.
- Akış seçilirse işlev topoloji dalını aşağıdaki gibi tamamlar:
- Uygulama tanımlı CreateMediaSinkActivate işlevini çağırarak havuz için bir etkinleştirme nesnesi oluşturur. Bu işlev sonraki bölümde gösterilir.
- Topolojiye bir kaynak düğüm ekler. Bu adımın kodu, kaynak düğümleri oluşturma konusunda gösterilmiştir.
- Topolojiye bir çıkış düğümü ekler. Bu adımın kodu, Çıkış Düğümleri Oluşturmakonusunda gösterilmiştir.
- kaynak düğümde IMFTopologyNode::ConnectOutput çağırarak iki düğümü bağlar. Uygulama, düğümleri bağlayarak yukarı akış düğümünü aşağı akış düğümüne veri teslim etmesi gerektiğini belirtir. Kaynak düğümün bir çıkışı vardır ve çıkış düğümünde bir giriş vardır, bu nedenle her iki akış dizini de sıfırdır.
Daha gelişmiş uygulamalar, kaynağın varsayılan yapılandırmasını kullanmak yerine akışları seçebilir veya bu akışların seçimini kaldırabilir. Bir kaynağın birden çok akışı olabilir ve bunlardan herhangi biri varsayılan olarak seçilebilir. Medya kaynağının sunu tanımlayıcısı varsayılan bir akış seçimleri kümesine sahiptir. Tek bir ses akışı ve video akışına sahip basit bir video dosyasında, medya kaynağı genellikle her iki akışı da varsayılan olarak seçer. Ancak, bir dosyada farklı diller için birden çok ses akışı veya farklı bit hızlarında kodlanmış birden çok video akışı olabilir. Bu durumda, bazı akışlar varsayılan olarak seçilmemiş olacak. Uygulama, sunum tanımlayıcısı üzerinde IMFPresentationDescriptor::SelectStream ve IMFPresentationDescriptor::DeselectStream çağrısı yaparak seçimi değiştirebilir.
Medya Havuzu Oluşturma
Sonraki işlev, EVR veya SAR medya havuzu için bir etkinleştirme nesnesi oluşturur.
// 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;
}
Bu işlev aşağıdaki adımları gerçekleştirir:
Akış tanımlayıcısı üzerinde IMFStreamDescriptor::GetMediaTypeHandler çağırır. Bu yöntem, bir IMFMediaTypeHandler arabirim işaretçisi döndürür.
IMFMediaTypeHandler::GetMajorTypeçağrısı yapılır. Bu yöntem, akışın ana türüne ait GUID'yi döndürür.
Akış türü ses ise işlev, ses işleyici etkinleştirme nesnesini oluşturmak için MFCreateAudioRendererActivateçağırır. Akış türü video ise işlev, video işleyici etkinleştirme nesnesini oluşturmak için MFCreateVideoRendererActivateçağırır. Bu işlevlerin her ikisi de IMFActivate arabirimine bir işaretçi döndürür. Bu işaretçi, daha önce gösterildiği gibi havuz için çıkış düğümünü başlatmak için kullanılır.
Diğer herhangi bir akış türü için bu örnek bir hata kodu döndürür. Alternatif olarak, akışı kaldırmak yeterlidir.
Sonraki Adımlar
Aynı anda tek bir medya dosyası yürütmek için, IMFMediaSession::SetTopologyçağırarak Medya Oturumunda topolojiyi sıraya koyun. Medya Oturumu topolojiyi çözümlemek için topoloji yükleyicisini kullanır. Tam bir örnek için bkz. Media Foundation ile Medya Dosyalarını Yürütme .
İlgili konular