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

 

Modelo de classe IMediaObjectImpl

Escrevendo um DMO