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 |