Поддержка JPEG YCbCr

Начиная с Windows 8.1, кодек JPEG компонента изображений Windows (WIC) поддерживает чтение и запись данных изображений в собственной форме YCbCr. Поддержку WIC YCbCr можно использовать в сочетании с Direct2D для отрисовки пиксельных данных YCbCr с эффектом изображения. Кроме того, кодек WIC JPEG может использовать пиксельные данные YCbCr , созданные определенными драйверами камеры через Media Foundation.

Данные пикселей YCbCR потребляют значительно меньше памяти, чем стандартные форматы пикселей BGRA. Кроме того, доступ к данным YCbCR позволяет разгрузить некоторые этапы конвейера декодирования и кодирования JPEG в Direct2D с ускорением GPU. С помощью YCbCr ваше приложение может сократить потребление памяти JPEG и время загрузки для изображений того же размера и качества. Кроме того, приложение может использовать изображения JPEG с более высоким разрешением без снижения производительности.

В этом разделе описывается, как работают данные YCbCr и как их использовать в WIC и Direct2D.

Сведения о данных JPEG YCbCr

В этом разделе описываются некоторые ключевые понятия, необходимые для понимания того, как работает поддержка YCbCr в WIC и ее основные преимущества.

Цветовая модель YCbCr

WIC в Windows 8 и более ранних версиях поддерживает четыре различные цветовые модели, наиболее распространенной из которых является RGB/BGR. Эта цветовая модель определяет цветовые данные с помощью компонентов красного, зеленого и синего цветов; также можно использовать четвертый альфа-компонент.

Вот изображение, разложенное на красный, зеленый и синий компоненты.

изображение, разложенное на красные, зеленые и синие компоненты.

YCbCr — это альтернативная цветовая модель, которая определяет цветовые данные с помощью компонента яркости (Y) и двух компонентов хрома (Cb и Cr). Обычно используется в сценариях создания цифровых изображений и видео. Термин YCbCr часто используется взаимозаменяемо с YUV, хотя они технически различаются.

Существует несколько вариантов YCbCr , которые отличаются цветовым пространством и определениями динамических диапазонов. WIC, в частности, поддерживает данные JPEG JFIF YCbCr . Дополнительные сведения см. в спецификации JPEG ITU-T81.

Ниже приведен образ, разделенный на компоненты Y, Cb и Cr .

изображение, разложенное на компоненты y, cb и cr.

Макеты плоской и чередуемой памяти

В этом разделе описываются некоторые различия между доступом к данным пикселей RGB и их хранением в памяти и данными YCbCR .

Данные в пикселях RGB обычно хранятся с помощью макета памяти с чередованием. Это означает, что данные для одного компонента цвета чередуются между пикселями, и каждый пиксель хранится непрерывно в памяти.

Ниже приведен рисунок, показывающий пиксельные данные RGBA, хранящиеся в макете памяти с чередованием.

Рисунок, показывающий rgba-пиксельные данные, хранящиеся в макете памяти с чередованием.

Данные YCbCR обычно хранятся с помощью макета планарной памяти. Это означает, что каждый компонент цвета хранится отдельно в отдельной смежных плоскостях, в общей сложности для трех плоскостей. В другой распространенной конфигурации компоненты Cb и Cr чередуются и хранятся вместе, а компонент Y остается в собственной плоскости, в общей сложности для двух плоскостей.

Вот рисунок, показывающий плоской Y и чередование данных пикселей CbCr , общий макет памяти YCbCr .

Рисунок, показывающий плоской y и данные пикселей с чередованием cbcr, общий макет памяти ycbcr.

В WIC и Direct2D каждая цветовая плоскость рассматривается как собственный отдельный объект ( IWICBitmapSource или ID2D1Bitmap), и вместе эти плоскости формируют резервные данные для изображения YCbCr .

Хотя WIC поддерживает доступ к данным YCbCr в конфигурациях плоскости 2 и 3, Direct2D поддерживает только первые (Y и CbCR). Поэтому при совместном использовании WIC и Direct2D всегда следует использовать конфигурацию YCbCR 2 плоскости.

Chroma Subsampling

Цветовая модель YCbCR хорошо подходит для сценариев создания цифровых изображений, так как она может использовать определенные аспекты визуальной системы человека. В частности, люди более чувствительны к изменениям яркости (яркости) изображения и менее чувствительны к хрома (цвету). Разделив данные о цвете на отдельные компоненты яркости и хрома, мы можем выборочно сжать только компоненты хрома, чтобы добиться экономии пространства с минимальной потерей качества.

Один из методов для этого называется chroma subsampling. Плоскости Cb и Cr имеют подвыбранные (пониженные масштабы) в одном или обоих горизонтальных и вертикальных измерениях. По историческим причинам каждый режим chroma subsampling обычно называется с использованием трехкомпонентного соотношения J:a:b.

Режим подсэмплинга Горизонтальное уменьшение масштаба Вертикальное уменьшение масштаба Бит на пиксель*
4:4:4 1x 1x 24
4:2:2 2x 1x 16
4:4:0 1x 2x 16
4:2:0 2x 2x 12

 

* Включает данные Y.

Из приведенной выше таблицы при использовании YCbCR для хранения несжатых данных изображений можно добиться экономии памяти от 25 % до 62,5 % по сравнению с 32 битами данных RGBA на пиксель в зависимости от того, какой режим хрома используется.

Использование JPEG YCbCr

На высоком уровне конвейер распаковки JPEG состоит из следующих этапов:

  1. Выполнение распаковки энтропии (например, Хаффман)
  2. Выполнение деквантизации
  3. Выполнение обратного дискретного преобразования косисинуса
  4. Выполнение chroma upsampling для данных CbCR
  5. Преобразование данных YCbCr в RGBA (при необходимости)

Если кодек JPEG создает данные YCbCr , мы можем избежать последних двух этапов процесса декодирования или отложить их на GPU. В дополнение к экономии памяти, указанной в предыдущем разделе, это значительно сокращает общее время, необходимое для декодирования изображения. Та же экономия применяется при кодировании данных YCbCr .

Использование данных JPEG YCbCr

В этом разделе объясняется, как использовать WIC и Direct2D для работы с данными YCbCR .

Инструкции из этого документа, используемые на практике, см. в примере оптимизации YCbCr JPEG в Direct2D и WIC , в котором показаны все шаги, необходимые для декодирования и отрисовки содержимого YCbCr в приложении Direct2D.

Использование изображений YCbCr JPEG

Подавляющее большинство изображений JPEG хранятся в формате YCbCr. Некоторые JPEG содержат данные CMYK или оттенков серого и не используют YCbCr. Это означает, что обычно, но не всегда, можно напрямую использовать уже существующее содержимое JPEG без каких-либо изменений.

WIC и Direct2D не поддерживают все возможные конфигурации YCbCr , а поддержка YCbCr в Direct2D зависит от базового графического оборудования и драйвера. По этой причине конвейер создания образов общего назначения должен быть надежным для образов, которые не используют YCbCr (включая другие распространенные форматы изображений, такие как PNG или BMP), или в случаях, когда поддержка YCbCr недоступна. Рекомендуется сохранить существующий конвейер образов на основе BGRA и включить YCbCr в качестве оптимизации производительности, если он доступен.

API-интерфейсы компонентов обработки образов Windows

WIC в Windows 8.1 добавляет три новых интерфейса для предоставления доступа к данным JPEG YCbCr.

IWICPlanarBitmapSourceTransform

IWICPlanarBitmapSourceTransform аналогичен IWICBitmapSourceTransform, за исключением того, что он создает пиксели в плоскостной конфигурации, включая данные YCbCr . Этот интерфейс можно получить, вызвав QueryInterface в реализации IWICBitmapSource , которая поддерживает планарный доступ. Сюда входит реализация кодека JPEG для IWICBitmapFrameDecode , а также IWICBitmapScaler, IWICBitmapFlipRotator и IWICColorTransform.

IWICPlanarBitmapFrameEncode

IWICPlanarBitmapFrameEncode предоставляет возможность кодировать плоские пиксельные данные, включая данные YCbCr . Этот интерфейс можно получить, вызвав QueryInterface в реализации кодека JPEG IWICBitmapFrameEncode.

IWICPlanarFormatConverter

IWICPlanarFormatConverter позволяет IWICFormatConverter использовать плоские пиксельные данные, включая YCbCr, и преобразовать их в формат с чередованием пикселей. Он не предоставляет возможность преобразования данных с чередованием пикселей в плоской формат. Этот интерфейс можно получить, вызвав QueryInterface в предоставленной Windows реализации IWICFormatConverter.

API Direct2D

Direct2D в Windows 8.1 поддерживает YCbCr плоский пиксель данных с новым эффектом изображения YCbCr . Этот эффект обеспечивает возможность отрисовки данных YCbCr . Эффект принимает в качестве входных данных два интерфейса ID2D1Bitmap : один из них содержит планарные данные Y в формате DXGI_FORMAT_R8_UNORM, а другой — чередующиеся данные CbCr в формате DXGI_FORMAT_R8G8_UNORM. Обычно этот эффект используется вместо ID2D1Bitmap , который содержал бы пиксельные данные BGRA.

Эффект изображения YCbCr предназначен для использования в сочетании с API WIC YCbCr , которые предоставляют данные YCbCr . Это эффективно действует для разгрузки некоторых операций декодирования с ЦП на GPU, где их можно обрабатывать гораздо быстрее и в параллельном режиме.

Определение поддержки конфигурации YCbCr

Как отмечалось ранее, ваше приложение должно быть надежным в тех случаях, когда поддержка YCbCr недоступна. В этом разделе рассматриваются условия, для которых приложение должно проверка. Если какая-либо из следующих проверок не пройдена, приложение должно вернуться к стандартному конвейеру на основе BGRA.

Поддерживает ли компонент WIC доступ к данным YCbCR ?

Доступ к данным YCbCR поддерживают только кодек JPEG, предоставленный Windows, и некоторые преобразования WIC. Полный список см. в разделе Api-интерфейсы компонентов обработки образов Windows .

Чтобы получить один из плоских интерфейсов YCbCr , вызовите QueryInterface в исходном интерфейсе. Это приведет к сбою, если компонент не поддерживает доступ к данным YCbCR .

Поддерживается ли запрошенный преобразование WIC для YCbCr?

После получения IWICPlanarBitmapSourceTransform необходимо сначала вызвать DoesSupportTransform. Этот метод принимает в качестве входных параметров полный набор преобразований, которые необходимо применить к данным плоских YCbCr , и возвращает логическое значение, указывающее на поддержку, а также ближайшие измерения к запрошенным размерам, которые могут быть возвращены. Перед доступом к пиксельным данным следует проверка все три значения с помощью IWICPlanarBitmapSourceTransform::CopyPixels.

Этот шаблон аналогичен использованию IWICBitmapSourceTransform .

Поддерживает ли графический драйвер функции, необходимые для использования YCbCr с Direct2D?

Это проверка необходимо только в том случае, если вы используете эффект Direct2D YCbCr для отрисовки содержимого YCbCr. Direct2D хранит данные YCbCR с использованием форматов DXGI_FORMAT_R8_UNORM и DXGI_FORMAT_R8G8_UNORM пикселей, которые доступны не во всех графических драйверах.

Перед использованием эффекта изображения YCbCr необходимо вызвать ID2D1DeviceContext::IsDxgiFormatSupported , чтобы убедиться, что драйвер поддерживает оба формата.

Образец кода

Ниже приведен пример кода, демонстрирующий рекомендуемые проверки. Этот пример взят из оптимизаций JPEG YCbCr в примере Direct2D и 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));
}

Декодирование пиксельных данных YCbCr

Если вы хотите получить пиксельные данные YCbCr, следует вызвать IWICPlanarBitmapSourceTransform::CopyPixels. Этот метод копирует пиксельные данные в массив заполненных структур WICBitmapPlane , по одному для каждой плоскости данных (например, Y и CbCR). WICBitmapPlane содержит сведения о пиксельных данных и указывает на буфер памяти, который будет получать данные.

Если вы хотите использовать пиксельные данные YCbCr с другими API WIC, создайте правильно настроенный IWICBitmap, вызовите Lock , чтобы получить базовый буфер памяти, и свяжите буфер с WICBitmapPlane, используемым для получения пиксельных данных YCbCr . Затем можно использовать IWICBitmap в обычном режиме.

Наконец, если вы хотите отобразить данные YCbCr в Direct2D, следует создать ID2D1Bitmap из каждого IWICBitmap и использовать их в качестве источника для эффекта изображения YCbCr . WIC позволяет запрашивать несколько планарных конфигураций. При взаимодействии с Direct2D следует запрашивать две плоскости, одна из них использует GUID_WICPixelFormat8bppY, а другая — GUID_WICPixelFormat16bppCbCr, так как это конфигурация, ожидаемая в Direct2D.

Образец кода

Ниже приведен пример кода, демонстрирующий шаги по декодированию и отрисовке данных YCbCr в Direct2D. Этот пример взят из оптимизаций JPEG YCbCr в примере Direct2D и 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();
}

Преобразование пиксельных данных YCbCr

Преобразование данных YCbCr почти идентично декодированию, так как оба они связаны с IWICPlanarBitmapSourceTransform. Единственное различие заключается в том, из какого объекта WIC вы получили интерфейс. В Windows предусмотрено средство масштабирования, вращатель переворачивания и преобразование цвета, поддерживается доступ YCbCr .

Объединение преобразований в цепочку

WIC поддерживает концепцию объединения нескольких преобразований. Например, можно создать следующий конвейер WIC:

Схема конвейера wic, начинающегося с декодера JPEG.

Затем можно вызвать QueryInterface в IWICColorTransform , чтобы получить IWICPlanarBitmapSourceTransform. Преобразование цвета может взаимодействовать с предыдущими преобразованиями и может предоставлять статистические возможности каждого этапа конвейера. WIC гарантирует, что данные YCbCR сохраняются в течение всего процесса. Эта цепочка работает только при использовании компонентов, поддерживающих доступ YCbCr .

Оптимизация кодека JPEG

Подобно реализации декодирования кадров JPEG в IWICBitmapSourceTransform, реализация декодирования кадров JPEG для IWICPlanarBitmapSourceTransform поддерживает масштабирование и поворот собственного домена JPEG DCT. Вы можете запросить мощность на два уменьшения масштаба или поворот непосредственно из декодера JPEG. Обычно это приводит к более высокому качеству и производительности, чем при использовании дискретных преобразований.

Кроме того, при связывании одного или нескольких преобразований WIC после декодера JPEG он может использовать собственное масштабирование и поворот JPEG для удовлетворения запрошенной статистической операции.

Преобразования формата

Используйте IWICPlanarFormatConverter для преобразования плоских данных пикселей YCbCr в формат с чередованием пикселей, например GUID_WICPixelFormat32bppPBGRA. WIC в Windows 8.1 не предоставляет возможность преобразования в плоской формат пикселей YCbCr.

Кодирование пиксельных данных YCbCr

Используйте IWICPlanarBitmapFrameEncode для кодирования данных пикселей YCbCr в кодировщике JPEG. Кодирование данных YCbCrIWICPlanarBitmapFrameEncode аналогично кодированию данных с чередованием с помощью IWICBitmapFrameEncode. Планарный интерфейс предоставляет только возможность записи данных изображения плоских кадров, и следует продолжать использовать интерфейс кодирования кадров для задания метаданных или эскиза и фиксации в конце операции.

В типичном случае необходимо выполнить следующие действия.

  1. Получите IWICBitmapFrameEncode в обычном режиме. Если вы хотите настроить подвыборку хрома, задайте параметр кодировщика JpegYCrCbSubsampling при создании кадра.
  2. Если вам нужно задать метаданные или эскиз, сделайте это с помощью IWICBitmapFrameEncode в обычном режиме.
  3. QueryInterface для IWICPlanarBitmapFrameEncode.
  4. Задайте пиксельные данные YCbCr с помощью IWICPlanarBitmapFrameEncode::WriteSource или IWICPlanarBitmapFrameEncode::WritePixels. В отличие от своих аналогов IWICBitmapFrameEncode , эти методы предоставляются с массивом IWICBitmapSource или WICBitmapPlane , который содержит плоскости пикселей YCbCr .
  5. По завершении вызовите IWICBitmapFrameEncode::Commit.

Декодирование пиксельных данных YCbCR в Windows 10

Начиная с Windows 10 сборки 1507, Direct2D предоставляет ID2D1ImageSourceFromWic, более простой способ декодирования JPEG в Direct2D с использованием оптимизации YCbCr. ID2D1ImageSourceFromWic автоматически выполняет все необходимые проверки возможностей YCbCr ; по возможности используется оптимизированный путь к коду, а в противном случае используется резервный путь. Он также позволяет выполнять новые оптимизации, такие как кэширование только подобласти изображения, которые требуются в данный момент времени.

Дополнительные сведения об использовании ID2D1ImageSourceFromWic см. в примере пакета SDK для Direct2D Photo Adjustment.