Compatibilidad con JPEG YCbCr

A partir de Windows 8.1, el códec JPEG Windows Imaging Component (WIC) admite la lectura y escritura de datos de imagen en su forma YCbCr nativa. La compatibilidad con WIC YCbCr se puede usar junto con Direct2D para representar datos de píxeles deYCbCr con un efecto de imagen. Además, el códec WIC JPEG puede consumir datos de píxeles de YCbCr generados por determinados controladores de cámara a través de Media Foundation.

Los datos de píxeles de YCbCr consumen significativamente menos memoria que los formatos de píxel BGRA estándar. Además, el acceso a los datos de YCbCr permite descargar algunas fases de la canalización de descodificación y codificación JPEG a Direct2D, que es acelerada por GPU. Al usar YCbCr, la aplicación puede reducir el consumo de memoria JPEG y los tiempos de carga de las mismas imágenes de tamaño y calidad. O bien, la aplicación puede usar imágenes JPEG de mayor resolución sin sufrir penalizaciones de rendimiento.

En este tema se describe cómo funcionan los datos de YCbCr y cómo usarlos en WIC y Direct2D.

Acerca de los datos de JPEG YCbCr

En esta sección se explican algunos conceptos clave necesarios para comprender cómo funciona la compatibilidad de YCbCr en WIC y sus principales ventajas.

Modelo de color de YCbCr

WIC en Windows 8 y versiones anteriores admite cuatro modelos de color diferentes, el más común es RGB/BGR. Este modelo de color define los datos de color mediante componentes rojo, verde y azul; También se puede usar un cuarto componente alfa.

Esta es una imagen descomponida en sus componentes rojo, verde y azul.

an image decomposed into its red, green and blue components.

YCbCr es un modelo de color alternativo que define los datos de color mediante un componente de luminancia (Y) y dos componentes de cromoinancia (Cb y Cr). Normalmente se usa en escenarios de imágenes digitales y vídeos. El término YCbCr se usa a menudo indistintamente con YUV, aunque los dos son técnicamente distintos.

Hay varias variaciones de YCbCr que difieren en el espacio de colores y las definiciones de intervalo dinámico: WIC admite específicamente datos JPEG JFIFYCbCr. Para obtener más información, consulte la especificación JPEG ITU-T81.

Esta es una imagen descomponida en sus componentes Y, Cb y Cr .

an image decomposed into its y, cb, and cr components.

Diseños de memoria intercalados frente a planos

En esta sección se describen algunas diferencias entre el acceso y el almacenamiento de datos de píxeles RGB en la memoria frente a los datos de YCbCr.

Normalmente, los datos de píxeles RGB se almacenan mediante un diseño de memoria intercalado. Esto significa que los datos de un único componente de color se intercalan entre píxeles y cada píxel se almacena contiguamente en la memoria.

Esta es una ilustración que muestra los datos de píxeles RGBA almacenados en un diseño de memoria intercalado.

a figure showing rgba pixel data stored in an interleaved memory layout.

Los datos de YCbCr se almacenan normalmente mediante un diseño de memoria planar. Esto significa que cada componente de color se almacena por separado en su propio plano contiguo, para un total de tres planos. En otra configuración común, los componentes Cb y Cr se intercalan y almacenan juntos, mientras que el componente Y permanece en su propio plano, para un total de dos planos.

Esta es una ilustración que muestra los datos de píxeles de CbCr intercalados Y e intercalados, un diseño de memoria deYCbCr común.

a figure showing planar y and interleaved cbcr pixel data, a common ycbcr memory layout.

En WIC y Direct2D, cada plano de color se trata como su propio objeto distinto (ya sea IWICBitmapSource o ID2D1Bitmap), y colectivamente estos planos forman los datos de respaldo de una imagen YCbCr.

Aunque WIC admite el acceso a datos de YCbCr en las configuraciones de plano 2 y 3, Direct2D solo admite el anterior (Y y CbCr). Por lo tanto, al usar WIC y Direct2D juntos, siempre debe usar la configuración de YCbCr del plano 2.

Submuestreo cromático

El modelo de color YCbCr es adecuado para escenarios de creación de imágenes digitales, ya que puede aprovechar ciertos aspectos del sistema visual humano. En particular, los seres humanos son más sensibles a los cambios en la luminancia (brillo) de una imagen y menos sensibles a la cromoncia (color). Al dividir los datos de color en componentes de luminancia y cromoinancia independientes, podemos comprimir selectivamente solo los componentes de cromotinación para lograr ahorros de espacio con una pérdida mínima de calidad.

Una técnica para hacer esto se denomina submuestreo cromático. Los planos Cb y Cr se submuestreo (escalado vertical) en una o ambas dimensiones horizontales y verticales. Por motivos históricos, cada modo de submuestreo cromático se conoce normalmente mediante una relación de tres partes J:a:b.

Modo de submuestreo Escala vertical horizontal Escala vertical vertical Bits por píxel*
4:4:4 1x 1x 24
4:2:2 2x 1x 16
4:4:0 1x 2x 16
4:2:0 2x 2x 12

 

* Incluye datos Y.

En la tabla anterior, si usa YCbCr para almacenar datos de imagen sin comprimir, puede lograr un ahorro de memoria del 25 % al 62,5 % frente a los datos RGBA de 32 bits por píxel, dependiendo del modo de submuestreo cromático.

Uso JPEG de YCbCr

En un nivel alto, la canalización de descompresión JPEG consta de las siguientes fases:

  1. Realizar la entropía (por ejemplo, Huffman) descompresión
  2. Realizar la desquantización
  3. Realización de una transformación de coseno discreta inversa
  4. Realizar el muestreo cromático en datos de CbCr
  5. Convertir datos de YCbCr en RGBA (si es necesario)

Al hacer que el códec JPEG genere datos de YCbCr, podemos evitar los dos pasos finales del proceso de descodificación o aplazarlos a la GPU. Además del ahorro de memoria que se muestra en la sección anterior, esto reduce significativamente el tiempo total necesario para descodificar la imagen. Se aplican los mismos ahorros al codificar datos de YCbCr.

Uso de datos JPEG YCbCr

En esta sección se explica cómo usar WIC y Direct2D para operar en datos de YCbCr.

Para ver las instrucciones de este documento que se usan en la práctica, consulte las optimizaciones jpeg YCbCr en Direct2D y el ejemplo WIC, que muestra todos los pasos necesarios para descodificar y representar contenido de YCbCr en una aplicación Direct2D.

Uso de imágenes JPEG deYCbCr

La gran mayoría de las imágenes JPEG se almacenan como YCbCr. Algunos JPEG contienen datos cmYK o escala de grises y no usan YCbCr. Esto significa que normalmente, pero no siempre, puede usar directamente contenido JPEG preexistente sin modificaciones.

WIC y Direct2D no admiten todas las configuraciones YCbCr posibles y la compatibilidad conYCbCr en Direct2D depende del hardware y controlador gráficos subyacentes. Debido a esto, una canalización de creación de imágenes de uso general debe ser sólida para las imágenes que no usan YCbCr (incluidos otros formatos de imagen comunes, como PNG o BMP) o en casos en los que la compatibilidad conYCbCr no está disponible. Se recomienda mantener la canalización de creación de imágenes basada en BGRA existente y habilitar YCbCr como una optimización del rendimiento cuando esté disponible.

API del componente de creación de imágenes de Windows

WIC en Windows 8.1 agrega tres interfaces nuevas para proporcionar acceso a datos JPEG YCbCr.

IWICPlanarBitmapSourceTransform

IWICPlanarBitmapSourceTransform es análogo a IWICBitmapSourceTransform, salvo que genera píxeles en una configuración planar, incluidos los datos de YCbCr. Puede obtener esta interfaz llamando a QueryInterface en una implementación de IWICBitmapSource que admita el acceso planar. Esto incluye la implementación del códec JPEG de IWICBitmapFrameDecode , así como IWICBitmapScaler, IWICBitmapFlipRotator e IWICColorTransform.

IWICPlanarBitmapFrameEncode

IWICPlanarBitmapFrameEncode proporciona la capacidad de codificar datos de píxeles planar, incluidos los datos de YCbCr. Puede obtener esta interfaz llamando a QueryInterface en la implementación del códec JPEG de IWICBitmapFrameEncode.

IWICPlanarFormatConverter

IWICPlanarFormatConverter permite que IWICFormatConverter consuma datos de píxeles planar, incluido YCbCr, y convertirlo en un formato de píxel intercalado. No expone la capacidad de convertir datos de píxeles intercalados a un formato planar. Puede obtener esta interfaz llamando a QueryInterface en la Windows implementación proporcionada de IWICFormatConverter.

API de Direct2D

Direct2D en Windows 8.1 admite datos de píxeles planar de YCbCr con el nuevo efecto de imagenYCbCr . Este efecto proporciona la capacidad de representar datos de YCbCr. El efecto toma como entrada dos interfaces ID2D1Bitmap : una que contiene datos Y planar en el formato DXGI_FORMAT_R8_UNORM y otra que contiene datos CbCr intercalados en el formato DXGI_FORMAT_R8G8_UNORM. Normalmente, este efecto se usa en lugar de ID2D1Bitmap que habría contenido datos de píxeles BGRA.

El efecto de imagen YCbCr está pensado para usarse junto con las API de WIC YCbCr que proporcionan los datos de YCbCr. Esto actúa eficazmente para descargar parte del trabajo de descodificación de la CPU a la GPU, donde se puede procesar mucho más rápido y en paralelo.

Determinar si se admite la configuración de YCbCr

Como se indicó antes, la aplicación debe ser sólida en los casos en los que la compatibilidad con YCbCr no está disponible. En esta sección se describen las condiciones que la aplicación debe comprobar. Si se produce un error en alguna de las siguientes comprobaciones, la aplicación debe revertir a una canalización estándar basada en BGRA.

¿El componente WIC admite el acceso a datos de YCbCr?

Solo el códec JPEG proporcionado Windows y ciertas transformaciones WIC admiten el acceso a datos de YCbCr. Para obtener una lista completa, consulte la sección api de componente de creación de imágenes de Windows.

Para obtener una de las interfaces YCbCr planar, llame a QueryInterface en la interfaz original. Esto producirá un error si el componente no admite el acceso a datos de YCbCr.

¿Se admite la transformación WIC solicitada para YCbCr?

Después de obtener un IWICPlanarBitmapSourceTransform, primero debe llamar a DoesSupportTransform. Este método toma como parámetros de entrada el conjunto completo de transformaciones que desea aplicar a los datos de YCbCr planar y devuelve un valor booleano que indica compatibilidad, así como las dimensiones más cercanas al tamaño solicitado que se puede devolver. Debe comprobar los tres valores antes de acceder a los datos de píxeles con IWICPlanarBitmapSourceTransform::CopyPixels.

Este patrón es similar a cómo se usa IWICBitmapSourceTransform .

¿El controlador de gráficos admite las características necesarias para usar YCbCr con Direct2D?

Esta comprobación solo es necesaria si usa el efecto YCbCr de Direct2D para representar el contenido de YCbCr. Direct2D almacena datos de YCbCr con los formatos de DXGI_FORMAT_R8_UNORM y DXGI_FORMAT_R8G8_UNORM píxeles, que no están disponibles en todos los controladores de gráficos.

Antes de usar el efecto de imagen YCbCr, debe llamar a ID2D1DeviceContext::IsDxgiFormatSupported para asegurarse de que el controlador admite ambos formatos.

Código de ejemplo

A continuación se muestra un ejemplo de código que muestra las comprobaciones recomendadas. Este ejemplo se tomó de las optimizaciones JPEG YCbCr en direct2D y el ejemplo 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));
}

Descodificación de datos de píxeles de YCbCr

Si desea obtener datos de píxeles de YCbCr, debe llamar a IWICPlanarBitmapSourceTransform::CopyPixels. Este método copia los datos de píxeles en una matriz de estructuras WICBitmapPlane rellenadas, una para cada plano de datos que desee (por ejemplo, Y y CbCr). WiCBitmapPlane contiene información sobre los datos de píxeles y apunta al búfer de memoria que recibirá los datos.

Si desea usar los datos de píxeles de YCbCr con otras API de WIC, debe crear un IWICBitmap configurado correctamente, llamar a Lock para obtener el búfer de memoria subyacente y asociar el búfer con el WICBitmapPlane usado para recibir los datos de píxeles deYCbCr. Después, puede usar IWICBitmap normalmente.

Por último, si desea representar los datos de YCbCr en Direct2D, debe crear un ID2D1Bitmap a partir de cada IWICBitmap y usarlos como origen para el efecto de imagen deYCbCr. WIC le permite solicitar varias configuraciones planar. Al interoperar con Direct2D, debe solicitar dos planos, uno con GUID_WICPixelFormat8bppY y el otro mediante GUID_WICPixelFormat16bppCbCr, ya que esta es la configuración esperada por Direct2D.

Ejemplo de código

A continuación se muestra un ejemplo de código que muestra los pasos para descodificar y representar datos de YCbCr en Direct2D. Este ejemplo se tomó de las optimizaciones JPEG YCbCr en direct2D y el ejemplo 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();
}

Transformación de datos de píxeles de YCbCr

La transformación de datos de YCbCr es casi idéntica a la descodificación, ya que ambas implican IWICPlanarBitmapSourceTransform. La única diferencia es el objeto WIC del que obtuvo la interfaz. El Windows escalador proporcionado, rotador volteo y transformación de color admiten el acceso de YCbCr.

Encadenar transformaciones juntas

WIC admite la noción de encadenar varias transformaciones. Por ejemplo, puede crear la siguiente canalización WIC:

a diagram of a wic pipeline starting with a jpeg decoder.

A continuación, puede llamar a QueryInterface en IWICColorTransform para obtener IWICPlanarBitmapSourceTransform. La transformación de color puede comunicarse con las transformaciones anteriores y puede exponer las funcionalidades agregadas de cada fase de la canalización. WIC garantiza que los datos de YCbCr se conservan a través de todo el proceso. Este encadenamiento solo funciona cuando se usan componentes que admiten el acceso de YCbCr.

Optimizaciones de códec JPEG

Al igual que la implementación de descodificación de fotograma JPEG de IWICBitmapSourceTransform, la implementación de descodificación de fotograma JPEG de IWICPlanarBitmapSourceTransform admite el escalado y la rotación de dominios JPEG DCT nativos. Puede solicitar una potencia de dos escalas descendentes o una rotación directamente desde el descodificador JPEG. Normalmente, esto da como resultado una mayor calidad y rendimiento que el uso de las transformaciones discretas.

Además, al encadenar una o varias transformaciones WIC después del descodificador JPEG, puede aprovechar el escalado JPEG nativo y la rotación para satisfacer la operación agregada solicitada.

Conversiones de formato

Use IWICPlanarFormatConverter para convertir datos de píxeles de YCbCr planar a un formato de píxel intercalado, como GUID_WICPixelFormat32bppPBGRA. WIC en Windows 8.1 no proporciona la capacidad de convertir a un formato de píxel de YCbCr planar.

Codificación de datos de píxeles de YCbCr

Use IWICPlanarBitmapFrameEncode para codificar los datos de píxeles de YCbCr en el codificador JPEG. La codificación de datos de YCbCrIWICPlanarBitmapFrameEncode es similar pero no idéntica a la codificación de datos intercalados mediante IWICBitmapFrameEncode. La interfaz planar solo expone la capacidad de escribir datos de imagen de fotogramas planar, y debe seguir usando la interfaz de codificación de fotogramas para establecer metadatos o una miniatura y confirmar al final de la operación.

Para el caso típico, debe seguir estos pasos:

  1. Obtenga IWICBitmapFrameEncode como normal. Si desea configurar el submuestreo cromático, establezca la opción de codificador JpegYCrCbSubsampling al crear el marco.
  2. Si necesita establecer metadatos o una miniatura, haga esto con IWICBitmapFrameEncode como normal.
  3. QueryInterface para IWICPlanarBitmapFrameEncode.
  4. Establezca los datos de píxeles de YCbCr mediante IWICPlanarBitmapFrameEncode::WriteSource o IWICPlanarBitmapFrameEncode::WritePixels. A diferencia de sus homólogos de IWICBitmapFrameEncode, estos métodos se proporcionan con una matriz de IWICBitmapSource o WICBitmapPlane que contienen los planos de píxeles de YCbCr.
  5. Cuando haya terminado, llame a IWICBitmapFrameEncode::Commit.

Descodificación de datos de píxeles de YCbCr en Windows 10

A partir de Windows 10 compilación 1507, Direct2D proporciona ID2D1ImageSourceFromWic, una manera más sencilla de descodificar JPEG en Direct2D mientras aprovecha las optimizaciones de YCbCr. ID2D1ImageSourceFromWic realiza automáticamente todas las comprobaciones necesarias de funcionalidad de YCbCr; usa la ruta de código optimizada siempre que sea posible y usa una reserva en caso contrario. También permite nuevas optimizaciones, como solo las subregiones de almacenamiento en caché de la imagen que se necesitan a la vez.

Para obtener más información sobre el uso de ID2D1ImageSourceFromWic, consulte el ejemplo del SDK de ajuste de fotos de Direct2D.