Partilhar via


Suporte JPEG YCbCr

A partir do Windows 8.1, o codec Windows Imaging Component (WIC) JPEG oferece suporte à leitura e gravação de dados de imagem em seu formulário nativo YCbCr. WIC YCbCr suporte pode ser usado em conjunto com Direct2D para renderizar YCbCr dados de pixel com um efeito de imagem. Além disso, o codec WIC JPEG pode consumir dados YCbCr pixel produzidos por determinados drivers de câmera via Media Foundation.

YCbCr dados de pixel consome significativamente menos memória do que os formatos de pixel BGRA padrão. Além disso, acessar dados YCbCr r permite descarregar alguns estágios do pipeline de decodificação/codificação JPEG para Direct2D, que é acelerado pela GPU. Usando YCbCr, seu aplicativo pode reduzir o consumo de memória JPEG e os tempos de carregamento para o mesmo tamanho e qualidade de imagens. Ou, seu aplicativo pode usar mais imagens JPEG de resolução mais alta sem sofrer penalidades de desempenho.

Este tópico descreve como YCbCr dados funcionam e como usá-lo em WIC e Direct2D.

Sobre JPEG YCbCr Data

Esta seção explica alguns conceitos-chave necessários para entender como o YCbCr suporte no WIC funciona e seus principais benefícios.

YCbCr Modelo de cor

O WIC no Windows 8 e versões anteriores suporta quatro modelos de cores diferentes, o mais comum dos quais é RGB/BGR. Este modelo de cores define dados de cor usando componentes vermelhos, verdes e azuis; Pode também utilizar-se um quarto componente alfa.

Aqui está uma imagem decomposta em seus componentes vermelho, verde e azul.

uma imagem decomposta em seus componentes vermelho, verde e azul.

YCbCr é um modelo de cor alternativo que define dados de cor usando um componente de luminância (Y) e dois componentes de crominância (Cb e Cr). É comumente usado em cenários de imagem digital e vídeo. O termo YCbCr é frequentemente usado indistintamente com YUV, embora os dois sejam tecnicamente distintos.

Existem várias variações de YCbCr que diferem em definições de espaço de cor e faixa dinâmica – WIC suporta especificamente dados JPEG JFIF YCbCr dados. Para obter mais informações, consulte a especificação JPEG ITU-T81.

Aqui está uma imagem decomposta em seus componentes Y, Cbe Cr.

uma imagem decomposta em seus componentes y, cb e cr.

Layouts de memória planar versus intercalada

Esta seção descreve algumas diferenças entre acessar e armazenar dados de pixel RGB na memória versus dados YCbCr dados.

Os dados de pixel RGB normalmente são armazenados usando um layout de memória intercalada. Isso significa que os dados de um único componente de cor são intercalados entre pixels e cada pixel é armazenado contíguamente na memória.

Aqui está uma figura mostrando dados de pixel RGBA armazenados em um layout de memória intercalada.

uma figura mostrando dados de pixel RGBA armazenados em um layout de memória intercalada.

YCbCr dados são normalmente armazenados usando um layout de memória plana. Isso significa que cada componente de cor é armazenado separadamente em seu próprio plano contíguo, para um total de três planos. Em outra configuração comum, os componentes Cb e Cr r são intercalados e armazenados juntos, enquanto o componente Y permanece em seu próprio plano, por um total de dois planos.

Aqui está uma figura mostrando Y planar e C intercalado CbCr dados de pixel, um YC comumbCr layout de memória.

uma figura mostrando dados de pixel CBCR planar y e intercalados, um layout de memória YCBCR comum.

Tanto no WIC quanto no Direct2D, cada plano de cores é tratado como seu próprio objeto distinto (um IWICBitmapSource ou ID2D1Bitmap) e, coletivamente, esses planos formam os dados de suporte para uma imagem YCbCr.

Enquanto o WIC suporta o acesso a dados YCbCr nas configurações de 2 e 3 planos, o Direct2D suporta apenas o primeiro (Y e CbCr). Portanto, ao usar WIC e Direct2D juntos, você deve sempre usar o YC de 2 planosbCr configuração.

Subamostragem de Chroma

O modelo de cores YCbCr é adequado para cenários de imagem digital porque pode tirar proveito de certos aspetos do sistema visual humano. Em particular, os seres humanos são mais sensíveis a mudanças na luminância (brilho) de uma imagem e menos sensíveis à crominância (cor). Ao dividir os dados de cor em componentes separados de luminância e crominância, podemos comprimir seletivamente apenas os componentes de crominância para obter economia de espaço com uma perda mínima de qualidade.

Uma técnica para fazer isso é chamada de subamostragem de cromo. Os planos Cb e Cr r são subamostrados (downscaled) em uma ou ambas as dimensões horizontal e vertical. Por razões históricas, cada modo de subamostragem de cromo é comumente referido usando uma relação J:a:b de três partes.

Modo de subamostragem Downscale horizontal Downscale vertical Bits por pixel*
4:4:4 1x 1x 24
4:2:2 2x 1x 16
4:4:0 1x 2x 16
4:2:0 2x 2x 12

 

* Inclui dados Y.

Na tabela acima, se você usar YCbCr para armazenar dados de imagem não compactados, poderá obter uma economia de memória de 25% a 62,5% versus 32 bits por pixel de dados RGBA, dependendo do modo de subamostragem chroma usado.

JPEG Uso de YCbCr

Em um alto nível, o pipeline de descompressão JPEG consiste nos seguintes estágios:

  1. Executar a descompressão de entropia (por exemplo, Huffman)
  2. Realizar desquantização
  3. Executar transformada de cosseno discreta inversa
  4. Execute o upsampling de chroma em dados CbCr r
  5. Converter dados YCbCr r para RGBA (se necessário)

Ao fazer com que o codec JPEG produza dados YCbCr, podemos evitar as duas etapas finais do processo de decodificação ou adiá-las para a GPU. Além da economia de memória listada na seção anterior, isso reduz significativamente o tempo total necessário para decodificar a imagem. A mesma economia se aplica ao codificar dados YCbCr.

Usando JPEG YCbCr Data

Esta seção explica como usar WIC e Direct2D para operar em dados YCbCr.

Para ver as orientações deste documento usadas na prática, consulte o JPEG YCbCr optimizations in Direct2D and WIC sample que demonstra todas as etapas necessárias para decodificar e renderizar conteúdo YCbCr em um aplicativo Direct2D.

Usando YCbCr imagens JPEG

A grande maioria das imagens JPEG são armazenadas como YCbCr. Alguns JPEGs contêm dados CMYK ou em tons de cinza e não usam YCbCr. Isso significa que você normalmente, mas nem sempre, pode usar diretamente o conteúdo JPEG pré-existente sem modificações.

WIC e Direct2D não suportam todas as configurações possíveis dede YCbC r, e YCbCr r suporte em Direct2D depende do hardware e driver gráficos subjacentes. Devido a isso, um pipeline de imagem de uso geral precisa ser robusto para imagens que não usam YCbCr (incluindo outros formatos de imagem comuns, como PNG ou BMP) ou para casos em que YCbCr suporte não está disponível. Recomendamos que você mantenha seu pipeline de geração de imagens baseado em BGRA existente e habilite o YCbCr como uma otimização de desempenho, quando disponível.

Windows Imaging Component APIs

WIC no Windows 8.1 adiciona três novas interfaces para fornecer acesso a JPEG YCbCr dados.

IWICPlanarBitmapSourceTransform

IWICPlanarBitmapSourceTransform é análogo a IWICBitmapSourceTransform, exceto que produz pixels em uma configuração plana, incluindo dados YCbCr. Você pode obter essa interface chamando QueryInterface em uma implementação de IWICBitmapSource que suporta acesso plano. Isso inclui a implementação do codec JPEG de IWICBitmapFrameDecode, bem como IWICBitmapScaler, IWICBitmapFlipRotatore IWICColorTransform.

IWICPlanarBitmapFrameEncode

IWICPlanarBitmapFrameEncode fornece a capacidade de codificar dados de pixel planares, incluindo dados YCbCr r. Você pode obter essa interface chamando QueryInterface na implementação do codec JPEG de IWICBitmapFrameEncode.

IWICPlanarFormatConverter

IWICPlanarFormatConverter permite que IWICFormatConverter consuma dados de pixel planares, incluindo YCbCr, e convertê-los em um formato de pixel intercalado. Ele não expõe a capacidade de converter dados de pixel intercalados para um formato plano. Você pode obter essa interface chamando QueryInterface na implementação fornecida pelo Windows de IWICFormatConverter.

Direct2D APIs

Direct2D no Windows 8.1 suporta YCbCr dados de pixel planar com o novo YCbCr efeito de imagem . Este efeito fornece a capacidade de renderizar YCbCr dados. O efeito toma como entrada duas interfaces ID2D1Bitmap: uma contendo dados Y planares no formato DXGI_FORMAT_R8_UNORM e outra contendo dados CbCr intercalados no formato DXGI_FORMAT_R8G8_UNORM. Normalmente, você usa esse efeito no lugar do ID2D1Bitmap que conteria dados de pixel BGRA.

O YCbCr efeito de imagem destina-se a ser usado em conjunto com o WIC YCbCr APIs que fornecem o YCbCr dados. Isso efetivamente age para descarregar parte do trabalho de decodificação da CPU para a GPU, onde pode ser processado muito mais rápido e em paralelo.

Determinando se a configuração deYCbC r é suportada

Como observado anteriormente, seu aplicativo deve ser robusto para casos em que YCbCr suporte não está disponível. Esta seção discute as condições que seu aplicativo deve verificar. Se qualquer uma das verificações a seguir falhar, seu aplicativo deverá retornar a um pipeline padrão baseado em BGRA.

O componente WIC suporta YCbCr acesso a dados?

Apenas o codec JPEG fornecido pelo Windows e determinadas transformações WIC suportam YCbCr acesso a dados. Para obter uma lista completa, consulte a seção APIs do Windows Imaging Component.

Para obter uma das interfaces planares YCbCr, chame QueryInterface na interface original. Isso falhará se o componente não suportar YCbCr acesso a dados.

A transformação WIC solicitada é suportada para YCbCr?

Depois de obter um IWICPlanarBitmapSourceTransform, você deve primeiro chamar DoesSupportTransform. Este método toma como parâmetros de entrada o conjunto completo de transformações que você deseja que sejam aplicadas aos dados planares YCbCr e retorna um suporte de indicação booleana, bem como as dimensões mais próximas do tamanho solicitado que podem ser retornadas. Você deve verificar todos os três valores antes de acessar os dados de pixel com IWICPlanarBitmapSourceTransform::CopyPixels.

Esse padrão é semelhante à forma como IWICBitmapSourceTransform é usado.

O driver gráfico suporta os recursos necessários para usar YCbCr com Direct2D?

Essa verificação só é necessária se você estiver usando o Direct2D YCbCr effect para renderizar YCbCr conteúdo. O Direct2D armazena dados YCbCr usando os formatos DXGI_FORMAT_R8_UNORM e DXGI_FORMAT_R8G8_UNORM pixel, que não estão disponíveis em todos os drivers gráficos.

Antes de usar o YCbCr efeito de imagem, você deve chamar ID2D1DeviceContext::IsDxgiFormatSupported para garantir que ambos os formatos sejam suportados pelo driver.

Código de exemplo

Abaixo está um exemplo de código demonstrando as verificações recomendadas. Este exemplo foi retirado do exemplo de otimizações JPEG YCbCr em Direct2D e WIC.

bool DirectXSampleRenderer::DoesWicSupportRequestedYCbCr()
{
    ComPtr<IWICPlanarBitmapSourceTransform> wicPlanarSource;
    HRESULT hr = m_wicScaler.As(&wicPlanarSource);
    if (SUCCEEDED(hr))
    {
        BOOL isTransformSupported;
        uint32 supportedWidth = m_cachedBitmapPixelWidth;
        uint32 supportedHeight = m_cachedBitmapPixelHeight;
        DX::ThrowIfFailed(
            wicPlanarSource->DoesSupportTransform(
                &supportedWidth,
                &supportedHeight,
                WICBitmapTransformRotate0,
                WICPlanarOptionsDefault,
                SampleConstants::WicYCbCrFormats,
                m_planeDescriptions,
                SampleConstants::NumPlanes,
                &isTransformSupported
                )
            );

        // The returned width and height may be larger if IWICPlanarBitmapSourceTransform does not
        // exactly support what is requested.
        if ((isTransformSupported == TRUE) &&
            (supportedWidth == m_cachedBitmapPixelWidth) &&
            (supportedHeight == m_cachedBitmapPixelHeight))
        {
            return true;
        }
    }

    return false;
}

bool DirectXSampleRenderer::DoesDriverSupportYCbCr()
{
    auto d2dContext = m_deviceResources->GetD2DDeviceContext();

    return (d2dContext->IsDxgiFormatSupported(DXGI_FORMAT_R8_UNORM)) &&
        (d2dContext->IsDxgiFormatSupported(DXGI_FORMAT_R8G8_UNORM));
}

Decodificação YCbCr Pixel Data

Se você quiser obter YCbCr dados de pixel, você deve chamar IWICPlanarBitmapSourceTransform::CopyPixels. Esse método copia dados de pixel em uma matriz de estruturas dedeWICBitmapPlane preenchidas, uma para cada plano de dados desejado (por exemplo, Y e CbCr). Um WICBitmapPlane contém informações sobre os dados de pixel e aponta para o buffer de memória que receberá os dados.

Se você quiser usar o YCbCr dados de pixel com outras APIs WIC, você deve criar umdeIWICBitmap configurado adequadamente, chamar Lock para obter o buffer de memória subjacente e associar o buffer ao WICBitmapPlane usado para receber os dados de pixel dedeC YC . Você pode usar o IWICBitmap normalmente.

Finalmente, se você quiser renderizar o YCbCr dados em Direct2D, você deve criar um ID2D1Bitmap de cadaIWICBitmape usá-los como fonte para o YCbCr efeito de imagem. O WIC permite que você solicite várias configurações planares. Ao interoperar com o Direct2D, você deve solicitar dois planos, um usando GUID_WICPixelFormat8bppY e outro usando GUID_WICPixelFormat16bppCbCr, pois essa é a configuração esperada pelo Direct2D.

Exemplo de código

Abaixo está um exemplo de código demonstrando as etapas para decodificar e renderizar dados YCbCr no Direct2D. Este exemplo foi retirado do exemplo de otimizações JPEG YCbCr em Direct2D e WIC.

void DirectXSampleRenderer::CreateYCbCrDeviceResources()
{
    auto wicFactory = m_deviceResources->GetWicImagingFactory();
    auto d2dContext = m_deviceResources->GetD2DDeviceContext();

    ComPtr<IWICPlanarBitmapSourceTransform> wicPlanarSource;
    DX::ThrowIfFailed(
        m_wicScaler.As(&wicPlanarSource)
        );

    ComPtr<IWICBitmap> bitmaps[SampleConstants::NumPlanes];
    ComPtr<IWICBitmapLock> locks[SampleConstants::NumPlanes];
    WICBitmapPlane planes[SampleConstants::NumPlanes];

    for (uint32 i = 0; i < SampleConstants::NumPlanes; i++)
    {
        DX::ThrowIfFailed(
            wicFactory->CreateBitmap(
                m_planeDescriptions[i].Width,
                m_planeDescriptions[i].Height,
                m_planeDescriptions[i].Format,
                WICBitmapCacheOnLoad,
                &bitmaps[i]
                )
            );

        LockBitmap(bitmaps[i].Get(), WICBitmapLockWrite, nullptr, &locks[i], &planes[i]);
    }

    DX::ThrowIfFailed(
        wicPlanarSource->CopyPixels(
            nullptr, // Copy the entire source region.
            m_cachedBitmapPixelWidth,
            m_cachedBitmapPixelHeight,
            WICBitmapTransformRotate0,
            WICPlanarOptionsDefault,
            planes,
            SampleConstants::NumPlanes
            )
        );

    DX::ThrowIfFailed(d2dContext->CreateEffect(CLSID_D2D1YCbCr, &m_d2dYCbCrEffect));

    ComPtr<ID2D1Bitmap1> d2dBitmaps[SampleConstants::NumPlanes];
    for (uint32 i = 0; i < SampleConstants::NumPlanes; i++)
    {
        // IWICBitmapLock must be released before using the IWICBitmap.
        locks[i] = nullptr;

        // First ID2D1Bitmap1 is DXGI_FORMAT_R8 (Y), second is DXGI_FORMAT_R8G8 (CbCr).
        DX::ThrowIfFailed(d2dContext->CreateBitmapFromWicBitmap(bitmaps[i].Get(), &d2dBitmaps[i]));
        m_d2dYCbCrEffect->SetInput(i, d2dBitmaps[i].Get());
    }
}

void DirectXSampleRenderer::LockBitmap(
    _In_ IWICBitmap *pBitmap,
    DWORD bitmapLockFlags,
    _In_opt_ const WICRect *prcSource,
    _Outptr_ IWICBitmapLock **ppBitmapLock,
    _Out_ WICBitmapPlane *pPlane
    )
{
    // ComPtr guarantees the IWICBitmapLock is released if an exception is thrown.
    ComPtr<IWICBitmapLock> lock;
    DX::ThrowIfFailed(pBitmap->Lock(prcSource, bitmapLockFlags, &lock));
    DX::ThrowIfFailed(lock->GetStride(&pPlane->cbStride));
    DX::ThrowIfFailed(lock->GetDataPointer(&pPlane->cbBufferSize, &pPlane->pbBuffer));
    DX::ThrowIfFailed(lock->GetPixelFormat(&pPlane->Format));
    *ppBitmapLock = lock.Detach();
}

Transformando YCbCr Pixel Data

A transformação de dados YCbCr é quase idêntica à decodificação, pois ambos envolvem IWICPlanarBitmapSourceTransform. A única diferença é de qual objeto WIC você obteve a interface. O Windows fornecido scaler, flip rotator e color transform todos suportam YCbCr acesso.

Encadeamento se transforma junto

O WIC suporta a noção de encadeamento de múltiplas transformações. Por exemplo, você pode criar o seguinte pipeline WIC:

um diagrama de um pipeline WIC começando com um decodificador JPEG.

Em seguida, você pode chamar QueryInterface no IWICColorTransform para obter IWICPlanarBitmapSourceTransform. A transformação de cor pode se comunicar com as transformações anteriores e pode expor os recursos agregados de cada estágio no pipeline. O WIC garante que os dados do YCbCr sejam preservados durante todo o processo. Esse encadeamento só funciona ao usar componentes que suportam YCbCr acesso.

Otimizações de codec JPEG

Semelhante à implementação de decodificação de quadros JPEG de IWICBitmapSourceTransform , a implementação de decodificação de quadros JPEG de IWICPlanarBitmapSourceTransform suporta dimensionamento e rotação de domínio JPEG DCT nativo. Você pode solicitar uma potência de dois downscale ou uma rotação diretamente do decodificador JPEG. Isso normalmente resulta em maior qualidade e desempenho do que usar as transformações discretas.

Além disso, quando você encadeia uma ou mais transformações WIC após o decodificador JPEG, ele pode aproveitar o dimensionamento e a rotação nativos do JPEG para satisfazer a operação agregada solicitada.

Conversões de formato

Use IWICPlanarFormatConverter para converter dados de pixel planar YCbCr para um formato de pixel intercalado, como GUID_WICPixelFormat32bppPBGRA. WIC no Windows 8.1 não fornece a capacidade de converter para um YC planarbCr formato pixel.

Codificação YCbCr Pixel Data

Use IWICPlanarBitmapFrameEncode para codificar dados deYC bCr pixel para o codificador JPEG. A codificação YCbCr dados IWICPlanarBitmapFrameEncode é semelhante, mas não idêntica à codificação de dados intercalados usando IWICBitmapFrameEncode. A interface planar expõe apenas a capacidade de escrever dados de imagem de quadro planar, e você deve continuar a usar a interface de codificação de quadro para definir metadados ou uma miniatura e confirmar no final da operação.

Para o caso típico, você deve seguir estas etapas:

  1. Obtenha o IWICBitmapFrameEncode normalmente. Se você quiser configurar a subamostragem do chroma, defina a opção JpegYCrCbSubsampling codificador ao criar o quadro.
  2. Se você precisar definir metadados ou uma miniatura, faça isso usando IWICBitmapFrameEncode normalmente.
  3. QueryInterface para o IWICPlanarBitmapFrameEncode.
  4. Defina o YCbCr dados de pixel usando IWICPlanarBitmapFrameEncode::WriteSource ou IWICPlanarBitmapFrameEncode::WritePixels. Ao contrário de seus IWICBitmapFrameEncode contrapartes, você fornece esses métodos com uma matriz de IWICBitmapSource ou WICBitmapPlane que contêm os planos YCbCr pixel.
  5. Quando terminar, chame IWICBitmapFrameEncode::Commit.

Decodificando dados YCbCr pixel no Windows 10

A partir do Windows 10 build 1507, o Direct2D fornece ID2D1ImageSourceFromWic, uma maneira mais simples de decodificar JPEGs em Direct2D enquanto aproveita as otimizações dede do YCbC r. ID2D1ImageSourceFromWic executa automaticamente todas as verificações de capacidade de de necessárias para você; ele usa o codepath otimizado quando possível e usa um fallback de outra forma. Ele também permite novas otimizações, como armazenar em cache apenas sub-regiões da imagem que são necessárias de cada vez.

Para obter mais informações sobre como usar ID2D1ImageSourceFromWic, consulte o SDK de Ajuste de Fotos Direct2D exemplo.