Filtrar Estados
[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEnginee Audio/Video Capture na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Audio/Video Capture no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]
Os filtros têm três estados possíveis: interrompidos, pausados e em execução. A finalidade do estado pausado é indicar dados no grafo para que um comando de execução responda imediatamente. O Gerenciador de Grafo de Filtro controla todas as transições de estado. Quando um aplicativo chama IMediaControl::Run, IMediaControl::P auseou IMediaControl::Stop, o Gerenciador de Grafo de Filtro chama o métodoIMediaFiltercorrespondente em todos os filtros. As transições entre parada e execução sempre passam pelo estado pausado, portanto, se o aplicativo chama Executar em um grafo parado, o Gerenciador do Grafo de 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 > de transformação de > de origem
Suponha, por enquanto, que o filtro de origem não é 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 "envia por push" os exemplos downstream chamando IMemInputPin::Receive no pin 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 ele 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 Receber ou IMemAllocator::GetBuffer. No entanto, nenhum dado é perdido. Depois que o thread de origem é desbloqueado, ele simplesmente é retomado do ponto em que ele foi 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 exemplos. Primeiro, ele renderiza o exemplo que manteve enquanto estava em pausa. Em seguida, cada vez que ele recebe um novo exemplo, ele calcula o tempo de apresentação do exemplo. (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 a 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 amostras enquanto pausa, somente durante a execução. Para sinalizar esse fato para o Gerenciador do Filter Graph, 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, mesmo que o renderizador não tenha recebido dados.
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 Grafo 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 amostras sejam descartadas e impedir que o grafo seja deadlocking. As transições de estado mais cruciais estão entre pausadas e interrompidas:
- Parado para pausado: à medida que cada filtro pausa, ele fica pronto para receber amostras do próximo filtro. O filtro de origem é o último a pausar. 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 Gerenciador de Grafo de Filtro 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 ele contém, o que desbloqueia todos os filtros upstream aguardando em GetBuffer. Se o filtro estiver aguardando um recurso dentro do método Receive, ele interromperá a espera e retornará do Receive, que desbloqueia o filtro de chamada. Portanto, quando o Gerenciador do Grafo de Filtro interrompe o próximo filtro upstream, esse filtro não é bloqueado em GetBuffer ou Receivee 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.
Tópicos relacionados
-
fluxo de dados no de grafo de filtro