Compartir a través de


Cómo escribir un filtro de origen para DirectShow

[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.

En este tema se describe cómo escribir un filtro de origen personalizado para DirectShow.

Nota:

En este tema solo se describen los orígenes de inserción; no describe los orígenes de extracción, como el filtro de lector asincrónico o los filtros divisores que se conectan a orígenes de extracción. Para obtener la distinción entre los orígenes de inserción y extracción, consulte Data Flow para desarrolladores de filtros.

El modelo de streaming de DirectShow

Al escribir un filtro de origen, es importante comprender que un origen de inserción no es lo mismo que un origen activo. Un origen en directo obtiene datos de algún origen externo, como una cámara o una secuencia de red. Por lo general, un origen activo no puede controlar la velocidad de entrada de los datos. Si los filtros de bajada no consumen los datos lo suficientemente rápido, el origen tendrá que quitar muestras.

Sin embargo, un origen de inserción no tiene que ser un origen activo. Por ejemplo, un origen de inserción puede leer datos de un archivo local. En ese caso, los filtros del representador de bajada determinan la rapidez con la que consumen los datos del origen, en función del reloj de referencia y de las marcas de tiempo de ejemplo. El filtro de origen entrega muestras lo antes posible, pero el flujo de datos real está limitado por los representadores. Los mecanismos para la asignación del flujo de datos se describen en Data Flow para desarrolladores de filtros.

Cada pin de salida del filtro de origen crea un subproceso denominado subproceso de streaming. El pin entrega ejemplos en el subproceso de streaming. Normalmente, todas las descodificación, procesamiento y representación se producen en este subproceso, aunque algunos filtros de bajada podrían crear subprocesos adicionales para poner en cola sus ejemplos de salida.

El subproceso de streaming ejecuta un bucle con la estructura siguiente:

until (stopped)
  1. Get a media sample from the allocator.
  2. Fill the sample with data.
  3. Time stamp the sample. 
  4. Deliver the sample downstream.

Si no hay ejemplos disponibles, el paso 1 se bloquea hasta que un ejemplo esté disponible. El paso 4 también puede bloquearse; por ejemplo, puede bloquear mientras el grafo está en pausa.

El bucle se ejecuta lo más rápido posible, pero está limitado por la rapidez con la que el filtro del representador representa cada ejemplo. Suponiendo que el gráfico de filtros tiene un reloj de referencia, la velocidad viene determinada por los tiempos de presentación de los ejemplos. Si no hay ningún reloj de referencia, el representador consume muestras lo más rápido posible.

Uso de CSource y CSourceStream

Las clases base directShow incluyen dos clases que admiten orígenes de inserción: CSource y CSourceStream.

Pines de salida

Un filtro de origen puede tener más de un pin de salida. En el método de constructor del filtro, cree uno o varios pines derivados de CSourceStream (un pin por secuencia de salida). No es necesario almacenar punteros a las patillas; las patillas se agregan automáticamente al filtro cuando se crean.

Formatos de salida

El pin de salida controla la negociación de formato con los siguientes métodos de CSourceStream :

Método Descripción
GetMediaType Obtiene un tipo de medio del pin de salida.
El pin debe proponer al menos un tipo de medio, ya que el filtro de bajada podría no proponer ningún tipo. En la mayoría de los casos, el filtro de bajada será un descodificador o un representador, en función de si el filtro de origen entrega datos comprimidos o sin comprimir. Normalmente, un filtro de representador requiere un tipo multimedia completo, que contiene toda la información de formato necesaria para representar la secuencia. Para un descodificador, la cantidad de información necesaria en el tipo de medio depende mucho del formato de codificación.
CheckMediaType Comprueba si el pin de salida acepta un tipo de medio determinado. La invalidación de este método es opcional, en función de cómo implemente GetMediaType.

El método GetMediaType está sobrecargado:

Si el pin de salida del filtro de origen admite exactamente un formato multimedia, debe invalidar (1) para inicializar el objeto CMediaType con ese formato. Deje la implementación predeterminada de (2) y deje también la implementación predeterminada de CheckMediaType.

Si el pin admite más de un formato, invalide (2). Inicialice el objeto CMediaType según el valor de la variable de índice. El pin debe devolver los formatos como una lista ordenada. En este caso, también debe invalidar CheckMediaType para comprobar el tipo de medio en la lista de formatos.

En el caso de los formatos de vídeo sin comprimir, recuerde que el filtro de bajada puede proponer formatos con varios valores de paso. El filtro debe aceptar cualquier valor de intervalo válido. Para obtener más información, vea BITMAPINFOHEADER.

También debe invalidar el método pure-virtual CBaseOutputPin::D ecideBufferSize . Use este método para establecer el tamaño de los búferes de ejemplo.

Streaming

La clase CSourceStream crea el subproceso de streaming para el pin. El procedimiento de subproceso se implementa en el método CSourceStream::D oBufferProcessingLoop . Este método llama al método CSourceStream::FillBuffer puro virtual, que la clase derivada debe invalidar. Este método es donde el pin rellena el búfer con datos. Por ejemplo, si el filtro entrega vídeo sin comprimir, aquí es donde dibujaría los fotogramas de vídeo.

La clase base inicia y detiene automáticamente el bucle de subproceso en los momentos correctos, cuando el filtro se detiene o se detiene. Cuando esto sucede, la clase CSourceStream llama a algunos métodos para notificar a la clase derivada:

Puede invalidar estos métodos si necesita agregar cualquier control especial. De lo contrario, las implementaciones predeterminadas simplemente devuelven S_OK.

Buscando

Si tiene un filtro de origen con un pin de salida, puede usar la clase CSourceSeeking como punto de partida para implementar la búsqueda. Hereda la clase pin de CSourceStream y CSourceSeeking.

Nota:

CSourceSeeking no se recomienda para un filtro con más de un pin de salida. El problema principal es que solo un pin debe responder a las solicitudes de búsqueda. Normalmente, esto requiere la comunicación entre los patillas y el filtro.

La clase CSourceSeeking administra la velocidad de reproducción, la hora de inicio, la hora de detención y la duración. La clase derivada debe establecer el tiempo de detención inicial y la duración. Cada vez que uno de estos valores cambia, se llama al método CSourceSeeking::ChangeRate, CSourceSeeking::ChangeStart o CSourceSeeking::ChangeStop , según corresponda. Los métodos son todos métodos virtuales puros. La clase pin derivada invalida estos métodos para hacer lo siguiente:

  1. Llame a IPin::BeginFlush en la patilla de bajada. Esto hace que los filtros de nivel inferior liberen muestras que contienen y rechazan nuevas muestras.
  2. Llame a CSourceStream::Stop para detener el subproceso de streaming. El filtro de origen suspende la generación de nuevos datos.
  3. Llame a IPin::EndFlush en la patilla de bajada. Esto indica que los filtros de bajada acepten nuevos datos.
  4. Llame a IPin::NewSegment con las nuevas horas de inicio y detención y frecuencia.
  5. Establezca la propiedad discontinuidad en el ejemplo siguiente.

Para obtener más información, consulte Compatibilidad con la búsqueda en un filtro de origen.

Si el filtro admite la búsqueda, la posición de la secuencia ahora es independiente del tiempo de presentación. Después de una búsqueda, las marcas de tiempo se restablecen a cero. La fórmula general para las marcas de tiempo es:

  • hora de inicio de ejemplo = tiempo transcurrido/velocidad de reproducción
  • hora de finalización de ejemplo = hora de inicio de ejemplo + (tiempo por fotograma/velocidad de reproducción)

donde ha transcurrido el tiempo es el tiempo transcurrido desde que el filtro comenzó a ejecutarse o desde el último comando seek.

Formatos de hora para buscar

De forma predeterminada, los comandos seek se encuentran en unidades de 100 nanosegundos. El filtro de origen puede admitir formatos de tiempo adicionales, como buscar por número de fotograma. Cada formato de hora se identifica mediante un GUID; consulte GUID de formato de hora.

Para admitir formatos de tiempo adicionales, debe implementar los métodos siguientes en el pin de salida:

Si la aplicación establece un nuevo formato de hora, todos los parámetros de posición de los métodos IMediaSeeking se interpretan en términos del nuevo formato de hora. Por ejemplo, si el formato de hora es fotogramas, el método IMediaSeeking::GetDuration debe devolver la duración en fotogramas.

En la práctica, algunos filtros directShow admiten formatos de tiempo adicionales y, como resultado, algunas aplicaciones directShow usan esta funcionalidad.

Escribir filtros de origen