1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/YCbCrImageDataSerializer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,296 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/layers/YCbCrImageDataSerializer.h" 1.10 +#include <string.h> // for memcpy 1.11 +#include "gfx2DGlue.h" // for ToIntSize 1.12 +#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory 1.13 +#include "mozilla/gfx/BaseSize.h" // for BaseSize 1.14 +#include "mozilla/gfx/Types.h" 1.15 +#include "mozilla/mozalloc.h" // for operator delete 1.16 +#include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc 1.17 + 1.18 +#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3) 1.19 + 1.20 +namespace mozilla { 1.21 + 1.22 +using namespace gfx; 1.23 + 1.24 +namespace layers { 1.25 + 1.26 +// The Data is layed out as follows: 1.27 +// 1.28 +// +-----------------+ -++ --+ --+ <-- Beginning of the buffer 1.29 +// | YCbCrBufferInfo | | | | 1.30 +// +-----------------+ --+ | | 1.31 +// | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset 1.32 +// +-----------------+ ------+ | 1.33 +// | data | | 1.34 +// +-----------------+ ----------+ 1.35 +// | data | 1.36 +// +-----------------+ 1.37 +// 1.38 +// There can be padding between the blocks above to keep word alignment. 1.39 + 1.40 +// Structure written at the beginning og the data blob containing the image 1.41 +// (as shown in the figure above). It contains the necessary informations to 1.42 +// read the image in the blob. 1.43 +struct YCbCrBufferInfo 1.44 +{ 1.45 + uint32_t mYOffset; 1.46 + uint32_t mCbOffset; 1.47 + uint32_t mCrOffset; 1.48 + uint32_t mYStride; 1.49 + uint32_t mYWidth; 1.50 + uint32_t mYHeight; 1.51 + uint32_t mCbCrStride; 1.52 + uint32_t mCbCrWidth; 1.53 + uint32_t mCbCrHeight; 1.54 + StereoMode mStereoMode; 1.55 +}; 1.56 + 1.57 +static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData, size_t aDataSize) 1.58 +{ 1.59 + return aDataSize >= sizeof(YCbCrBufferInfo) 1.60 + ? reinterpret_cast<YCbCrBufferInfo*>(aData) 1.61 + : nullptr; 1.62 +} 1.63 + 1.64 +void YCbCrImageDataDeserializerBase::Validate() 1.65 +{ 1.66 + mIsValid = false; 1.67 + if (!mData) { 1.68 + return; 1.69 + } 1.70 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.71 + if (!info) { 1.72 + return; 1.73 + } 1.74 + size_t requiredSize = ComputeMinBufferSize( 1.75 + IntSize(info->mYWidth, info->mYHeight), 1.76 + info->mYStride, 1.77 + IntSize(info->mCbCrWidth, info->mCbCrHeight), 1.78 + info->mCbCrStride); 1.79 + mIsValid = requiredSize <= mDataSize; 1.80 + 1.81 +} 1.82 + 1.83 +uint8_t* YCbCrImageDataDeserializerBase::GetYData() 1.84 +{ 1.85 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.86 + return reinterpret_cast<uint8_t*>(info) + info->mYOffset; 1.87 +} 1.88 + 1.89 +uint8_t* YCbCrImageDataDeserializerBase::GetCbData() 1.90 +{ 1.91 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.92 + return reinterpret_cast<uint8_t*>(info) + info->mCbOffset; 1.93 +} 1.94 + 1.95 +uint8_t* YCbCrImageDataDeserializerBase::GetCrData() 1.96 +{ 1.97 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.98 + return reinterpret_cast<uint8_t*>(info) + info->mCrOffset; 1.99 +} 1.100 + 1.101 +uint8_t* YCbCrImageDataDeserializerBase::GetData() 1.102 +{ 1.103 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.104 + return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); 1.105 +} 1.106 + 1.107 +uint32_t YCbCrImageDataDeserializerBase::GetYStride() 1.108 +{ 1.109 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.110 + return info->mYStride; 1.111 +} 1.112 + 1.113 +uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride() 1.114 +{ 1.115 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.116 + return info->mCbCrStride; 1.117 +} 1.118 + 1.119 +gfx::IntSize YCbCrImageDataDeserializerBase::GetYSize() 1.120 +{ 1.121 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.122 + return gfx::IntSize(info->mYWidth, info->mYHeight); 1.123 +} 1.124 + 1.125 +gfx::IntSize YCbCrImageDataDeserializerBase::GetCbCrSize() 1.126 +{ 1.127 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.128 + return gfx::IntSize(info->mCbCrWidth, info->mCbCrHeight); 1.129 +} 1.130 + 1.131 +StereoMode YCbCrImageDataDeserializerBase::GetStereoMode() 1.132 +{ 1.133 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.134 + return info->mStereoMode; 1.135 +} 1.136 + 1.137 +// Offset in bytes 1.138 +static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride) 1.139 +{ 1.140 + return MOZ_ALIGN_WORD(aHeight * aStride); 1.141 +} 1.142 + 1.143 +// Minimum required shmem size in bytes 1.144 +size_t 1.145 +YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, 1.146 + uint32_t aYStride, 1.147 + const gfx::IntSize& aCbCrSize, 1.148 + uint32_t aCbCrStride) 1.149 +{ 1.150 + return ComputeOffset(aYSize.height, aYStride) 1.151 + + 2 * ComputeOffset(aCbCrSize.height, aCbCrStride) 1.152 + + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); 1.153 +} 1.154 + 1.155 +// Minimum required shmem size in bytes 1.156 +size_t 1.157 +YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, 1.158 + const gfx::IntSize& aCbCrSize) 1.159 +{ 1.160 + return ComputeMinBufferSize(aYSize, aYSize.width, aCbCrSize, aCbCrSize.width); 1.161 +} 1.162 + 1.163 +// Offset in bytes 1.164 +static size_t ComputeOffset(uint32_t aSize) 1.165 +{ 1.166 + return MOZ_ALIGN_WORD(aSize); 1.167 +} 1.168 + 1.169 +// Minimum required shmem size in bytes 1.170 +size_t 1.171 +YCbCrImageDataDeserializerBase::ComputeMinBufferSize(uint32_t aSize) 1.172 +{ 1.173 + return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); 1.174 +} 1.175 + 1.176 +void 1.177 +YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset, 1.178 + uint32_t aCbOffset, 1.179 + uint32_t aCrOffset, 1.180 + uint32_t aYStride, 1.181 + uint32_t aCbCrStride, 1.182 + const gfx::IntSize& aYSize, 1.183 + const gfx::IntSize& aCbCrSize, 1.184 + StereoMode aStereoMode) 1.185 +{ 1.186 + YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize); 1.187 + MOZ_ASSERT(info); // OK to assert here, this method is client-side-only 1.188 + uint32_t info_size = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); 1.189 + info->mYOffset = info_size + aYOffset; 1.190 + info->mCbOffset = info_size + aCbOffset; 1.191 + info->mCrOffset = info_size + aCrOffset; 1.192 + info->mYStride = aYStride; 1.193 + info->mYWidth = aYSize.width; 1.194 + info->mYHeight = aYSize.height; 1.195 + info->mCbCrStride = aCbCrStride; 1.196 + info->mCbCrWidth = aCbCrSize.width; 1.197 + info->mCbCrHeight = aCbCrSize.height; 1.198 + info->mStereoMode = aStereoMode; 1.199 + Validate(); 1.200 +} 1.201 + 1.202 +void 1.203 +YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYStride, 1.204 + uint32_t aCbCrStride, 1.205 + const gfx::IntSize& aYSize, 1.206 + const gfx::IntSize& aCbCrSize, 1.207 + StereoMode aStereoMode) 1.208 +{ 1.209 + uint32_t yOffset = 0; 1.210 + uint32_t cbOffset = yOffset + MOZ_ALIGN_WORD(aYStride * aYSize.height); 1.211 + uint32_t crOffset = cbOffset + MOZ_ALIGN_WORD(aCbCrStride * aCbCrSize.height); 1.212 + return InitializeBufferInfo(yOffset, cbOffset, crOffset, 1.213 + aYStride, aCbCrStride, aYSize, aCbCrSize, aStereoMode); 1.214 +} 1.215 + 1.216 +void 1.217 +YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize, 1.218 + const gfx::IntSize& aCbCrSize, 1.219 + StereoMode aStereoMode) 1.220 +{ 1.221 + return InitializeBufferInfo(aYSize.width, aCbCrSize.width, aYSize, aCbCrSize, aStereoMode); 1.222 +} 1.223 + 1.224 +static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) { 1.225 + for (uint32_t i = 0; i < len; ++i) { 1.226 + *dst = *src; 1.227 + src += 1 + skip; 1.228 + ++dst; 1.229 + } 1.230 +} 1.231 + 1.232 +bool 1.233 +YCbCrImageDataSerializer::CopyData(const uint8_t* aYData, 1.234 + const uint8_t* aCbData, const uint8_t* aCrData, 1.235 + gfx::IntSize aYSize, uint32_t aYStride, 1.236 + gfx::IntSize aCbCrSize, uint32_t aCbCrStride, 1.237 + uint32_t aYSkip, uint32_t aCbCrSkip) 1.238 +{ 1.239 + if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) { 1.240 + return false; 1.241 + } 1.242 + for (int i = 0; i < aYSize.height; ++i) { 1.243 + if (aYSkip == 0) { 1.244 + // fast path 1.245 + memcpy(GetYData() + i * GetYStride(), 1.246 + aYData + i * aYStride, 1.247 + aYSize.width); 1.248 + } else { 1.249 + // slower path 1.250 + CopyLineWithSkip(aYData + i * aYStride, 1.251 + GetYData() + i * GetYStride(), 1.252 + aYSize.width, aYSkip); 1.253 + } 1.254 + } 1.255 + for (int i = 0; i < aCbCrSize.height; ++i) { 1.256 + if (aCbCrSkip == 0) { 1.257 + // fast path 1.258 + memcpy(GetCbData() + i * GetCbCrStride(), 1.259 + aCbData + i * aCbCrStride, 1.260 + aCbCrSize.width); 1.261 + memcpy(GetCrData() + i * GetCbCrStride(), 1.262 + aCrData + i * aCbCrStride, 1.263 + aCbCrSize.width); 1.264 + } else { 1.265 + // slower path 1.266 + CopyLineWithSkip(aCbData + i * aCbCrStride, 1.267 + GetCbData() + i * GetCbCrStride(), 1.268 + aCbCrSize.width, aCbCrSkip); 1.269 + CopyLineWithSkip(aCrData + i * aCbCrStride, 1.270 + GetCrData() + i * GetCbCrStride(), 1.271 + aCbCrSize.width, aCbCrSkip); 1.272 + } 1.273 + } 1.274 + return true; 1.275 +} 1.276 + 1.277 +TemporaryRef<DataSourceSurface> 1.278 +YCbCrImageDataDeserializer::ToDataSourceSurface() 1.279 +{ 1.280 + RefPtr<DataSourceSurface> result = 1.281 + Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8); 1.282 + 1.283 + DataSourceSurface::MappedSurface map; 1.284 + result->Map(DataSourceSurface::MapType::WRITE, &map); 1.285 + 1.286 + gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(), 1.287 + map.mData, 1.288 + 0, 0, //pic x and y 1.289 + GetYSize().width, GetYSize().height, 1.290 + GetYStride(), GetCbCrStride(), 1.291 + map.mStride, 1.292 + gfx::YV12); 1.293 + result->Unmap(); 1.294 + return result.forget(); 1.295 +} 1.296 + 1.297 + 1.298 +} // namespace 1.299 +} // namespace