summaryrefslogtreecommitdiff
path: root/src/android/jpeg/thumbnailer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/jpeg/thumbnailer.cpp')
-rw-r--r--src/android/jpeg/thumbnailer.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/android/jpeg/thumbnailer.cpp b/src/android/jpeg/thumbnailer.cpp
new file mode 100644
index 00000000..5cb00744
--- /dev/null
+++ b/src/android/jpeg/thumbnailer.cpp
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * thumbnailer.cpp - Simple image thumbnailer
+ */
+
+#include "thumbnailer.h"
+
+#include <libcamera/base/log.h>
+
+#include <libcamera/formats.h>
+
+using namespace libcamera;
+
+LOG_DEFINE_CATEGORY(Thumbnailer)
+
+Thumbnailer::Thumbnailer()
+ : valid_(false)
+{
+}
+
+void Thumbnailer::configure(const Size &sourceSize, PixelFormat pixelFormat)
+{
+ sourceSize_ = sourceSize;
+ pixelFormat_ = pixelFormat;
+
+ if (pixelFormat_ != formats::NV12) {
+ LOG(Thumbnailer, Error)
+ << "Failed to configure: Pixel Format "
+ << pixelFormat_.toString() << " unsupported.";
+ return;
+ }
+
+ valid_ = true;
+}
+
+void Thumbnailer::createThumbnail(const FrameBuffer &source,
+ const Size &targetSize,
+ std::vector<unsigned char> *destination)
+{
+ MappedFrameBuffer frame(&source, PROT_READ);
+ if (!frame.isValid()) {
+ LOG(Thumbnailer, Error)
+ << "Failed to map FrameBuffer : "
+ << strerror(frame.error());
+ return;
+ }
+
+ if (!valid_) {
+ LOG(Thumbnailer, Error) << "Config is unconfigured or invalid.";
+ return;
+ }
+
+ const unsigned int sw = sourceSize_.width;
+ const unsigned int sh = sourceSize_.height;
+ const unsigned int tw = targetSize.width;
+ const unsigned int th = targetSize.height;
+
+ ASSERT(tw % 2 == 0 && th % 2 == 0);
+
+ /* Image scaling block implementing nearest-neighbour algorithm. */
+ unsigned char *src = static_cast<unsigned char *>(frame.maps()[0].data());
+ unsigned char *srcC = src + sh * sw;
+ unsigned char *srcCb, *srcCr;
+ unsigned char *dstY, *srcY;
+
+ size_t dstSize = (th * tw) + ((th / 2) * tw);
+ destination->resize(dstSize);
+ unsigned char *dst = destination->data();
+ unsigned char *dstC = dst + th * tw;
+
+ for (unsigned int y = 0; y < th; y += 2) {
+ unsigned int sourceY = (sh * y + th / 2) / th;
+
+ dstY = dst + y * tw;
+ srcY = src + sw * sourceY;
+ srcCb = srcC + (sourceY / 2) * sw + 0;
+ srcCr = srcC + (sourceY / 2) * sw + 1;
+
+ for (unsigned int x = 0; x < tw; x += 2) {
+ unsigned int sourceX = (sw * x + tw / 2) / tw;
+
+ dstY[x] = srcY[sourceX];
+ dstY[tw + x] = srcY[sw + sourceX];
+ dstY[x + 1] = srcY[sourceX + 1];
+ dstY[tw + x + 1] = srcY[sw + sourceX + 1];
+
+ dstC[(y / 2) * tw + x + 0] = srcCb[(sourceX / 2) * 2];
+ dstC[(y / 2) * tw + x + 1] = srcCr[(sourceX / 2) * 2];
+ }
+ }
+}