Prise en charge de JPEG YCbCr

À compter de Windows 8.1, le codec JPEG WIC (Windows Imaging Component) prend en charge la lecture et l’écriture de données d’image dans son formulaire YCbCr natif. La prise en charge de WIC YCbCr peut être utilisée conjointement avec Direct2D pour afficher les données de pixels YCbCr avec un effet d’image. En outre, le codec JPEG WIC peut consommer des données de pixels YCbCr produites par certains pilotes d’appareil photo via Media Foundation.

Les données de pixels YCbCr consomment beaucoup moins de mémoire que les formats de pixels BGRA standard. En outre, l’accès aux données YCbCr vous permet de décharger certaines étapes du pipeline de décodage/encode JPEG vers Direct2D qui est accéléré par GPU. En utilisant YCbCr, votre application peut réduire la consommation de mémoire JPEG et les temps de chargement pour des images de même taille et qualité. Ou, votre application peut utiliser plus d’images JPEG de résolution supérieure sans subir de pénalités de performances.

Cette rubrique décrit comment fonctionnent les données YCbCr et comment les utiliser dans WIC et Direct2D.

À propos des données JPEG YCbCr r

Cette section explique certains concepts clés nécessaires pour comprendre le fonctionnement de la prise en charge YCbCr dans WIC et ses principaux avantages.

Modèle de couleur YCbCr

WIC dans Windows 8 et versions antérieures prend en charge quatre modèles de couleurs différents, dont le plus courant est RVB/BGR. Ce modèle de couleur définit les données de couleur à l’aide de composants rouges, verts et bleus ; un quatrième composant alpha peut également être utilisé.

Voici une image décomposée en ses composants rouge, vert et bleu.

une image décomposée en ses composants rouge, vert et bleu.

YCbCr est un autre modèle de couleur qui définit des données de couleur à l’aide d’un composant de luminance (Y) et de deux composants de chrominance (Cb et Cr). Il est couramment utilisé dans les scénarios vidéo et d’imagerie numérique. Le terme YCbCr est souvent utilisé indifféremment avec YUV, bien que les deux soient techniquement distincts.

Il existe plusieurs variantes de YCbCr qui diffèrent dans les définitions d’espace de couleur et de plage dynamique : WIC prend spécifiquement en charge les données JPEG JFIF YCbCr . Pour plus d’informations, reportez-vous à la spécification JPEG ITU-T81.

Voici une image décomposée en ses composants Y, Cb et Cr .

une image décomposée en ses composants y, cb et cr.

Dispositions de mémoire planaire ou entrelacée

Cette section décrit certaines différences entre l’accès et le stockage de données de pixels RVB en mémoire et les données YCbCr .

Les données de pixel RVB sont généralement stockées à l’aide d’une disposition de mémoire entrelacée. Cela signifie que les données d’un seul composant de couleur sont entrelacées entre les pixels et que chaque pixel est stocké de manière contiguë en mémoire.

Voici une figure montrant les données de pixels RVBA stockées dans une disposition de mémoire entrelacée.

figure montrant les données de pixels rgba stockées dans une disposition de mémoire entrelacée.

Les données YCbCr sont généralement stockées à l’aide d’une disposition de mémoire planaire. Cela signifie que chaque composant de couleur est stocké séparément dans son propre plan contigu, pour un total de trois plans. Dans une autre configuration courante, les composants Cb et Cr sont entrelacés et stockés ensemble, tandis que le composant Y reste dans son propre plan, pour un total de deux plans.

Voici une figure montrant des données de pixels Y planaires et CbCr entrelacées, une disposition de mémoire YCbCr commune.

figure montrant des données y planaires et des données de pixels cbcr entrelacées, une disposition de mémoire ycbcr commune.

Dans WIC et Direct2D, chaque plan de couleurs est traité comme son propre objet distinct (un IWICBitmapSource ou ID2D1Bitmap), et collectivement ces plans forment les données de stockage d’une image CR YCb.

Alors que WIC prend en charge l’accès aux données YCbCr dans les configurations de plan 2 et 3, Direct2D prend uniquement en charge les anciennes (Y et CbCr). Par conséquent, lorsque vous utilisez WIC et Direct2D ensemble, vous devez toujours utiliser la configuration YCbCr à 2 plans.

Sous-échantillonnage chroma

Le modèle de couleur YCbCr est bien adapté aux scénarios d’imagerie numérique, car il peut tirer parti de certains aspects du système visuel humain. En particulier, les humains sont plus sensibles aux changements de luminosité (luminosité) d’une image et moins sensibles à la chrominance (couleur). En divisant les données de couleur en composants de luminance et de chrominance distincts, nous pouvons compresser de manière sélective uniquement les composants de chrominance pour réaliser des économies d’espace avec une perte de qualité minimale.

Une technique pour ce faire est appelée sous-échantillonnage chromatique. Les plans Cb et Cr sont sous-échantillonné (mis à l’échelle inférieure) dans l’une ou l’autre des dimensions horizontales et verticales. Pour des raisons historiques, chaque mode de sous-échantillonnage chromatique est couramment désigné à l’aide d’un ratio J:a:b en trois parties.

Mode de sous-échantillonnage Mise à l’échelle horizontale Mise à l’échelle verticale Bits par pixel*
4:4:4 1x 1x 24
4:2:2 x 2 1x 16
4:4:0 1x x 2 16
4:2:0 x 2 x 2 12

 

* Inclut les données Y.

Dans le tableau ci-dessus, si vous utilisez YCbCr pour stocker des données d’image non compressées, vous pouvez obtenir des économies de mémoire de 25 % à 62,5 % par rapport aux données RVBA de 32 bits par pixel, selon le mode de sous-échantillonnage chromatique utilisé.

Utilisation JPEG de YCbCr

À un niveau élevé, le pipeline de décompression JPEG se compose des étapes suivantes :

  1. Effectuer une décompression de l’entropie (par exemple, Huffman)
  2. Effectuer la dequantisation
  3. Effectuer une transformation de cosinus discret inverse
  4. Effectuer un upsampling chroma sur des données CbCr
  5. Convertir des données YCbCr en RVBA (si nécessaire)

En faisant en sorte que le codec JPEG produise des données YCbCr , nous pouvons éviter les deux dernières étapes du processus de décodage ou les reporter au GPU. En plus des économies de mémoire répertoriées dans la section précédente, cela réduit considérablement le temps global nécessaire au décodage de l’image. Les mêmes économies s’appliquent lors de l’encodage des données YCbCr .

Utilisation des données JPEG YCbCr

Cette section explique comment utiliser WIC et Direct2D pour fonctionner sur des données YCbCr .

Pour voir les conseils de ce document utilisés dans la pratique, consultez l’exemple JPEG D’optimisations YCbCr dans Direct2D et WIC qui illustre toutes les étapes nécessaires pour décoder et afficher le contenu YCbCr dans une application Direct2D.

Utilisation d’images JPEG YCbCr

La grande majorité des images JPEG sont stockées en tant que YCbCr. Certains JPEG contiennent des données CMJN ou en nuances de gris et n’utilisent pas YCbCr. Cela signifie que vous pouvez généralement, mais pas toujours, utiliser directement du contenu JPEG préexistant sans aucune modification.

WIC et Direct2D ne prennent pas en charge toutes les configurations YCbCr possibles, et la prise en charge de YCbCr dans Direct2D dépend du matériel et du pilote graphiques sous-jacents. Pour cette raison, un pipeline d’imagerie à usage général doit être robuste pour les images qui n’utilisent pas YCbCr (y compris d’autres formats d’image courants tels que PNG ou BMP) ou dans les cas où la prise en charge de YCbCr n’est pas disponible. Nous vous recommandons de conserver votre pipeline d’imagerie basé sur BGRA existant et d’activer YCbCr comme optimisation des performances quand elle est disponible.

API du composant d’acquisition d’images Windows

WIC in Windows 8.1 ajoute trois nouvelles interfaces pour fournir l’accès aux données JPEG YCbCr.

IWICPlanarBitmapSourceTransform

IWICPlanarBitmapSourceTransform est analogue à IWICBitmapSourceTransform, sauf qu’il produit des pixels dans une configuration planaire, y compris des données YCbCr . Vous pouvez obtenir cette interface en appelant QueryInterface sur une implémentation de IWICBitmapSource qui prend en charge l’accès planaire. Cela inclut l’implémentation par le codec JPEG de IWICBitmapFrameDecode , ainsi que IWICBitmapScaler, IWICBitmapFlipRotator et IWICColorTransform.

IWICPlanarBitmapFrameEncode

IWICPlanarBitmapFrameEncode permet d’encoder des données de pixels planaires, y compris des données YCbCr . Vous pouvez obtenir cette interface en appelant QueryInterface sur l’implémentation du codec JPEG de IWICBitmapFrameEncode.

IWICPlanarFormatConverter

IWICPlanarFormatConverter permet à IWICFormatConverter de consommer des données de pixels planaires, y compris YCbCr, et de les convertir au format de pixels entrelacés. Il n’expose pas la possibilité de convertir des données de pixels entrelacées en un format planaire. Vous pouvez obtenir cette interface en appelant QueryInterface sur l’implémentation fournie par Windows de IWICFormatConverter.

API Direct2D

Direct2D dans Windows 8.1 prend en charge les données de pixels planaires YCbCr avec le nouvel effet d’image YCbCr . Cet effet offre la possibilité de restituer les données YCbCr . L’effet prend en entrée deux interfaces ID2D1Bitmap : l’une contenant des données Y planaires au format DXGI_FORMAT_R8_UNORM et l’autre contenant des données CbCr entrelacées au format DXGI_FORMAT_R8G8_UNORM. En règle générale, vous utilisez cet effet à la place de l’ID2D1Bitmap qui aurait contenu des données de pixels BGRA.

L’effet d’image YCbCr est destiné à être utilisé conjointement avec les API WIC YCbCr qui fournissent les données YCbCr . Cela agit efficacement pour décharger une partie du travail de décodage de l’UC vers le GPU, où il peut être traité beaucoup plus rapidement et en parallèle.

Déterminer si la configuration YCbCr est prise en charge

Comme indiqué précédemment, votre application doit être robuste dans les cas où la prise en charge de YCbCr n’est pas disponible. Cette section décrit les conditions pour lesquelles votre application doit case activée. Si l’une des vérifications suivantes échoue, votre application doit revenir à un pipeline BGRA standard.

Le composant WIC prend-il en chargel’accèsaux données YC b Cr ?

Seuls le codec JPEG fourni par Windows et certaines transformations WIC prennent en charge l’accès aux données YCbCr . Pour obtenir la liste complète, reportez-vous à la section API du composant d’acquisition d’images Windows .

Pour obtenir l’une des interfaces YCbCr planaires, appelez QueryInterface sur l’interface d’origine. Cela échouera si le composant ne prend pas en charge l’accès aux données YCbCr .

La transformation WIC demandée est-elle prise en charge pour YCbCr ?

Après avoir obtenu un IWICPlanarBitmapSourceTransform, vous devez d’abord appeler DoesSupportTransform. Cette méthode prend comme paramètres d’entrée l’ensemble complet de transformations que vous souhaitez appliquer aux données YCbCr planaires et retourne une valeur booléenne indiquant la prise en charge, ainsi que les dimensions les plus proches de la taille demandée pouvant être retournées. Vous devez case activée les trois valeurs avant d’accéder aux données de pixels avec IWICPlanarBitmapSourceTransform::CopyPixels.

Ce modèle est similaire à la façon dont IWICBitmapSourceTransform est utilisé.

Le pilote graphique prend-il en charge les fonctionnalités nécessaires pour utiliser YCbCr avec Direct2D ?

Cette case activée n’est nécessaire que si vous utilisez l’effet Direct2D YCbCr pour afficher le contenu YCbCr. Direct2D stocke les données YCbCr à l’aide des formats de pixels DXGI_FORMAT_R8_UNORM et DXGI_FORMAT_R8G8_UNORM, qui ne sont pas disponibles à partir de tous les pilotes graphiques.

Avant d’utiliser l’effet d’image YCbCr , vous devez appeler ID2D1DeviceContext::IsDxgiFormatSupported pour vous assurer que les deux formats sont pris en charge par le pilote.

Exemple de code

Voici un exemple de code illustrant les vérifications recommandées. Cet exemple est tiré des optimisations JPEG YCbCr dans Direct2D et 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));
}

Décodage des données de pixels YCbCr

Si vous souhaitez obtenir des données de pixels YCbCr , vous devez appeler IWICPlanarBitmapSourceTransform::CopyPixels. Cette méthode copie les données de pixels dans un tableau de structures WICBitmapPlane remplies, une pour chaque plan de données souhaité (par exemple, Y et CbCr). Un WICBitmapPlane contient des informations sur les données de pixels et pointe vers la mémoire tampon qui recevra les données.

Si vous souhaitez utiliser les données de pixels YCbCr avec d’autres API WIC, vous devez créer un IWICBitmap configuré de manière appropriée, appeler Lock pour obtenir la mémoire tampon sous-jacente et associer la mémoire tampon au WICBitmapPlane utilisé pour recevoir les données de pixels YCbCr . Vous pouvez ensuite utiliser le IWICBitmap normalement.

Enfin, si vous souhaitez afficher les données YCbCr dans Direct2D, vous devez créer un ID2D1Bitmap à partir de chaque IWICBitmap et les utiliser comme source pour l’effet d’image YCbCr . WIC vous permet de demander plusieurs configurations planaires. Lors de l’interopérabilité avec Direct2D, vous devez demander deux plans, l’un utilisant GUID_WICPixelFormat8bppY et l’autre utilisant GUID_WICPixelFormat16bppCbCr, car il s’agit de la configuration attendue par Direct2D.

Exemple de code

Voici un exemple de code illustrant les étapes de décodage et de rendu des données YCbCr dans Direct2D. Cet exemple est tiré des optimisations JPEG YCbCr dans Direct2D et 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();
}

Transformation des données de pixels YCbCr

La transformation des données YCbCr est presque identique au décodage, car les deux impliquent IWICPlanarBitmapSourceTransform. La seule différence est l’objet WIC à partir duquel vous avez obtenu l’interface. Le scaler fourni par Windows, le pivoteur tournant et la transformation de couleur prennent tous en charge l’accès YCbCr .

Chaînage de transformations ensemble

WIC prend en charge la notion de chaînage de plusieurs transformations. Par exemple, vous pouvez créer le pipeline WIC suivant :

diagramme d’un pipeline wic commençant par un décodeur jpeg.

Vous pouvez ensuite appeler QueryInterface sur IWICColorTransform pour obtenir IWICPlanarBitmapSourceTransform. La transformation de couleur peut communiquer avec les transformations précédentes et exposer les fonctionnalités d’agrégation de chaque étape du pipeline. WIC garantit que les données YCbCr sont conservées tout au long du processus. Ce chaînage fonctionne uniquement lors de l’utilisation de composants qui prennent en chargel’accèsYC b Cr .

Optimisations des codecs JPEG

À l’instar de l’implémentation du décodage de trame JPEG de IWICBitmapSourceTransform, l’implémentation de décodage de trame JPEG de IWICPlanarBitmapSourceTransform prend en charge la mise à l’échelle et la rotation du domaine JPEG DCT natifs. Vous pouvez demander une puissance de deux downscale ou une rotation directement à partir du décodeur JPEG. Cela se traduit généralement par une qualité et des performances supérieures à l’utilisation des transformations discrètes.

En outre, lorsque vous chaînez une ou plusieurs transformations WIC après le décodeur JPEG, il peut tirer parti de la mise à l’échelle et de la rotation JPEG natives pour satisfaire l’opération d’agrégation demandée.

Format Conversions

Utilisez IWICPlanarFormatConverter pour convertir les données de pixels YCbCr planaires en un format de pixel entrelacé tel que GUID_WICPixelFormat32bppPBGRA. WIC dans Windows 8.1 ne permet pas de convertir au format planaire YCbCr pixel.

Encodage des données de pixels YCbCr

Utilisez IWICPlanarBitmapFrameEncode pour encoder les données de pixels YCbCr dans l’encodeur JPEG. L’encodage des données YCbCrIWICPlanarBitmapFrameEncode est similaire, mais pas identique à l’encodage des données entrelacées à l’aide de IWICBitmapFrameEncode. L’interface planaire expose uniquement la possibilité d’écrire des données d’image de trame planaire, et vous devez continuer à utiliser l’interface d’encodage de trame pour définir des métadonnées ou une miniature et valider à la fin de l’opération.

Pour le cas classique, vous devez suivre les étapes suivantes :

  1. Obtenez le IWICBitmapFrameEncode comme d’habitude. Si vous souhaitez configurer le sous-échantillonnage chroma, définissez l’option d’encodeur JpegYCrCbSubsampling lors de la création du frame.
  2. Si vous devez définir des métadonnées ou une miniature, effectuez cette opération en utilisant IWICBitmapFrameEncode comme d’habitude.
  3. QueryInterface pour IWICPlanarBitmapFrameEncode.
  4. Définissez les données de pixels YCbCr à l’aide de IWICPlanarBitmapFrameEncode::WriteSource ou IWICPlanarBitmapFrameEncode::WritePixels. Contrairement à leurs équivalents IWICBitmapFrameEncode , vous fournissez à ces méthodes un tableau de IWICBitmapSource ou WICBitmapPlane qui contiennent les plans de pixels YCbCr .
  5. Lorsque vous avez terminé, appelez IWICBitmapFrameEncode::Commit.

Décodage des données de pixels YCbCr dans Windows 10

À compter de Windows 10 build 1507, Direct2D fournit ID2D1ImageSourceFromWic, un moyen plus simple de décoder des JPEG en Direct2D tout en tirant parti des optimisations YCbCr. ID2D1ImageSourceFromWic effectue automatiquement toutes les vérifications de capacité YCbCr nécessaires pour vous ; il utilise le codepath optimisé lorsque cela est possible, et utilise une solution de secours dans le cas contraire. Il permet également de nouvelles optimisations telles que la mise en cache uniquement des sous-régions de l’image qui sont nécessaires à la fois.

Pour plus d’informations sur l’utilisation de ID2D1ImageSourceFromWic, reportez-vous à l’exemple du Kit de développement logiciel (SDK) d’ajustement de photo Direct2D.