ImageUtils.cpp (7037B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/ImageUtils.h" 8 9 #include "ImageContainer.h" 10 #include "Intervals.h" 11 #include "mozilla/dom/ImageBitmapBinding.h" 12 13 using namespace mozilla::layers; 14 using namespace mozilla::gfx; 15 16 namespace mozilla::dom { 17 18 static Maybe<ImageBitmapFormat> GetImageBitmapFormatFromSurfaceFromat( 19 SurfaceFormat aSurfaceFormat) { 20 switch (aSurfaceFormat) { 21 case SurfaceFormat::B8G8R8A8: 22 case SurfaceFormat::B8G8R8X8: 23 return Some(ImageBitmapFormat::BGRA32); 24 case SurfaceFormat::R8G8B8A8: 25 case SurfaceFormat::R8G8B8X8: 26 return Some(ImageBitmapFormat::RGBA32); 27 case SurfaceFormat::R8G8B8: 28 return Some(ImageBitmapFormat::RGB24); 29 case SurfaceFormat::B8G8R8: 30 return Some(ImageBitmapFormat::BGR24); 31 case SurfaceFormat::HSV: 32 return Some(ImageBitmapFormat::HSV); 33 case SurfaceFormat::Lab: 34 return Some(ImageBitmapFormat::Lab); 35 case SurfaceFormat::Depth: 36 return Some(ImageBitmapFormat::DEPTH); 37 case SurfaceFormat::A8: 38 return Some(ImageBitmapFormat::GRAY8); 39 case SurfaceFormat::R5G6B5_UINT16: 40 case SurfaceFormat::R10G10B10A2_UINT32: 41 case SurfaceFormat::R10G10B10X2_UINT32: 42 case SurfaceFormat::R16G16B16A16F: 43 case SurfaceFormat::YUV420: 44 case SurfaceFormat::NV12: 45 case SurfaceFormat::P010: 46 case SurfaceFormat::P016: 47 case SurfaceFormat::UNKNOWN: 48 default: 49 return Nothing(); 50 } 51 } 52 53 static Maybe<ImageBitmapFormat> GetImageBitmapFormatFromPlanarYCbCrData( 54 layers::PlanarYCbCrData const* aData) { 55 MOZ_ASSERT(aData); 56 57 auto ySize = aData->YDataSize(); 58 auto cbcrSize = aData->CbCrDataSize(); 59 media::Interval<uintptr_t> YInterval( 60 uintptr_t(aData->mYChannel), 61 uintptr_t(aData->mYChannel) + ySize.height * aData->mYStride), 62 CbInterval( 63 uintptr_t(aData -> mCbChannel), 64 uintptr_t(aData->mCbChannel) + cbcrSize.height * aData->mCbCrStride), 65 CrInterval( 66 uintptr_t(aData->mCrChannel), 67 uintptr_t(aData->mCrChannel) + cbcrSize.height * aData->mCbCrStride); 68 if (aData->mYSkip == 0 && aData->mCbSkip == 0 && 69 aData->mCrSkip == 0) { // Possibly three planes. 70 if (!YInterval.Intersects(CbInterval) && 71 !CbInterval.Intersects(CrInterval)) { // Three planes. 72 switch (aData->mChromaSubsampling) { 73 case ChromaSubsampling::FULL: 74 return Some(ImageBitmapFormat::YUV444P); 75 case ChromaSubsampling::HALF_WIDTH: 76 return Some(ImageBitmapFormat::YUV422P); 77 case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT: 78 return Some(ImageBitmapFormat::YUV420P); 79 default: 80 break; 81 } 82 } 83 } else if (aData->mYSkip == 0 && aData->mCbSkip == 1 && aData->mCrSkip == 1 && 84 aData->mChromaSubsampling == 85 ChromaSubsampling::HALF_WIDTH_AND_HEIGHT) { // Possibly two 86 // planes. 87 if (!YInterval.Intersects(CbInterval) && 88 aData->mCbChannel == aData->mCrChannel - 1) { // Two planes. 89 return Some(ImageBitmapFormat::YUV420SP_NV12); // Y-Cb-Cr 90 } else if (!YInterval.Intersects(CrInterval) && 91 aData->mCrChannel == aData->mCbChannel - 1) { // Two planes. 92 return Some(ImageBitmapFormat::YUV420SP_NV21); // Y-Cr-Cb 93 } 94 } 95 96 return Nothing(); 97 } 98 99 // ImageUtils::Impl implements the _generic_ algorithm which always readback 100 // data in RGBA format into CPU memory. 101 // Since layers::CairoImage is just a warpper to a DataSourceSurface, the 102 // implementation of CairoSurfaceImpl is nothing different to the generic 103 // version. 104 class ImageUtils::Impl { 105 public: 106 explicit Impl(layers::Image* aImage) : mImage(aImage), mSurface(nullptr) {} 107 108 virtual ~Impl() = default; 109 110 virtual Maybe<ImageBitmapFormat> GetFormat() const { 111 if (DataSourceSurface* surface = Surface()) { 112 return GetImageBitmapFormatFromSurfaceFromat(surface->GetFormat()); 113 } 114 return Nothing(); 115 } 116 117 virtual uint32_t GetBufferLength() const { 118 if (DataSourceSurface* surface = Surface()) { 119 DataSourceSurface::ScopedMap map(surface, DataSourceSurface::READ); 120 const uint32_t stride = map.GetStride(); 121 const IntSize size = surface->GetSize(); 122 return (uint32_t)(size.height * stride); 123 } 124 return 0; 125 } 126 127 protected: 128 Impl() = default; 129 130 DataSourceSurface* Surface() const { 131 if (mSurface) { 132 return mSurface.get(); 133 } 134 135 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface(); 136 if (NS_WARN_IF(!surface)) { 137 return nullptr; 138 } 139 140 mSurface = surface->GetDataSurface(); 141 MOZ_ASSERT(mSurface); 142 return mSurface.get(); 143 } 144 145 RefPtr<layers::Image> mImage; 146 mutable RefPtr<DataSourceSurface> mSurface; 147 }; 148 149 // YUVImpl is optimized for the layers::PlanarYCbCrImage and layers::NVImage. 150 // This implementation does not readback data in RGBA format but keep it in YUV 151 // format family. 152 class YUVImpl final : public ImageUtils::Impl { 153 public: 154 explicit YUVImpl(layers::Image* aImage) : Impl(aImage) { 155 MOZ_ASSERT(aImage->GetFormat() == ImageFormat::PLANAR_YCBCR || 156 aImage->GetFormat() == ImageFormat::NV_IMAGE); 157 } 158 159 Maybe<ImageBitmapFormat> GetFormat() const override { 160 return GetImageBitmapFormatFromPlanarYCbCrData(GetPlanarYCbCrData()); 161 } 162 163 uint32_t GetBufferLength() const override { 164 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { 165 return mImage->AsPlanarYCbCrImage()->GetDataSize(); 166 } 167 return mImage->AsNVImage()->GetBufferSize(); 168 } 169 170 private: 171 const PlanarYCbCrData* GetPlanarYCbCrData() const { 172 if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { 173 return mImage->AsPlanarYCbCrImage()->GetData(); 174 } 175 return mImage->AsNVImage()->GetData(); 176 } 177 }; 178 179 // TODO: optimize for other platforms. 180 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl. 181 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl 182 // EGLImageImpl and OverlayImegImpl. 183 184 ImageUtils::ImageUtils(layers::Image* aImage) : mImpl(nullptr) { 185 MOZ_ASSERT(aImage, "Create ImageUtils with nullptr."); 186 switch (aImage->GetFormat()) { 187 case mozilla::ImageFormat::PLANAR_YCBCR: 188 case mozilla::ImageFormat::NV_IMAGE: 189 mImpl = new YUVImpl(aImage); 190 break; 191 case mozilla::ImageFormat::MOZ2D_SURFACE: 192 default: 193 mImpl = new Impl(aImage); 194 } 195 } 196 197 ImageUtils::~ImageUtils() { 198 if (mImpl) { 199 delete mImpl; 200 mImpl = nullptr; 201 } 202 } 203 204 Maybe<ImageBitmapFormat> ImageUtils::GetFormat() const { 205 MOZ_ASSERT(mImpl); 206 return mImpl->GetFormat(); 207 } 208 209 uint32_t ImageUtils::GetBufferLength() const { 210 MOZ_ASSERT(mImpl); 211 return mImpl->GetBufferLength(); 212 } 213 214 } // namespace mozilla::dom