Paso 5. Transformación de la imagen

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

Este es el paso 5 del tutorial Escritura de filtros de transformación.

El filtro ascendente entrega ejemplos multimedia al filtro de transformación llamando al método IMemInputPin::Receive en el pin de entrada del filtro de transformación. Para procesar los datos, el filtro de transformación llama al método Transform , que es virtual puro. Las clases CTransformFilter y CTransInPlaceFilter usan dos versiones diferentes de este método:

  • CTransformFilter::Transform toma un puntero al ejemplo de entrada y un puntero al ejemplo de salida. Antes de que el filtro llame al método , copia las propiedades de ejemplo del ejemplo de entrada en el ejemplo de salida, incluidas las marcas de tiempo.
  • CTransInPlaceFilter::Transform toma un puntero al ejemplo de entrada. El filtro modifica los datos en su lugar.

Si el método Transform devuelve S_OK, el filtro entrega la muestra de bajada. Para omitir un marco, devuelva S_FALSE. Si se produce un error de streaming, devuelva un código de error.

En el ejemplo siguiente se muestra cómo el codificador RLE podría implementar este método. Su propia implementación puede diferir considerablemente, dependiendo de lo que haga el filtro.

HRESULT CRleFilter::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    // Get pointers to the underlying buffers.
    BYTE *pBufferIn, *pBufferOut;
    hr = pSource->GetPointer(&pBufferIn);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = pDest->GetPointer(&pBufferOut);
    if (FAILED(hr))
    {
        return hr;
    }
    // Process the data.
    DWORD cbDest = EncodeFrame(pBufferIn, pBufferOut);
    KASSERT((long)cbDest <= pDest->GetSize());

    pDest->SetActualDataLength(cbDest);
    pDest->SetSyncPoint(TRUE);
    return S_OK;
}

En este ejemplo se supone que EncodeFrame es un método privado que implementa la codificación RLE. El propio algoritmo de codificación no se describe aquí; para obtener más información, consulte el tema "Compresión de mapa de bits" en la documentación del SDK de plataforma.

En primer lugar, el ejemplo llama a IMediaSample::GetPointer para recuperar las direcciones de los búferes subyacentes. Pasa estos al método EncoderFrame privado. A continuación, llama a IMediaSample::SetActualDataLength para especificar la longitud de los datos codificados. El filtro de bajada necesita esta información para que pueda administrar el búfer correctamente. Por último, el método llama a IMediaSample::SetSyncPoint para establecer la marca de fotograma clave en TRUE. La codificación de longitud de ejecución no usa ningún fotograma delta, por lo que cada fotograma es un fotograma clave. Para fotogramas delta, establezca el valor en FALSE.

Otros problemas que debe tener en cuenta son:

  • Marcas de tiempo. La clase CTransformFilter marca de tiempo el ejemplo de salida antes de llamar al método Transform . Copia los valores de marca de tiempo del ejemplo de entrada, sin modificarlos. Si el filtro necesita cambiar las marcas de tiempo, llame a IMediaSample::SetTime en el ejemplo de salida.

  • Cambios de formato. El filtro ascendente puede cambiar formatos de flujo medio mediante la asociación de un tipo de medio al ejemplo. Antes de hacerlo, llama a IPin::QueryAccept en el pin de entrada del filtro. En la clase CTransformFilter , esto da como resultado una llamada a CheckInputType seguida de CheckTransform. El filtro de bajada también puede cambiar los tipos de medios mediante el mismo mecanismo. En su propio filtro, hay dos cosas para watch para:

    • Asegúrese de que QueryAccept no devuelve aceptaciones falsas.
    • Si el filtro acepta cambios de formato, compruebe si están dentro del método Transform llamando a IMediaSample::GetMediaType. Si ese método devuelve S_OK, el filtro debe responder al cambio de formato.

    Para obtener más información, vea Cambios de formato dinámico.

  • Subprocesos. En CTransformFilter y CTransInPlaceFilter, el filtro de transformación entrega muestras de salida de forma sincrónica dentro del método Receive . El filtro no crea ningún subproceso de trabajo para procesar los datos. Normalmente, no hay ninguna razón para que un filtro de transformación cree subprocesos de trabajo.

Siguiente: Paso 6. Agregue compatibilidad con COM.

Escribir filtros directShow