Compartir a través de


Uso de la plantilla de clase DMO

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

DirectShow incluye una plantilla de clase, IMediaObjectImpl, para implementar DMO. La plantilla controla muchas de las tareas de "contabilidad", como validar parámetros de entrada. Mediante el uso de la plantilla, puede centrarse en la funcionalidad específica de su DMO. Además, la plantilla ayuda a garantizar que se crea una implementación sólida. La plantilla se define en el archivo de encabezado Dmoimpl.h, que se encuentra en el directorio Include del SDK.

La plantilla IMediaObjectImpl hereda la interfaz IMediaObject . Para crear un DMO mediante la plantilla, defina una nueva clase que derive de IMediaObjectImpl. La plantilla implementa todos los métodos IMediaObject . En la mayoría de los casos, la plantilla llama a un método privado correspondiente en la clase derivada. La plantilla proporciona las siguientes características:

  • Comprobación básica de parámetros. Los métodos de plantilla comprueban que los parámetros necesarios no son NULL, que los índices de flujo están dentro del intervalo y que las marcas son válidas.
  • Bloqueo. Los métodos de plantilla llaman a dos métodos internos, Lock y Unlock, para serializar las operaciones en DMO. Esta característica garantiza que DMO es seguro para subprocesos.
  • Tipos de medios. La plantilla almacena los tipos de medios establecidos por el cliente y proporciona métodos de descriptor de acceso para los tipos de medios.
  • Streaming. La plantilla impide el streaming hasta que el cliente haya establecido tipos de medios para todas las secuencias no opcionales. También garantiza que se llame al método IMediaObject::AllocateStreamingResources antes de que comience el streaming, lo que garantiza que se asignan los recursos.

La clase derivada debe implementar la interfaz IUnknown ; la plantilla no proporciona esta interfaz. Puede usar la Biblioteca de plantillas activas (ATL) para implementar IUnknown o puede proporcionar alguna otra implementación. La plantilla tampoco implementa el mecanismo de bloqueo. La clase derivada debe implementar los métodos Lock y Unlock . Si crea la clase mediante ATL, puede usar las implementaciones de ATL predeterminadas.

Declarar la clase derivada

La plantilla de clase IMediaObjectImpl se declara de la siguiente manera:

template <class _DERIVED_, int NUMBEROFINPUTS, int NUMBEROFOUTPUTS>
class IMediaObjectImpl : public ImediaObject

Los tres parámetros de plantilla son _DERIVED_, NUMBEROFINPUTS y NUMBEROFOUTPUTS. Establezca _DERIVED_ igual al nombre de la clase. Los otros dos parámetros definen el número de flujos de entrada y flujos de salida en DMO. Por ejemplo, para crear una clase DMO denominada CMyDmo que admita un flujo de entrada y dos flujos de salida, use la siguiente declaración:

class CMyDmo : public IMediaObjectImpl<CMyDmo, 1, 2>

En el resto de esta sección se describe cómo implementa la plantilla los distintos métodos en IMediaObject.

Métodos para establecer tipos de medios

Los métodos siguientes establecen o recuperan tipos de medios en DMO:

  • GetInputType, GetOutputType. Estos métodos devuelven tipos de medios preferidos, por número de secuencia e índice de tipo. La plantilla llama a InternalGetInputType o InternalGetOutputType en la clase derivada.
  • SetInputType, SetOutputType. Estos métodos establecen el tipo de medio en una secuencia, prueban un tipo de medio o borran un tipo de medio. Para validar el tipo de medio, la plantilla llama a InternalCheckInputType o InternalCheckOutputType en la clase derivada. La clase derivada devuelve S_OK para aceptar el tipo o DMO_E_INVALIDTYPE para rechazar el tipo. La plantilla controla la configuración o desactiva el tipo de medio.
  • GetInputCurrentType, GetOutputCurrentType. Estos métodos devuelven el tipo de medio actual para una secuencia o DMO_E_TYPE_NOT_SET si no se establece ningún tipo. La plantilla implementa completamente estos métodos.

Métodos informativos

Los métodos siguientes proporcionan información sobre DMO.

  • GetInputMaxLatency, SetInputMaxLatency. Estos métodos recuperan o establecen la latencia máxima. La plantilla llama a InternalGetInputMaxLatency o InternalSetInputMaxLatency en la clase derivada.
  • GetInputSizeInfo, GetOutputSizeInfo. Estos métodos devuelven los requisitos de búfer de DMO para una secuencia especificada. Si no se ha establecido ningún tipo de medio en esa secuencia, la plantilla devuelve DMO_E_TYPE_NOT_SET. De lo contrario, llama a InternalGetInputSizeInfo o InternalGetOutputSizeInfo en la clase derivada.
  • GetInputStreamInfo, GetOutputStreamInfo. Estos métodos devuelven varias marcas que indican cómo el cliente debe dar formato a los datos. La plantilla llama a InternalGetInputStreamInfo o InternalGetOutputStreamInfo en la clase derivada.
  • GetStreamCount. Este método devuelve el número de flujos de entrada y salida. La plantilla implementa este método mediante los parámetros de plantilla.

Métodos para la asignación de recursos

  • El método AllocateStreamingResources asigna los recursos que necesita DMO antes de que comience el streaming. El método FreeStreamingResources libera los mismos recursos. La plantilla llama a InternalAllocateStreamingResources y InternalFreeStreamingResources, respectivamente.

El cliente de DMO no es necesario para llamar a estos métodos, pero la plantilla llama automáticamente a AllocateStreamingResources antes de que se inicie el streaming. Por lo tanto, el DMO puede suponer que los recursos se han asignado correctamente en el momento en que se llama a ProcessInput . El DMO debe llamar a FreeStreamingResources en su destructor.

Además, cuando la plantilla llama a InternalAllocateStreamingResources, establece una marca interna para que no llame de nuevo a ese método hasta que llame a InternalFreeStreamingResources. Esto garantiza que los recursos no se vuelvan a asignar accidentalmente, lo que podría provocar pérdidas de memoria.

Métodos para streaming

Los métodos siguientes se usan para transmitir datos:

  • GetInputStatus. Este método indica si el DMO puede aceptar la entrada en este momento. La plantilla llama a InternalAcceptingInput en la clase derivada. Si DMO puede aceptar la entrada, la clase derivada devuelve S_OK y la plantilla establece el bit DMO_INPUT_STATUSF_ACCEPT_DATA en el parámetro dwFlags . De lo contrario, la clase derivada devuelve S_FALSE y la plantilla establece dwFlags en cero.
  • ProcessInput. Este método procesa un búfer de entrada. La plantilla llama a AllocateStreamingResources, descrita anteriormente. A continuación, llama a InternalAcceptingInput en la clase derivada. Si DMO puede aceptar una nueva entrada, la plantilla llama a InternalProcessInput.
  • ProcessOutput. Este método procesa un conjunto de búferes de salida, un búfer para cada flujo de salida. La plantilla llama a AllocateStreamingResources y, a continuación, InternalProcessOutput.
  • Discontinuidad. Este método señala una discontinuidad en un flujo de entrada. La plantilla llama a InternalAcceptingInput en la clase derivada. Si ese método devuelve S_OK, la plantilla llama a InternalDiscontinuity en la clase derivada.
  • Vaciado. Este método vacía el DMO. La plantilla llama a InternalFlush en la clase derivada. El DMO debe descartar los búferes de entrada que todavía contiene para su procesamiento.

La plantilla no proporciona compatibilidad directa con la interfaz IMediaObjectInPlace .

Métodos para bloquear

El bloqueo se usa para proteger el estado de DMO en un entorno multiproceso. En un proyecto ATL, el método IMediaObject::Lock produce un conflicto de nombre con el método Lock ATL. Para resolver el conflicto, la plantilla cambia el nombre del método IMediaObject a DMOLock. Al compilar la clase derivada, defina FIX_LOCK_NAME antes de incluir el archivo de encabezado Dmo.h:

#define FIX_LOCK_NAME
#include <dmo.h>

Esta directiva hace que el preprocesador sustituya DMOLock por Lock en la declaración de la interfaz IMediaObject . Las aplicaciones todavía pueden invocar el método con el nombre Lock, porque el orden de la tabla virtual no cambia. El método DMOLock llama a Lock o Unlock en la clase derivada. Si usa ATL para implementar la clase derivada, estos métodos ya están definidos por ATL, por lo que no es necesario ningún código adicional. Si no usa ATL, debe proporcionar métodos Lock y Unlock en la clase derivada.

La plantilla bloquea automáticamente el DMO en cada uno de los métodos IMediaObject . Es posible que la clase derivada tenga que bloquear el DMO dentro de otros métodos públicos que implementa (por ejemplo, si admite IMediaObjectInPlace). La plantilla de clase también proporciona una clase auxiliar interna, IMediaObjectImpl::LockIt, que es útil para bloquear y desbloquear el DMO.

Resumen

Para los métodos IMediaObject siguientes, la plantilla llama a un método correspondiente con la misma firma en la clase derivada. La clase derivada debe implementar cada uno de los métodos que se muestran en la segunda columna.

IMediaObject (método) Método de clase derivada
AllocateStreamingResources InternalAllocateStreamingResources
Discontinuidad InternalDiscontinuity
Vaciar InternalFlush
FreeStreamingResources InternalFreeStreamingResources
GetInputMaxLatency InternalGetInputMaxLatency
GetInputSizeInfo InternalGetInputSizeInfo
GetInputStreamInfo InternalGetInputStreamInfo
GetInputType InternalGetInputType
GetOutputSizeInfo InternalGetOutputSizeInfo
GetOutputStreamInfo InternalGetOutputStreamInfo
GetOutputType InternalGetOutputType
ProcessInput InternalProcessInput
ProcessOutput InternalProcessOutput
SetInputMaxLatency InternalSetInputMaxLatency

 

Para los métodos IMediaObject restantes, no hay una correspondencia uno a uno entre los métodos de plantilla y los métodos de clase derivada. En la tabla siguiente se resumen los métodos que la plantilla implementa por completo y qué métodos llaman a otros métodos en la clase derivada.

IMediaObject (método) Método de clase derivada
GetInputCurrentType Totalmente implementado
GetOutputCurrentType Totalmente implementado
GetStreamCount Totalmente implementado
GetInputStatus InternalAcceptingInput
Bloqueo (implementado como DMOLock) Bloquear, desbloquear
SetInputType InternalCheckInputType
SetOutputType InternalCheckOutputType

 

Plantilla de clase IMediaObjectImpl

Escritura de un DMO