Usando o modelo de classe DMO
[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEngine e Audio/Video Capture in 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 in 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.]
O DirectShow inclui um modelo de classe, IMediaObjectImpl, para implementar DMOs. O modelo lida com muitas das tarefas de "contabilidade", como validar parâmetros de entrada. Usando o modelo, você pode se concentrar na funcionalidade específica do seu DMO. Além disso, o modelo ajuda a garantir que você crie uma implementação robusta. O modelo é definido no arquivo de cabeçalho Dmoimpl.h, localizado no diretório Incluir do SDK.
O modelo IMediaObjectImpl herda a interface IMediaObject . Para criar um DMO usando o modelo, defina uma nova classe derivada de IMediaObjectImpl. O modelo implementa todos os métodos IMediaObject . Na maioria dos casos, o modelo chama um método privado correspondente na classe derivada. O modelo fornece os seguintes recursos:
- Verificação básica de parâmetros. Os métodos de modelo verificam se os parâmetros necessários não são NULL, se os índices de fluxo estão dentro do intervalo e se os sinalizadores são válidos.
- Bloqueio. Os métodos de modelo chamam dois métodos internos, Lock e Unlock, para serializar operações no DMO. Esse recurso garante que o DMO seja thread-safe.
- Tipos de mídia. O modelo armazena os tipos de mídia definidos pelo cliente e fornece métodos de acessador para os tipos de mídia.
- Streaming. O modelo impede o streaming até que o cliente tenha definido tipos de mídia para todos os fluxos não opcionais. Ele também garante que o método IMediaObject::AllocateStreamingResources seja chamado antes do início do streaming, o que garante que os recursos sejam alocados.
A classe derivada deve implementar a interface IUnknown ; o modelo não fornece essa interface. Você pode usar a ATL (Biblioteca de Modelos Ativos) para implementar o IUnknown ou pode fornecer alguma outra implementação. O modelo também não implementa o mecanismo de bloqueio. A classe derivada deve implementar os métodos Lock e Unlock . Se você criar sua classe usando a ATL, poderá usar as implementações de ATL padrão.
Declarando a classe derivada
O modelo de classe IMediaObjectImpl é declarado da seguinte maneira:
template <class _DERIVED_, int NUMBEROFINPUTS, int NUMBEROFOUTPUTS>
class IMediaObjectImpl : public ImediaObject
Os três parâmetros de modelo são _DERIVED_, NUMBEROFINPUTS e NUMBEROFOUTPUTS. Defina _DERIVED_ igual ao nome da sua classe. Os outros dois parâmetros definem o número de fluxos de entrada e fluxos de saída no DMO. Por exemplo, para criar uma classe DMO chamada CMyDmo que dá suporte a um fluxo de entrada e dois fluxos de saída, use a seguinte declaração:
class CMyDmo : public IMediaObjectImpl<CMyDmo, 1, 2>
O restante desta seção descreve como o modelo implementa os vários métodos no IMediaObject.
Métodos para definir tipos de mídia
Os seguintes métodos definem ou recuperam tipos de mídia no DMO:
- GetInputType, GetOutputType. Esses métodos retornam tipos de mídia preferenciais, por número de fluxo e índice de tipo. O modelo chama InternalGetInputType ou InternalGetOutputType na classe derivada.
- SetInputType, SetOutputType. Esses métodos definem o tipo de mídia em um fluxo, testam um tipo de mídia ou limpam um tipo de mídia. Para validar o tipo de mídia, o modelo chama InternalCheckInputType ou InternalCheckOutputType na classe derivada. A classe derivada retorna S_OK para aceitar o tipo ou DMO_E_INVALIDTYPE para rejeitar o tipo. O modelo manipula a configuração ou a limpeza do tipo de mídia.
- GetInputCurrentType, GetOutputCurrentType. Esses métodos retornam o tipo de mídia atual para um fluxo ou DMO_E_TYPE_NOT_SET se nenhum tipo estiver definido. O modelo implementa completamente esses métodos.
Métodos informativos
Os métodos a seguir fornecem informações sobre o DMO.
- GetInputMaxLatency, SetInputMaxLatency. Esses métodos recuperam ou definem a latência máxima. O modelo chama InternalGetInputMaxLatency ou InternalSetInputMaxLatency na classe derivada.
- GetInputSizeInfo, GetOutputSizeInfo. Esses métodos retornam os requisitos de buffer do DMO para um fluxo especificado. Se nenhum tipo de mídia tiver sido definido nesse fluxo, o modelo retornará DMO_E_TYPE_NOT_SET. Caso contrário, ele chamará InternalGetInputSizeInfo ou InternalGetOutputSizeInfo na classe derivada.
- GetInputStreamInfo, GetOutputStreamInfo. Esses métodos retornam vários sinalizadores que indicam como o cliente deve formatar os dados. O modelo chama InternalGetInputStreamInfo ou InternalGetOutputStreamInfo na classe derivada.
- GetStreamCount. Esse método retorna o número de fluxos de entrada e saída. O modelo implementa esse método usando os parâmetros de modelo.
Métodos para alocação de recursos
- O método AllocateStreamingResources aloca todos os recursos que o DMO precisa antes do início do streaming. O método FreeStreamingResources libera os mesmos recursos. O modelo chama InternalAllocateStreamingResources e InternalFreeStreamingResources, respectivamente.
O cliente do DMO não é necessário para chamar esses métodos, mas o modelo chama automaticamente AllocateStreamingResources antes do início do streaming. Portanto, o DMO pode assumir que os recursos foram alocados corretamente no momento em que ProcessInput é chamado. O DMO deve chamar FreeStreamingResources em seu destruidor.
Além disso, quando o modelo chama InternalAllocateStreamingResources, ele define um sinalizador interno, para que ele não chame esse método novamente até chamar InternalFreeStreamingResources. Isso garante que os recursos não sejam realocados acidentalmente, o que pode causar vazamentos de memória.
Métodos para streaming
Os métodos a seguir são usados para transmitir dados:
- GetInputStatus. Esse método indica se o DMO pode aceitar a entrada no momento. O modelo chama InternalAcceptingInput na classe derivada. Se o DMO puder aceitar a entrada, a classe derivada retornará S_OK e o modelo definirá o DMO_INPUT_STATUSF_ACCEPT_DATA bit no parâmetro dwFlags . Caso contrário, a classe derivada retornará S_FALSE e o modelo definirá dwFlags como zero.
- ProcessInput. Esse método processa um buffer de entrada. O modelo chama AllocateStreamingResources, descrito anteriormente. Em seguida, ele chama InternalAcceptingInput na classe derivada. Se o DMO puder aceitar novas entradas, o modelo chamará InternalProcessInput.
- ProcessOutput. Esse método processa um conjunto de buffers de saída, um buffer para cada fluxo de saída. O modelo chama AllocateStreamingResources e, em seguida, InternalProcessOutput.
- Descontinuidade. Esse método sinaliza uma descontinuidade em um fluxo de entrada. O modelo chama InternalAcceptingInput na classe derivada. Se esse método retornar S_OK, o modelo chamará InternalDiscontinuity na classe derivada.
- Liberação. Esse método libera o DMO. O modelo chama InternalFlush na classe derivada. O DMO deve descartar todos os buffers de entrada que ele ainda mantém para serem processados.
O modelo não fornece suporte direto para a interface IMediaObjectInPlace .
Métodos para bloqueio
O bloqueio é usado para proteger o estado do DMO em um ambiente multithread. Em um projeto da ATL, o método IMediaObject::Lock causa um conflito de nome com o método ATL Lock . Para resolve o conflito, o modelo renomeia o método IMediaObject para DMOLock. Ao compilar a classe derivada, defina FIX_LOCK_NAME antes de incluir o arquivo de cabeçalho Dmo.h:
#define FIX_LOCK_NAME
#include <dmo.h>
Essa diretiva faz com que o pré-processador substitua DMOLock por Lock na declaração da interface IMediaObject . Os aplicativos ainda podem invocar o método usando o nome Lock, pois a ordem da vtable não é alterada. O método DMOLock chama Lock ou Unlock na classe derivada. Se você estiver usando a ATL para implementar a classe derivada, esses métodos já serão definidos pela ATL, portanto, nenhum código adicional será necessário. Se você não estiver usando a ATL, deverá fornecer métodos Lock e Unlock em sua classe derivada.
O modelo bloqueia automaticamente o DMO em cada um dos métodos IMediaObject . A classe derivada pode precisar bloquear o DMO dentro de outros métodos públicos que ela implementa (por exemplo, se for compatível com IMediaObjectInPlace). O modelo de classe também fornece uma classe auxiliar interna, IMediaObjectImpl::LockIt, que é útil para bloquear e desbloquear o DMO.
Resumo
Para os métodos IMediaObject a seguir, o modelo chama um método correspondente com a mesma assinatura na classe derivada. A classe derivada deve implementar cada um dos métodos mostrados na segunda coluna.
Método IMediaObject | Método de classe derivada |
---|---|
Allocatestreamingresources | InternalAllocateStreamingResources |
Descontinuidade | InternalDiscontinuity |
Liberar | InternalFlush |
FreeStreamingResources | InternalFreeStreamingResources |
GetInputMaxLatency | InternalGetInputMaxLatency |
GetInputSizeInfo | InternalGetInputSizeInfo |
GetInputStreamInfo | InternalGetInputStreamInfo |
GetInputType | InternalGetInputType |
GetOutputSizeInfo | InternalGetOutputSizeInfo |
GetOutputStreamInfo | InternalGetOutputStreamInfo |
Getoutputtype | InternalGetOutputType |
ProcessInput | InternalProcessInput |
Processoutput | InternalProcessOutput |
SetInputMaxLatency | InternalSetInputMaxLatency |
Para os métodos IMediaObject restantes, não há uma correspondência um-para-um entre métodos de modelo e métodos de classe derivada. A tabela a seguir resume quais métodos são totalmente implementados pelo modelo e quais métodos chamam outros métodos na classe derivada.
Método IMediaObject | Método de classe derivada |
---|---|
GetInputCurrentType | Totalmente implementado |
GetOutputCurrentType | Totalmente implementado |
GetStreamCount | Totalmente implementado |
GetInputStatus | InternalAcceptingInput |
Bloqueio (implementado como DMOLock) | Bloquear, Desbloquear |
Setinputtype | InternalCheckInputType |
Setoutputtype | InternalCheckOutputType |
Tópicos relacionados