Chromium Code Reviews| Index: blimp/common/compositor/blimp_remote_image_serializer.cc |
| diff --git a/blimp/common/compositor/blimp_remote_image_serializer.cc b/blimp/common/compositor/blimp_remote_image_serializer.cc |
| index 562c70d2f75401953f4eb022c6c48e42f0b07b23..1db3a6ef1a745a8f849e91552ad7c3eb5c0ff3b4 100644 |
| --- a/blimp/common/compositor/blimp_remote_image_serializer.cc |
| +++ b/blimp/common/compositor/blimp_remote_image_serializer.cc |
| @@ -4,18 +4,145 @@ |
| #include "blimp/common/compositor/blimp_remote_image_serializer.h" |
| +#include <stddef.h> |
| +#include <vector> |
| + |
| +#include "third_party/libwebp/webp/encode.h" |
| +#include "third_party/skia/include/core/SkData.h" |
| #include "third_party/skia/include/core/SkPixelSerializer.h" |
| +namespace { |
| +// TODO(nyquist): Make sure encoder does not serialize images more than once. |
| +// See crbug.com/548434. |
| +class WebPImageEncoder : public SkPixelSerializer { |
| + public: |
| + WebPImageEncoder() {} |
| + ~WebPImageEncoder() override{}; |
| + |
| + bool onUseEncodedData(const void* data, size_t len) override { |
| + const unsigned char* cast_data = static_cast<const unsigned char*>(data); |
| + if (len < 10) |
|
urvang
2016/02/10 23:54:42
Don't you need first 14 bytes? (8 + 6)
nyquist
2016/02/11 05:19:23
Done.
|
| + return false; |
| + return !memcmp(cast_data, "RIFF", 4) && !memcmp(cast_data + 8, "WEBPVP", 6); |
| + } |
| + |
| + SkData* onEncode(const SkPixmap& pixmap) override { |
| + auto pixel_chars = static_cast<const unsigned char*>(pixmap.addr()); |
| + WebPConfig config; |
| + if (!WebPConfigInit(&config)) |
| + return nullptr; |
| + WebPPicture picture; |
| + if (!WebPPictureInit(&picture)) |
| + return nullptr; |
| + |
| + if (!pixmap.width() || pixmap.width() > WEBP_MAX_DIMENSION) |
| + return nullptr; |
| + picture.width = pixmap.width(); |
| + if (!pixmap.height() || pixmap.height() > WEBP_MAX_DIMENSION) |
| + return nullptr; |
| + picture.height = pixmap.height(); |
| + |
| + const bool has_alpha = pixmap.alphaType() != kOpaque_SkAlphaType; |
| + const bool premultiplied = |
| + has_alpha && pixmap.alphaType() == kPremul_SkAlphaType; |
| + if (premultiplied && |
| + !PlatformPremultipliedImportPicture(pixel_chars, &picture)) |
| + return nullptr; |
| + if (!premultiplied && !ImportPictureRGBA<false>(pixel_chars, &picture)) |
| + return nullptr; |
| + |
| + const int quality = 50; |
| + std::vector<unsigned char> data; |
| + picture.custom_ptr = &data; |
| + picture.writer = &WebPImageEncoder::WriteOutput; |
| + config.quality = quality; |
| + config.method = 3; |
| + |
| + bool success = WebPEncode(&config, &picture) != 0; |
|
urvang
2016/02/10 23:54:42
"!= 0" isn't really needed
nyquist
2016/02/11 05:19:23
Done.
|
| + WebPPictureFree(&picture); |
| + if (!success) |
| + return nullptr; |
| + return SkData::NewWithCopy(&data.front(), data.size()); |
| + } |
| + |
| + private: |
| + static int WriteOutput(const uint8_t* data, |
| + size_t size, |
| + const WebPPicture* const picture) { |
| + std::vector<unsigned char>* dest = |
| + static_cast<std::vector<unsigned char>*>(picture->custom_ptr); |
| + dest->insert(dest->end(), data, data + size); |
| + return 1; |
| + } |
| + |
| + typedef int (*WebPImporter)(WebPPicture* const, |
| + const uint8_t* const data, |
| + int row_stride); |
| + |
| + bool RgbPictureImport(const unsigned char* pixels, |
|
urvang
2016/02/10 23:54:42
These parts were taken from an OLD version of http
nyquist
2016/02/11 05:19:23
So, I tried to change the code so that it assumed
|
| + bool premultiplied, |
| + WebPImporter import_RGBA, |
| + WebPImporter import_RGB, |
| + WebPPicture* picture) { |
| + if (premultiplied) { |
| + return import_RGBA(picture, pixels, |
| + static_cast<int>(picture->width * 4)) != 0; |
| + } |
| + |
| + // Write the RGB pixels to an rgb data buffer, alpha premultiplied, |
| + // then import the rgb data. |
| + |
| + size_t pixelCount = picture->height * picture->width; |
| + std::vector<unsigned char> rgb(pixelCount * 3); |
| + |
| + for (unsigned char* data = rgb.data(); pixelCount-- > 0; pixels += 4) { |
| + unsigned char alpha = pixels[3]; |
| + if (alpha != 255) { |
| + *data++ = SkMulDiv255Round(pixels[0], alpha); |
| + *data++ = SkMulDiv255Round(pixels[1], alpha); |
| + *data++ = SkMulDiv255Round(pixels[2], alpha); |
| + } else { |
| + *data++ = pixels[0]; |
| + *data++ = pixels[1]; |
| + *data++ = pixels[2]; |
| + } |
| + } |
| + |
| + return import_RGB(picture, rgb.data(), picture->width * 3) != 0; |
| + } |
| + |
| + template <bool Premultiplied> |
| + bool ImportPictureBGRA(const unsigned char* pixels, WebPPicture* picture) { |
| + return RgbPictureImport(pixels, Premultiplied, &WebPPictureImportBGRA, |
| + &WebPPictureImportBGR, picture); |
| + } |
| + |
| + template <bool Premultiplied> |
| + bool ImportPictureRGBA(const unsigned char* pixels, WebPPicture* picture) { |
| + return RgbPictureImport(pixels, Premultiplied, &WebPPictureImportRGBA, |
| + &WebPPictureImportRGB, picture); |
| + } |
| + |
| + bool PlatformPremultipliedImportPicture(const unsigned char* pixels, |
| + WebPPicture* picture) { |
| + if (SK_B32_SHIFT) // Android |
| + return ImportPictureRGBA<true>(pixels, picture); |
| + |
| + return ImportPictureBGRA<true>(pixels, picture); |
| + } |
| +}; |
| + |
| +} // namespace |
| + |
| namespace blimp { |
| -BlimpRemoteImageSerializer::BlimpRemoteImageSerializer() {} |
| +BlimpRemoteImageSerializer::BlimpRemoteImageSerializer() |
| + : pixel_serializer_(make_scoped_ptr(new WebPImageEncoder)) {} |
| BlimpRemoteImageSerializer::~BlimpRemoteImageSerializer() {} |
| SkPixelSerializer* BlimpRemoteImageSerializer::GetPixelSerializer() { |
| - // TODO(nyquist): Add an image encoder. Make sure it does not serialize images |
| - // more than once. crbug.com/548434. |
| - return nullptr; |
| + return pixel_serializer_.get(); |
| } |
| } // namespace blimp |