Dukungan JPEG YCbCr

Dimulai dengan Windows 8.1, codec JPEG Windows Imaging Component (WIC) mendukung pembacaan dan penulisan data gambar dalam formulir YCbCr aslinya. Dukungan WIC YCbCr dapat digunakan bersama dengan Direct2D untuk merender data piksel YCbCr dengan efek gambar. Selain itu, codec WIC JPEG dapat menggunakan data piksel YCbCr yang diproduksi oleh driver kamera tertentu melalui Media Foundation.

Data piksel YCbCr mengonsumsi memori yang jauh lebih sedikit daripada format piksel BGRA standar. Selain itu, mengakses data YCbCr memungkinkan Anda untuk membongkar beberapa tahap alur dekode/enkode JPEG ke Direct2D yang dipercepat GPU. Dengan menggunakan YCbCr, aplikasi Anda dapat mengurangi konsumsi memori JPEG dan waktu muat untuk ukuran dan gambar berkualitas yang sama. Atau, aplikasi Anda dapat menggunakan gambar JPEG resolusi yang lebih tinggi tanpa menderita penalti performa.

Topik ini menjelaskan cara kerja data YCbCr dan cara menggunakannya di WIC dan Direct2D.

Tentang JPEG YCbCr Data

Bagian ini menjelaskan beberapa konsep utama yang diperlukan untuk memahami cara kerja dukungan YCbCr di WIC dan manfaat utamanya.

Model Warna YCbCr

WIC di Windows 8 dan yang lebih lama mendukung empat model warna yang berbeda, yang paling umum adalah RGB/BGR. Model warna ini mendefinisikan data warna menggunakan komponen merah, hijau, dan biru; komponen alfa keempat juga dapat digunakan.

Berikut adalah gambar yang diurai menjadi komponen merah, hijau, dan birunya.

gambar terurai menjadi komponen merah, hijau, dan biru.

YCbCr adalah model warna alternatif yang mendefinisikan data warna menggunakan komponen luminance (Y) dan dua komponen krominasi (Cb dan Cr). Ini umumnya digunakan dalam skenario pencitraan digital dan video. Istilah YCbCr sering digunakan secara bergantian dengan YUV, meskipun keduanya secara teknis berbeda.

Ada beberapa variasi YCbCr yang berbeda dalam ruang warna dan definisi rentang dinamis - WIC secara khusus mendukung data JPEG JFIF YCbCr . Untuk informasi selengkapnya, lihat spesifikasi JPEG ITU-T81.

Berikut adalah gambar yang diurai ke dalam komponen Y, Cb, dan Cr-nya .

gambar diurai menjadi komponen y, cb, dan cr.

Planar Versus Tata Letak Memori Interleaved

Bagian ini menjelaskan beberapa perbedaan antara mengakses dan menyimpan data piksel RGB dalam memori versus data YCbCr .

Data piksel RGB biasanya disimpan menggunakan tata letak memori yang saling berhubungan. Ini berarti bahwa data untuk komponen warna tunggal diselingi antara piksel, dan setiap piksel disimpan secara berdampingan dalam memori.

Berikut adalah gambar yang menunjukkan data piksel RGBA yang disimpan dalam tata letak memori yang saling terkait.

gambar yang menunjukkan data piksel rgba yang disimpan dalam tata letak memori yang saling terkait.

Data YCbCr biasanya disimpan menggunakan tata letak memori planar. Ini berarti bahwa setiap komponen warna disimpan secara terpisah dalam bidangnya sendiri yang bersebelahan, dengan total tiga bidang. Dalam konfigurasi umum lainnya, komponen Cb dan Cr saling terkait dan disimpan bersama-sama, sementara komponen Y tetap berada di bidangnya sendiri, dengan total dua bidang.

Berikut adalah gambar yang menunjukkan planar Y dan data piksel CbCr interleaved, tata letak memori YCbCr umum.

gambar yang menunjukkan data piksel cbcr planar y dan interleaved cbcr, tata letak memori ycbcr umum.

Dalam WIC dan Direct2D, setiap bidang warna diperlakukan sebagai objek yang berbeda sendiri (baik IWICBitmapSource atau ID2D1Bitmap), dan secara kolektif bidang ini membentuk data cadangan untuk gambar YCbCr .

Sementara WIC mendukung akses data YCbCr dalam konfigurasi bidang 2 dan 3, Direct2D hanya mendukung yang pertama (Y dan CbCr). Oleh karena itu, saat menggunakan WIC dan Direct2D bersama-sama, Anda harus selalu menggunakan konfigurasi 2 plane YCbCr .

Chroma Subsampling

Model warna YCbCr sangat cocok untuk skenario pencitraan digital karena dapat memanfaatkan aspek tertentu dari sistem visual manusia. Secara khusus, manusia lebih sensitif terhadap perubahan luminasi (kecerahan) gambar dan kurang sensitif terhadap krominasi (warna). Dengan membagi data warna menjadi komponen luminance dan krominasi terpisah, kita dapat secara selektif memadatkan hanya komponen krominasi untuk mencapai penghematan ruang dengan kerugian minimal dalam kualitas.

Salah satu teknik untuk melakukan ini disebut subsampling chroma. Bidang Cb dan Cr disubsampel (diturunkan skalanya) dalam satu atau kedua dimensi horizontal dan vertikal. Untuk alasan historis, setiap mode subsampling chroma umumnya disebut menggunakan rasio tiga bagian J:a:b.

Mode subsampling Skala bawah horizontal Skala bawah vertikal Bit per piksel*
4:4:4 1x 1x 24
4:2:2 2x 1x 16
4:4:0 1x 2x 16
4:2:0 2x 2x 12

 

* Termasuk data Y.

Dari tabel di atas, jika Anda menggunakan YCbCr untuk menyimpan data gambar yang tidak dikompresi, Anda dapat mencapai penghematan memori 25% hingga 62,5% versus 32 bit per piksel data RGBA, tergantung pada mode subsampling chroma mana yang digunakan.

Penggunaan JPEG YCbCr

Pada tingkat tinggi, alur dekompresi JPEG terdiri dari tahap-tahap berikut:

  1. Lakukan dekompresi entropi (misalnya Huffman)
  2. Melakukan dequantization
  3. Melakukan transformasi kosinus diskrit terbalik
  4. Melakukan upsampling klorma pada data CbCr
  5. Mengonversi data YCbCr ke RGBA (jika diperlukan)

Dengan meminta codec JPEG menghasilkan data YCbCr , kita dapat menghindari dua langkah akhir dari proses dekode, atau menundanya ke GPU. Selain penghematan memori yang tercantum di bagian sebelumnya, ini secara signifikan mengurangi waktu keseluruhan yang diperlukan untuk mendekode gambar. Penghematan yang sama berlaku saat mengodekan data YCbCr .

Menggunakan DATA JPEG YCbCr

Bagian ini menjelaskan cara menggunakan WIC dan Direct2D untuk beroperasi pada data YCbCr .

Untuk melihat panduan dari dokumen ini yang digunakan dalam praktiknya, lihat pengoptimalan JPEG YCbCr dalam sampel Direct2D dan WIC yang menunjukkan semua langkah yang diperlukan untuk mendekode dan merender konten YCbCr di aplikasi Direct2D.

Menggunakan gambar YCbCr JPEG

Sebagian besar gambar JPEG disimpan sebagai YCbCr. Beberapa JPEG berisi data CMYK atau skala abu-abu dan tidak menggunakan YCbCr. Ini berarti bahwa Anda biasanya, tetapi tidak selalu, dapat langsung menggunakan konten JPEG yang sudah ada sebelumnya tanpa modifikasi apa pun.

WIC dan Direct2D tidak mendukung setiap kemungkinan konfigurasi YCbCr , dan dukungan YCbCr di Direct2D tergantung pada perangkat keras dan driver grafis yang mendasarinya. Karena itu, alur pencitraan tujuan umum harus kuat terhadap gambar yang tidak menggunakan YCbCr (termasuk format gambar umum lainnya seperti PNG atau BMP) atau ke kasus di mana dukungan YCbCr tidak tersedia. Kami menyarankan agar Anda menyimpan alur pencitraan berbasis BGRA yang ada dan mengaktifkan YCbCr sebagai pengoptimalan performa saat tersedia.

API Komponen Pencitraan Windows

WIC di Windows 8.1 menambahkan tiga antarmuka baru untuk menyediakan akses ke data JPEG YCbCr.

IWICPlanarBitmapSourceTransform

IWICPlanarBitmapSourceTransform dianalogikan dengan IWICBitmapSourceTransform, kecuali bahwa ia menghasilkan piksel dalam konfigurasi planar, termasuk data YCbCr . Anda dapat memperoleh antarmuka ini dengan memanggil QueryInterface pada implementasi IWICBitmapSource yang mendukung akses planar. Ini termasuk implementasi codec JPEG dari IWICBitmapFrameDecode serta IWICBitmapScaler, IWICBitmapFlipRotator, dan IWICColorTransform.

IWICPlanarBitmapFrameEncode

IWICPlanarBitmapFrameEncode menyediakan kemampuan untuk mengodekan data piksel planar, termasuk data YCbCr . Anda dapat memperoleh antarmuka ini dengan memanggil QueryInterface pada implementasi codec JPEG dari IWICBitmapFrameEncode.

IWICPlanarFormatConverter

IWICPlanarFormatConverter memungkinkan IWICFormatConverter untuk menggunakan data piksel planar, termasuk YCbCr, dan mengonversinya ke format piksel yang saling terkait. Ini tidak mengekspos kemampuan untuk mengonversi data piksel yang saling terkait ke format planar. Anda dapat memperoleh antarmuka ini dengan memanggil QueryInterface pada implementasi IWICFormatConverter yang disediakan Windows.

API Direct2D

Direct2D di Windows 8.1 mendukung data piksel planar YCbC r dengan efek gambar YCbCr baru . Efek ini memberikan kemampuan untuk merender data YCbCr . Efeknya mengambil sebagai input dua antarmuka ID2D1Bitmap : satu berisi data planar Y dalam format DXGI_FORMAT_R8_UNORM, dan satu yang berisi data CbCr yang saling terkait dalam format DXGI_FORMAT_R8G8_UNORM. Anda biasanya menggunakan efek ini sebagai pengganti ID2D1Bitmap yang akan berisi data piksel BGRA.

Efek gambar YCbCr dimaksudkan untuk digunakan bersama dengan WIC YCbCr API yang menyediakan data YCbCr . Tindakan ini secara efektif bertindak untuk membongkar beberapa pekerjaan dekode dari CPU ke GPU, di mana dapat diproses jauh lebih cepat dan paralel.

Menentukan apakah Konfigurasi YCbCr Didukung

Seperti disebutkan sebelumnya, aplikasi Anda harus kuat untuk kasus di mana dukungan YCbCr tidak tersedia. Bagian ini membahas kondisi yang harus diperiksa aplikasi Anda. Jika salah satu pemeriksaan berikut gagal, aplikasi Anda harus kembali ke alur standar berbasis BGRA.

Apakah komponen WIC mendukung akses data YCbCr ?

Hanya codec JPEG yang disediakan Windows dan transformasi WIC tertentu yang mendukung akses data YCbCr . Untuk daftar lengkapnya, lihat bagian API Komponen Pencitraan Windows .

Untuk mendapatkan salah satu antarmuka YCbCr planar, panggil QueryInterface pada antarmuka asli. Ini akan gagal jika komponen tidak mendukung akses data YCbCr .

Apakah transformasi WIC yang diminta didukung untuk YCbCr?

Setelah mendapatkan IWICPlanarBitmapSourceTransform, Anda harus terlebih dahulu memanggil DoesSupportTransform. Metode ini mengambil parameter input kumpulan transformasi lengkap yang ingin Anda terapkan ke data planar YCbCr , dan mengembalikan Boolean yang menunjukkan dukungan, serta dimensi terdekat dengan ukuran yang diminta yang dapat dikembalikan. Anda harus memeriksa ketiga nilai sebelum mengakses data piksel dengan IWICPlanarBitmapSourceTransform::CopyPixels.

Pola ini mirip dengan bagaimana IWICBitmapSourceTransform digunakan.

Apakah driver grafis mendukung fitur yang diperlukan untuk menggunakan YCbCr dengan Direct2D?

Pemeriksaan ini hanya diperlukan jika Anda menggunakan efek Direct2D YCbCr untuk merender konten YCbCr . Direct2D menyimpan data YCbCr menggunakan format DXGI_FORMAT_R8_UNORM dan DXGI_FORMAT_R8G8_UNORM piksel, yang tidak tersedia dari semua driver grafis.

Sebelum menggunakan efek gambar YCbCr , Anda harus memanggil ID2D1DeviceContext::IsDxgiFormatSupported untuk memastikan bahwa kedua format didukung oleh driver.

Kode sampel

Di bawah ini adalah contoh kode yang menunjukkan pemeriksaan yang direkomendasikan. Contoh ini diambil dari pengoptimalan JPEG YCbCr dalam sampel Direct2D dan 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));
}

Pendekodean Data Piksel YCbCr

Jika Anda ingin mendapatkan data piksel YCbCr , Anda harus memanggil IWICPlanarBitmapSourceTransform::CopyPixels. Metode ini menyalin data piksel ke dalam array struktur WICBitmapPlane yang diisi, satu untuk setiap bidang data yang Anda inginkan (misalnya, Y dan CbCr). WICBitmapPlane berisi info tentang data piksel dan menunjuk ke buffer memori yang akan menerima data.

Jika Anda ingin menggunakan data piksel YCbCr dengan API WIC lainnya, Anda harus membuat IWICBitmap yang dikonfigurasi dengan tepat, panggil Kunci untuk mendapatkan buffer memori yang mendasarinya, dan mengaitkan buffer dengan WICBitmapPlane yang digunakan untuk menerima data piksel YCbCr . Anda kemudian dapat menggunakan IWICBitmap secara normal.

Terakhir, jika Anda ingin merender data YCbCr di Direct2D, Anda harus membuat ID2D1Bitmap dari setiap IWICBitmap dan menggunakannya sebagai sumber untuk efek gambar YCbCr . WIC memungkinkan Anda untuk meminta beberapa konfigurasi planar. Saat beroperasi dengan Direct2D, Anda harus meminta dua bidang, satu menggunakan GUID_WICPixelFormat8bppY dan yang lain menggunakan GUID_WICPixelFormat16bppCbCr, karena ini adalah konfigurasi yang diharapkan oleh Direct2D.

Sampel Kode

Di bawah ini adalah contoh kode yang menunjukkan langkah-langkah untuk mendekode dan merender data YCbCr di Direct2D. Contoh ini diambil dari pengoptimalan JPEG YCbCr dalam sampel Direct2D dan 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();
}

Mengubah Data Piksel YCbCr

Mengubah data YCbCr hampir identik dengan decoding, karena keduanya melibatkan IWICPlanarBitmapSourceTransform. Satu-satunya perbedaan adalah objek WIC tempat Anda mendapatkan antarmuka. Scaler yang disediakan Windows, flip rotator, dan transformasi warna semuanya mendukung akses YCbCr .

Menautkan Transformasi Bersama

WIC mendukung gagasan penautan bersama-sama beberapa transformasi. Misalnya, Anda dapat membuat alur WIC berikut:

diagram alur wic yang dimulai dengan dekoder jpeg.

Anda kemudian dapat memanggil QueryInterface pada IWICColorTransform untuk mendapatkan IWICPlanarBitmapSourceTransform. Transformasi warna dapat berkomunikasi dengan transformasi sebelumnya dan dapat mengekspos kemampuan agregat setiap tahap dalam alur. WIC memastikan bahwa data YCbCr dipertahankan melalui seluruh proses. Penautan ini hanya berfungsi saat menggunakan komponen yang mendukung akses YCbCr .

Pengoptimalan Codec JPEG

Mirip dengan implementasi dekode bingkai JPEG dari IWICBitmapSourceTransform, implementasi dekode bingkai JPEG dari IWICPlanarBitmapSourceTransform mendukung penskalaan dan rotasi domain JPEG DCT asli. Anda dapat meminta daya dua downscale atau rotasi langsung dari dekoder JPEG. Ini biasanya menghasilkan kualitas dan performa yang lebih tinggi daripada menggunakan transformasi diskrit.

Selain itu, ketika Anda menautkan satu atau beberapa WIC berubah setelah decoder JPEG, itu dapat memanfaatkan penskalaan dan rotasi JPEG asli untuk memenuhi operasi yang diminta agregat.

Konversi Format

Gunakan IWICPlanarFormatConverter untuk mengonversi data piksel YCbCr planar ke format piksel yang saling terkait seperti GUID_WICPixelFormat32bppPBGRA. WIC dalam Windows 8.1 tidak menyediakan kemampuan untuk mengonversi ke format piksel YCbCr planar.

Pengodean Data Piksel YCbCr

Gunakan IWICPlanarBitmapFrameEncode untuk mengodekan data piksel YCbCr ke encoder JPEG. Pengodean data YCbCrIWICPlanarBitmapFrameEncode serupa tetapi tidak identik dengan pengodean data yang saling terkait menggunakan IWICBitmapFrameEncode. Antarmuka planar hanya mengekspos kemampuan untuk menulis data gambar bingkai planar, dan Anda harus terus menggunakan antarmuka enkode bingkai untuk mengatur metadata atau gambar mini dan untuk berkomitmen di akhir operasi.

Untuk kasus umum, Anda harus mengikuti langkah-langkah berikut:

  1. Dapatkan IWICBitmapFrameEncode seperti biasa. Jika Anda ingin mengonfigurasi subsampling chroma, atur opsi encoder JpegYCrCbSubsampling saat membuat bingkai.
  2. Jika Anda perlu mengatur metadata atau gambar mini, lakukan ini menggunakan IWICBitmapFrameEncode seperti biasa.
  3. QueryInterface untuk IWICPlanarBitmapFrameEncode.
  4. Atur data piksel YCbCr menggunakan IWICPlanarBitmapFrameEncode::WriteSource atau IWICPlanarBitmapFrameEncode::WritePixels. Tidak seperti rekan IWICBitmapFrameEncode mereka, Anda menyediakan metode ini dengan array IWICBitmapSource atau WICBitmapPlane yang berisi bidang piksel YCbCr .
  5. Setelah selesai, hubungi IWICBitmapFrameEncode::Commit.

Mendekode data piksel YCbCr dalam Windows 10

Mulai dari Windows 10 build 1507, Direct2D menyediakan ID2D1ImageSourceFromWic, cara yang lebih sederhana untuk mendekode JPEG ke Direct2D sambil memanfaatkan pengoptimalan YCbCr. ID2D1ImageSourceFromWic secara otomatis melakukan semua pemeriksaan kemampuan YCbCr yang diperlukan untuk Anda; ini menggunakan codepath yang dioptimalkan jika memungkinkan, dan menggunakan fallback sebaliknya. Ini juga memungkinkan pengoptimalan baru seperti hanya subregion penembolokan gambar yang diperlukan pada satu waktu.

Untuk informasi selengkapnya tentang menggunakan ID2D1ImageSourceFromWic, lihat sampel Direct2D Photo Adjustment SDK.