Compatibilidad con JPEG YCbCr
A partir de Windows 8.1, el códec JPEG del componente de imágenes de Windows (WIC) admite la lectura y escritura de datos de imagen en su formato nativo de YCbCr. La compatibilidad con WIC YCbCr se puede usar junto con Direct2D para representar datos de píxeles de YCbCr con un efecto de imagen. Además, el códec JPEG WIC 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íxeles 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. Mediante el uso de 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, tu aplicación puede usar más 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 JPEG YCbCr
-
Uso de datos JPEG YCbCr
- Uso de imágenes JPEG de YCbCr
- API de componentes de imágenes de Windows
- API de Direct2D
- Determinar si se admite la configuración de YCbCr
- Descodificación de datos de píxeles de YCbCr
- Transformación de datos de píxeles de YCbCr
- Codificación de datos de píxeles de YCbCr
- Descodificación de datos de píxeles de YCbCr en Windows 10
- Temas relacionados
Acerca de los datos JPEG YCbCr
En esta sección se explican algunos conceptos clave necesarios para comprender cómo funciona la compatibilidad con 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.
YCbCr es un modelo de color alternativo que define los datos de color mediante un componente de luminancia (Y) y dos componentes de cromoncia (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 rango dinámico: WIC admite específicamente datos JPEG JFIF YCbCr . 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 .
Diseños de memoria planeada frente a intercalados
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 de forma contigua en la memoria.
Esta es una ilustración que muestra los datos de píxeles RGBA almacenados en un diseño de memoria intercalado.
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 de 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 en la que se muestran los datos de píxeles de Y plano e intercalados CbCr , un diseño de memoria de YCbCr común.
En WIC y Direct2D, cada plano de color se trata como su propio objeto distinto (ya sea un IWICBitmapSource o ID2D1Bitmap), y colectivamente estos planos forman los datos de respaldo de una imagen de YCbCr .
Aunque WIC admite el acceso a los datos de YCbCr en las configuraciones de plano 2 y 3, Direct2D solo admite el primero (Y y CbCr). Por lo tanto, al usar WIC y Direct2D juntos, siempre debes usar la configuración de 2 planos YCbCr .
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 concreto, los seres humanos son más sensibles a los cambios en la luminancia (brillo) de una imagen y menos sensible a la crominancia (color). Al dividir los datos de color en componentes de luminancia y cromoinancia independientes, podemos comprimir de forma selectiva 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 son submuestreos (escalados) en una o ambas dimensiones horizontales y verticales. Por motivos históricos, normalmente se hace referencia a cada modo de submuestreo cromático mediante una relación J:a:b de tres partes.
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 r 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 que se use.
Uso JPEG de YCbCr
En un nivel alto, la canalización de descompresión JPEG consta de las siguientes fases:
- Realizar descompresión de entropía (por ejemplo, Huffman)
- Realización de la desquantización
- Realización de una transformación de coseno discreta inversa
- Realizar el muestreo cromático en los datos de CbCr
- Convertir datos de YCbCr en RGBA (si es necesario)
Al hacer que el códec JPEG genere datos 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 los 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, consulta las optimizaciones YCbCr jpeg en Direct2D y el ejemplo de WIC , que muestra todos los pasos necesarios para descodificar y representar el contenido de YCbCr en una aplicación Direct2D.
Uso de imágenes JPEG de YCbCr
La gran mayoría de las imágenes JPEG se almacenan como YCbCr. Algunos JPEG contienen datos de 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 posibles de YCbCr , y la compatibilidad con YCbCr en Direct2D depende del hardware y controlador gráficos subyacentes. Por este motivo, 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 con YCbCr 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 de componentes de imágenes de Windows
WIC en Windows 8.1 agrega tres nuevas interfaces para proporcionar acceso a los 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 plano, 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 plano, 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 implementación proporcionada por Windows de IWICFormatConverter.
API de Direct2D
Direct2D en Windows 8.1 admite datos de píxeles planar de YCbCcon el nuevo efecto de imagen de YCbCr . Este efecto proporciona la capacidad de representar datos de YCbCr . El efecto toma como entrada dos interfaces ID2D1Bitmap : una que contiene datos Y plano 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 de YCbCr está diseñado 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 recurrir 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 por Windows y ciertas transformaciones WIC admiten el acceso a datos de YCbCr . Para obtener una lista completa, consulte la sección API de componentes de imágenes de Windows .
Para obtener una de las interfaces YCbCr planar, llame a QueryInterface en la interfaz original. Se 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 del 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 usas el efecto Direct2D YCbCr 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 de YCbCr , debe llamar a ID2D1DeviceContext::IsDxgiFormatSupported para asegurarse de que el controlador admita ambos formatos.
Código de ejemplo
A continuación se muestra un ejemplo de código que muestra las comprobaciones recomendadas. Este ejemplo se ha tomado de las optimizaciones JPEG YCbCr en direct2D y wic de ejemplo.
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). Un 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 de YCbCr . A continuación, puede usar IWICBitmap normalmente.
Por último, si quieres representar los datos de YCbCr en Direct2D, debes crear un ID2D1Bitmap a partir de cada IWICBitmap y usarlos como origen para el efecto de imagen de YCbCr . WIC permite solicitar varias configuraciones planar. Al interoperar con Direct2D, debes solicitar dos planos, uno con GUID_WICPixelFormat8bppY y el otro con 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 ha tomado de las optimizaciones JPEG YCbCr en direct2D y wic de ejemplo.
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
Transformar datos de YCbCr es casi idéntico a la descodificación, ya que ambos implican IWICPlanarBitmapSourceTransform. La única diferencia es el objeto WIC del que obtuvo la interfaz. El escalador proporcionado por Windows, el rotador de volteo y la transformación de color admiten el acceso de YCbCr .
Encadenar transformaciones juntas
WIC admite la noción de encadenamiento de varias transformaciones. Por ejemplo, puede crear la siguiente canalización wic:
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 fotogramas JPEG de IWICBitmapSourceTransform, la implementación de descodificación de fotogramas JPEG de IWICPlanarBitmapSourceTransform admite el escalado y 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 plano 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 plano YCbCr.
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 fotograma 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:
- Obtenga IWICBitmapFrameEncode como normal. Si desea configurar el submuestreo cromático, establezca la opción Del codificador JpegYCrCbSubsampling al crear el marco.
- Si necesita establecer metadatos o una miniatura, házlo con IWICBitmapFrameEncode como normal.
- QueryInterface para IWICPlanarBitmapFrameEncode.
- Establezca los datos de píxeles de YCbCconIWICPlanarBitmapFrameEncode::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 .
- 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 y aprovechar las optimizaciones de YCbCr. ID2D1ImageSourceFromWic realiza automáticamente todas las comprobaciones de funcionalidad de YCbCr necesarias; usa la ruta de código optimizada siempre que sea posible y usa una reserva en caso contrario. También permite nuevas optimizaciones, como el almacenamiento en caché solo de las subdivisiones 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 fotográfico de Direct2D.