Filtrar Estados

Os filtros têm três estados possíveis: interrompidos, pausados e em execução. A finalidade do estado pausado é sinalizar dados no grafo para que um comando de execução responda imediatamente. O Filter Graph Manager controla todas as transições de estado. Quando um aplicativo chama IMediaControl::Run, IMediaControl::P ause ou IMediaControl::Stop, o Filter Graph Manager chama o método IMediaFilter correspondente em todos os filtros. As transições entre parada e execução sempre passam pelo estado em pausa, portanto, se o aplicativo chama Executar em um grafo parado, o Gerenciador de Graph filtro pausa o grafo antes de executá-lo.

Para a maioria dos filtros, os estados em execução e pausados são idênticos. Considere o seguinte grafo de filtro:

Renderizador de Transformação > de Origem >

Suponha, por enquanto, que o filtro de origem não seja uma fonte de captura dinâmica. Quando o filtro de origem é pausado, ele cria um thread que gera novos dados e os grava em exemplos de mídia o mais rápido possível. O thread "empurra" os exemplos downstream chamando IMemInputPin::Receive no pino de entrada do filtro de transformação. O filtro de transformação recebe os exemplos no thread do filtro de origem. Ele pode usar um thread de trabalho para entregar os exemplos ao renderizador, mas normalmente os entrega no mesmo thread. Enquanto o renderizador está em pausa, ele aguarda para receber uma amostra. Depois de receber um, ele bloqueia e mantém esse exemplo indefinidamente. Se for um renderizador de vídeo, ele exibirá o exemplo como uma imagem de pôster, repintando a imagem conforme necessário.

Neste ponto, o fluxo está totalmente preparado e pronto para renderização. Se o grafo permanecer em pausa, os exemplos serão "acumulados" no grafo por trás do primeiro exemplo, até que cada filtro seja bloqueado em Receive ou IMemAllocator::GetBuffer. No entanto, nenhum dado é perdido. Depois que o thread de origem é desbloqueado, ele simplesmente retoma do ponto em que ele é bloqueado.

O filtro de origem e o filtro de transformação ignoram a transição da pausa para a execução, elas simplesmente continuam a processar dados o mais rápido possível. Mas quando o renderizador é executado, ele começa a renderizar amostras. Primeiro, ele renderiza o exemplo que mantinha enquanto estava em pausa. Em seguida, cada vez que recebe um novo exemplo, ele calcula o tempo de apresentação da amostra. (Para obter detalhes, consulte Hora e Relógios no DirectShow.) O renderizador mantém cada exemplo até a hora da apresentação, momento em que renderiza o exemplo. Enquanto aguarda o tempo de apresentação, ele bloqueia o método Receive ou recebe novos exemplos em um thread de trabalho com uma fila. Os filtros upstream do renderizador não estão envolvidos no agendamento.

Fontes dinâmicas, como dispositivos de captura, são uma exceção para essa arquitetura geral. Com uma fonte dinâmica, não é apropriado sinalizar dados com antecedência. O aplicativo pode pausar o grafo e aguardar muito tempo antes de executá-lo. O grafo não deve renderizar exemplos "obsoletos". Portanto, uma fonte dinâmica não produz exemplos enquanto está em pausa, somente durante a execução. Para sinalizar esse fato para o Filter Graph Manager, o método IMediaFilter::GetState do filtro de origem retorna VFW_S_CANT_CUE. Esse código de retorno indica que o filtro mudou para o estado em pausa, embora o renderizador não tenha recebido nenhum dado.

Quando um filtro é interrompido, ele rejeita mais amostras entregues a ele. Os filtros de origem desligam seus threads de streaming e outros filtros desligam os threads de trabalho que podem ter criado. Os pinos descompromissam seus alocadores.

Transições de estado

O Gerenciador de Graph de Filtro executa todas as transições de estado na ordem upstream, começando do renderizador e trabalhando para trás para o filtro de origem. Essa ordenação é necessária para impedir que exemplos sejam descartados e impedir que o grafo seja deadlocking. As transições de estado mais cruciais estão entre pausadas e interrompidas:

  • Parado para pausar: à medida que cada filtro pausa, ele fica pronto para receber amostras do próximo filtro. O filtro de origem é o último a ser pausado. Ele cria o thread de streaming e começa a fornecer exemplos. Como todos os filtros downstream estão em pausa, nenhum filtro rejeita nenhum exemplo. O Filter Graph Manager não conclui a transição até que cada renderizador no grafo tenha recebido uma amostra (com exceção de fontes dinâmicas, conforme descrito anteriormente).
  • Pausado para parar: quando um filtro é interrompido, ele libera todos os exemplos que contém, o que desbloqueia todos os filtros upstream aguardando no GetBuffer. Se o filtro estiver aguardando um recurso dentro do método Receive , ele interromperá a espera e retornará de Receive, o que desbloqueia o filtro de chamada. Portanto, quando o Gerenciador de Graph de Filtro para o próximo filtro upstream, esse filtro não é bloqueado no GetBuffer ou no Receive e pode responder ao comando stop. O filtro upstream pode fornecer alguns exemplos extras antes de obter o comando stop, mas o filtro downstream simplesmente os rejeita, porque ele já parou.

Fluxo de Dados na Graph de Filtro