Compartilhar via


Etapa 5. Transformar a imagem

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

Esta é a etapa 5 do tutorial Escrevendo filtros de transformação.

O filtro upstream fornece exemplos de mídia para o filtro de transformação chamando o método IMemInputPin::Receive no pin de entrada do filtro de transformação. Para processar os dados, o filtro de transformação chama o método Transform , que é virtual puro. As classes CTransformFilter e CTransInPlaceFilter usam duas versões diferentes deste método:

  • CTransformFilter::Transform usa um ponteiro para o exemplo de entrada e um ponteiro para o exemplo de saída. Antes que o filtro chame o método , ele copia as propriedades de exemplo do exemplo de entrada para o exemplo de saída, incluindo os carimbos de data/hora.
  • CTransInPlaceFilter::Transform usa um ponteiro para o exemplo de entrada. O filtro modifica os dados em vigor.

Se o método Transform retornar S_OK, o filtro fornecerá o exemplo downstream. Para ignorar um quadro, retorne S_FALSE. Se houver um erro de streaming, retorne um código de falha.

O exemplo a seguir mostra como o codificador RLE pode implementar esse método. Sua própria implementação pode ser consideravelmente diferente, dependendo do que o filtro faz.

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;
}

Este exemplo pressupõe que EncodeFrame é um método privado que implementa a codificação RLE. O algoritmo de codificação em si não é descrito aqui; para obter detalhes, consulte o tópico "Compactação de bitmap" na documentação do SDK da plataforma.

Primeiro, o exemplo chama IMediaSample::GetPointer para recuperar os endereços dos buffers subjacentes. Ele os passa para o método EncoderFrame privado. Em seguida, ele chama IMediaSample::SetActualDataLength para especificar o comprimento dos dados codificados. O filtro downstream precisa dessas informações para que possa gerenciar o buffer corretamente. Por fim, o método chama IMediaSample::SetSyncPoint para definir o sinalizador de quadro-chave como TRUE. A codificação de comprimento de execução não usa quadros delta, portanto, cada quadro é um quadro-chave. Para quadros delta, defina o valor como FALSE.

Outros problemas que você deve considerar incluem:

  • Carimbos de data/hora. A classe CTransformFilter carimbou o carimbo de data/hora do exemplo de saída antes de chamar o método Transform . Ele copia os valores de carimbo de data/hora do exemplo de entrada, sem modificá-los. Se o filtro precisar alterar os carimbos de data/hora, chame IMediaSample::SetTime no exemplo de saída.

  • Formatar alterações. O filtro upstream pode alterar formatos no meio do fluxo anexando um tipo de mídia ao exemplo. Antes de fazer isso, ele chama IPin::QueryAccept no pin de entrada do filtro. Na classe CTransformFilter , isso resulta em uma chamada para CheckInputType seguida por CheckTransform. O filtro downstream também pode alterar os tipos de mídia, usando o mesmo mecanismo. Em seu próprio filtro, há duas coisas para watch:

    • Verifique se QueryAccept não retorna aceitações falsas.
    • Se o filtro aceitar alterações de formato, marcar para elas dentro do método Transform chamando IMediaSample::GetMediaType. Se esse método retornar S_OK, o filtro deverá responder à alteração de formato.

    Para obter mais informações, consulte Alterações de formato dinâmico.

  • Tópicos. Em CTransformFilter e CTransInPlaceFilter, o filtro de transformação fornece amostras de saída de forma síncrona dentro do método Receive . O filtro não cria threads de trabalho para processar os dados. Normalmente, não há motivo para um filtro de transformação criar threads de trabalho.

Próximo: Etapa 6. Adicionar suporte para COM.

Escrevendo filtros do DirectShow