Поделиться через


Создание топологий воспроизведения

В этом разделе описывается создание топологии для воспроизведения звука или видео. Для базового воспроизведения можно создать частичную топологию, в которой исходные узлы подключаются непосредственно к выходным узлам. Вам не нужно вставлять узлы для промежуточных преобразований, таких как декодеры или преобразователи цветов. Сеанс мультимедиа будет использовать загрузчик топологии для разрешения топологии, а загрузчик топологии вставляет необходимые преобразования.

Создание топологии

Ниже приведены общие шаги по созданию топологии частичного воспроизведения из источника мультимедиа:

  1. Создайте источник мультимедиа. В большинстве случаев вы будете использовать исходный сопоставитель для создания источника мультимедиа. Дополнительные сведения см. в сопоставителе источников .
  2. Получите дескриптор презентации источника мультимедиа.
  3. Создайте пустую топологию.
  4. Используйте дескриптор презентации для перечисления дескрипторов потока. Для каждого дескриптора потока:
    1. Получите основной тип мультимедиа потока, например аудио или видео.
    2. Проверьте, выбран ли поток в данный момент. (При необходимости можно выбрать или отменить выбор потока на основе типа носителя.)
    3. Если выбран поток, создайте объект активации для приемника мультимедиа на основе типа носителя потока.
    4. Добавьте исходный узел для потока и выходного узла приемника мультимедиа.
    5. Подключите исходный узел к выходному узлу.

Чтобы упростить выполнение этого процесса, пример кода в этом разделе организован в нескольких функциях. Функция верхнего уровня называется CreatePlaybackTopology. Он принимает три параметра:

  • Указатель на интерфейс IMFMediaSource источника мультимедиа.
  • Указатель на интерфейс IMFPresentationDescriptor дескриптора презентации. Получите этот указатель, вызвав IMFMediaSource::CreatePresentationDescriptor. Для источников с несколькими презентациями дескрипторы презентаций для последующих презентаций предоставляются в событии MENewPresentation.
  • Дескриптор окна приложения. Если источник имеет видеопоток, видео будет отображаться в этом окне.

Функция возвращает указатель на частичную топологию воспроизведения в параметре 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;
}

Эта функция выполняет следующие действия:

  1. Вызовите MFCreateTopology для создания топологии. Изначально топология не содержит узлов.
  2. Вызовите IMFPresentationDescriptor::GetStreamDescriptorCount, для получения количества потоков в презентации.
  3. Для каждого потока вызовите определяемую приложением функцию AddBranchToPartialTopology к ветви в топологии. Эта функция показана в следующем разделе.

Подключение потоков к приемникам мультимедиа

Для каждого выбранного потока добавьте исходный узел и выходной узел, а затем подключите два узла. Исходный узел представляет поток. Выходной узел представляет либо расширенный видео рендерер (EVR), либо потоковый аудио рендерер (SAR).

Функция AddBranchToPartialTopology, показанная в следующем примере, принимает следующие параметры:

  • Указатель на интерфейс IMFTopology топологии.
  • Указатель на интерфейс IMFMediaSource источника мультимедиа.
  • Указатель на интерфейс IMFPresentationDescriptor дескриптора презентации.
  • Отсчитываемый от нуля индекс потока.
  • Дескриптор к окну видео. Этот дескриптор используется только для видеопотока.
//  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;
}

Эта функция выполняет следующие действия:

  1. Вызывает IMFPresentationDescriptor::GetStreamDescriptorByIndex и передает индекс потока. Этот метод возвращает указатель на дескриптор потока для этого потока, а также логическое значение, указывающее, выбран ли поток.
  2. Если поток не выбран, функция завершает работу и возвращает S_OK, так как приложению не нужно создавать ветвь топологии для потока, если она не выбрана.
  3. Если выбран поток, функция завершает ветвь топологии следующим образом:
    1. Создает объект активации для приемника, вызвав функцию CreateMediaSinkActivate, определяемую приложением. Эта функция показана в следующем разделе.
    2. Добавляет исходный узел в топологию. Код этого шага показан в разделе создании исходных узлов.
    3. Добавляет выходной узел в топологию. Код этого шага показан в разделе создании выходных узлов.
    4. Подключает два узла, вызвав IMFTopologyNode::ConnectOutput на исходном узле. Подключив узлы, приложение указывает, что вышестоящий узел должен доставлять данные на подчиненный узел. Исходный узел имеет один выход, а выходной узел имеет один входной ввод, поэтому оба индекса потока равны нулю.

Более сложные приложения могут выбирать или отменять выбор потоков, а не использовать конфигурацию источника по умолчанию. Источник может иметь несколько потоков, и любой из них может быть выбран по умолчанию. Дескриптор представления источника мультимедиа имеет набор выбранных потоков по умолчанию. В простом видеофайле с одним аудиопотоком и видеопотоком источник мультимедиа обычно выбирает оба потока по умолчанию. Однако файл может иметь несколько звуковых потоков для разных языков или несколько видеопотоков, закодированных по разным скоростям. В этом случае некоторые потоки будут не выбраны по умолчанию. Приложение может изменить выбор, вызвав IMFPresentationDescriptor::SelectStream и IMFPresentationDescriptor::DeselectStream на презентационном дескрипторе.

Создание приемника мультимедиа

Следующая функция создает объект активации для приемника мультимедиа EVR или 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;
}

Эта функция выполняет следующие действия:

  1. Вызывает дескриптор потока IMFStreamDescriptor::GetMediaTypeHandler. Этот метод возвращает указатель интерфейса IMFMediaTypeHandler.

  2. Вызывает IMFMediaTypeHandler::GetMajorType. Этот метод возвращает GUID основного типа для потока.

  3. Если тип потока является звуком, функция вызывает MFCreateAudioRendererActivate для создания объекта активации отрисовщика звука. Если тип потока является видео, функция вызывает MFCreateVideoRendererActivate для создания объекта активации отрисовщика видео. Обе эти функции возвращают указатель на интерфейс IMFActivate. Этот указатель используется для инициализации выходного узла приемника, как показано ранее.

Для любого другого типа потока в этом примере возвращается код ошибки. Кроме того, можно просто отменить выбор потока.

Дальнейшие действия

Чтобы воспроизвести один мультимедийный файл за раз, добавьте топологию в очередь на медиасессии с помощью вызова IMFMediaSession::SetTopology. Сеанс мультимедиа будет использовать загрузчик топологии для разрешения топологии. Полный пример см. в разделе Воспроизведение файлов мультимедиа с помощьюMedia Foundation.

Воспроизведение незащищенных файлов мультимедиа

мультимедиа-сеанс

Топологии