Como usar a origem do sequenciador

Este tópico descreve como usar a Origem do Sequenciador. Ele contém as seções a seguir:

Para obter uma visão geral da origem do sequenciador, confira Sobre a origem do sequenciador.

Visão geral

A origem do sequenciador expõe as interfaces a seguir.

Interface Descrição
IMFMediaSource Expõe a funcionalidade de fonte de mídia genérica.
IMFSequencerSource Permite que o aplicativo adicione ou remova topologias.
IMFMediaSourceTopologyProvider Recupera a próxima topologia a ser enfileirada na Sessão de Mídia.
IMFMediaSourcePresentationProvider Usado pela Sessão de Mídia para segmentos finais. Os aplicativos não usam essa interface.
IMFGetService Consulta a origem do sequenciador para Interfaces de Serviço.

 

Para reproduzir uma sequência de origens de mídia, execute as seguintes etapas:

  1. Para criar a origem do sequenciador, chame a função MFCreateSequencerSource.
  2. Para cada segmento, crie uma topologia de reprodução, conforme descrito em Como criar topologias de reprodução. Para adicionar a topologia à apresentação, chame IMFSequencerSource::AppendTopology.
  3. Antes de iniciar a reprodução, chame IMFMediaSource::CreatePresentationDescriptor na origem do sequenciador. Esse método retorna um ponteiro para um descritor de apresentação do primeiro segmento. Para obter a topologia associada a esse segmento, chame QueryInterface na origem do sequenciador da interface IMFMediaSourceTopologyProvider. Passe o descritor de apresentação para o método IMFMediaSourceTopologyProvider::GetMediaSourceTopology. Esse método retorna um ponteiro para a topologia.
  4. Passe a topologia do primeiro segmento para a Sessão de Mídia, chamando o método IMFMediaSession::SetTopology da Sessão de Mídia.
  5. Inicie a reprodução chamando IMFMediaSession::Start.
  6. Quando a origem do sequenciador está pronta para executar pré-rolagem do próximo segmento, ela envia um evento MENewPresentation cujos dados de evento são um ponteiro de interface IMFPresentationDescriptor. Novamente, obtenha a topologia do segmento chamando GetMediaSourceTopology na origem do sequenciador e defina a topologia na Sessão de Mídia chamando SetTopology. Não é necessário reiniciar a fonte de mídia. Ela será reproduzida automaticamente para o próximo segmento.
  7. Antes que o aplicativo seja encerrado, desligue a origem do sequenciador chamando IMFMediaSource::Shutdown.

O código a seguir mostra como obter a topologia e defini-la na Sessão de Mídia:

// Queues the next topology on the session.

HRESULT CPlaylist::QueueNextSegment(IMFPresentationDescriptor *pPD)
{
    IMFMediaSourceTopologyProvider *pTopoProvider = NULL;
    IMFTopology *pTopology = NULL;

    //Get the topology for the presentation descriptor
    HRESULT hr = m_pSequencerSource->QueryInterface(IID_PPV_ARGS(&pTopoProvider));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pTopoProvider->GetMediaSourceTopology(pPD, &pTopology);
    if (FAILED(hr))
    {
        goto done;
    }

    //Set the topology on the media session
    m_pSession->SetTopology(NULL, pTopology);

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

Para obter um exemplo de código completo, confira Código de exemplo da Origem do Sequencer.

Como adicionar topologias

A origem do sequenciador mantém duas listas de topologias: a lista de entrada e a lista de pré-rolagem.

A lista de entrada é uma coleção de topologias correspondentes aos segmentos de playlist, na ordem em que foram adicionados pelo aplicativo chamando IMFSequencerSource::AppendTopology. Esse método atribui a cada topologia um identificador de segmento exclusivo do tipo MFSequencerElementId. O identificador de segmento é definido como um atributo para todos os nós da topologia de origem. Um aplicativo pode obter o identificador de segmento de um nó de origem usando o atributo MF_TOPONODE_SEQUENCE_ELEMENTID. A lista de entrada pode ter topologias duplicadas se o aplicativo chamou AppendTopology na mesma topologia mais de uma vez. No entanto, elas são distinguidas por seus identificadores de segmento exclusivos.

A lista de pré-rolagem é uma coleção de topologias de lista de entrada que foram inicializadas em preparação para reprodução. Isso permite que a Sessão de Mídia faça uma transição para a próxima topologia sem problemas, quando a topologia ativa terminar. O aplicativo não pode adicionar nem remover as topologias diretamente da lista de pré-rolagem. Isso é gerado pela origem do sequenciador quando uma topologia da lista de entrada é selecionada para reprodução. Isso faz com que a origem do sequenciador adicione a próxima topologia da lista de entrada à lista de pré-rolagem. Depois de fazer isso, a origem do sequenciador gera de forma assíncrona o evento MENewPresentation e passa o descritor de apresentação para a topologia de pré-rolagem como dados de evento. O aplicativo deve escutar esse evento usando a interface IMFMediaEventGenerator da Sessão de Mídia e enfileirar a topologia de pré-rolagem na Sessão de Mídia chamando IMFMediaSession::SetTopology. Isso deve ser feito antes que a Sessão de Mídia conclua a reprodução da topologia ativa. SetTopology informa a Sessão de Mídia sobre a próxima topologia que ela deve reproduzir após o término da reprodução da topologia ativa. Para garantir uma transição sem problemas, o aplicativo deve chamar SetTopology antes que a Sessão de Mídia conclua a reprodução da topologia anterior. Caso contrário, haverá um intervalo entre os segmentos.

O evento MENewPresentation é gerado desde que haja uma topologia após a topologia ativa. Consequentemente, se a lista de entrada contiver apenas uma topologia ou se a topologia ativa for a última na lista de entrada, esse evento não será gerado.

A lista de pré-rolagem é sincronizada com a lista de entrada e atualizada sempre que uma topologia é adicionada ou excluída da lista de entrada.

Como excluir topologias

Para remover uma topologia da origem do sequenciador, um aplicativo deve chamar o método IMFSequencerSource::DeleteTopology e especificar o identificador de segmento.

Antes de chamar DeleteTopology, o aplicativo deve verificar se a Sessão de Mídia não está usando a topologia que o aplicativo deseja excluir. Para fazer isso, as ações a seguir devem ser realizadas antes que o aplicativo chame DeleteTopology:

  • O evento MESessionTopologyStatus com MF_TOPOSTATUS_ENDED é recebido na topologia para garantir que a Sessão de Mídia conclui a reprodução.

  • MESessionTopologyStatus com MF_TOPOSTATUS_STARTED_SOURCE é recebido para a próxima topologia para garantir que a Sessão de Mídia começou a reproduzir a próxima topologia, o evento MESessionEnded é recebido para garantir que a Sessão de Mídia seja concluída com a última topologia na origem do sequenciador.

Se o segmento que está sendo excluído for a topologia ativa, a reprodução será interrompida e a origem do sequenciador gerará o evento MEEndOfPresentationSegment. Se a topologia ativa também for a última topologia, o evento MEEndOfPresentation será gerado.

Como ignorar um segmento

Um aplicativo pode ir para um segmento específico na sequência iniciando a Sessão de Mídia com um deslocamento de segmento, da seguinte maneira:

  1. Chame a função MFCreateSequencerSegmentOffset para criar o deslocamento de segmento. Especifique o identificador do segmento no parâmetro dwId. (O identificador foi retornado pelo método IMFSequencerSource::AppendTopology quando você adicionou pela primeira vez a topologia à origem do sequenciador.) O parâmetro hnsOffset especifica um deslocamento de tempo em relação ao início do segmento. A reprodução será iniciada neste momento. Para o parâmetro pvarSegmentOffset, passe o endereço de um PROPVARIANT vazio. Quando a função retorna, esse PROPVARIANT contém o deslocamento de segmento.

  2. Chame o método IMFMediaSession::Start na Sessão de Mídia. Para o parâmetro pguidTimeFormat, use o valor de GUID MF_TIME_FORMAT_SEGMENT_OFFSET. Esse valor indica a busca pelo segmento de deslocamento. Para o parâmetro pvarStartPosition, passe o endereço do PROPVARIANT criado na etapa anterior.

O exemplo de código a seguir mostra como ir para o início de um segmento especificado em uma sequência.

// Skips to the specified segment in the sequencer source

HRESULT CPlaylist::SkipTo(DWORD index)
{
    if (index >= m_count)
    {
        return E_INVALIDARG;
    }

    MFSequencerElementId ID = m_segments[index].SegmentID;

    PROPVARIANT var;

    HRESULT hr = MFCreateSequencerSegmentOffset(ID, NULL, &var);
    
    if (SUCCEEDED(hr))
    {
        hr = m_pSession->Start(&MF_TIME_FORMAT_SEGMENT_OFFSET, &var);
        PropVariantClear(&var);
    }
    return hr;
}

Quando o aplicativo procura entre os segmentos, o aplicativo recebe vários eventos à medida que a origem do sequenciador termina o segmento atual e se prepara para reproduzir o novo segmento. Como esses eventos são recebidos de forma assíncrona, é difícil prever a sequência exata de eventos. Os requisitos são os seguintes:

Mais detalhes sobre os eventos enviados pela origem do sequenciador podem ser encontrados no tópico Eventos de origem do sequenciador.

Como criar uma playlist

Origem do Sequenciador