summaryrefslogtreecommitdiff
path: root/src/qcam/format_converter.cpp
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-03-23 03:24:25 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-03-29 17:09:46 +0200
commit97e8b3a2eb321884fe1e15fb584f41a38cc33d51 (patch)
tree3ed93b2504e4fcdc3511bcf956f43ad84a558d0f /src/qcam/format_converter.cpp
parentffef90a1c1f1990581d8fbc22193bfc766d23d3b (diff)
qcam: Add Qt-based GUI application
qcam is a sample camera GUI application based on Qt. It demonstrates integration of the Qt event loop with libcamera. The application lets the user select a camera through the GUI, and then captures a single stream from the camera and displays it in a window. Only streams in YUYV formats are supported for now. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Diffstat (limited to 'src/qcam/format_converter.cpp')
-rw-r--r--src/qcam/format_converter.cpp104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp
new file mode 100644
index 00000000..6979a054
--- /dev/null
+++ b/src/qcam/format_converter.cpp
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * format_convert.cpp - qcam - Convert buffer to RGB
+ */
+
+#include <errno.h>
+
+#include <linux/videodev2.h>
+
+#include "format_converter.h"
+
+#define RGBSHIFT 8
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef CLAMP
+#define CLAMP(a,low,high) MAX((low),MIN((high),(a)))
+#endif
+#ifndef CLIP
+#define CLIP(x) CLAMP(x,0,255)
+#endif
+
+int FormatConverter::configure(unsigned int format, unsigned int width,
+ unsigned int height)
+{
+ switch (format) {
+ case V4L2_PIX_FMT_VYUY:
+ y_pos_ = 1;
+ cb_pos_ = 2;
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ y_pos_ = 0;
+ cb_pos_ = 3;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ y_pos_ = 1;
+ cb_pos_ = 0;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ y_pos_ = 0;
+ cb_pos_ = 1;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ width_ = width;
+ height_ = height;
+
+ return 0;
+}
+
+static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
+{
+ int c = y - 16;
+ int d = u - 128;
+ int e = v - 128;
+ *r = CLIP(( 298 * c + 409 * e + 128) >> RGBSHIFT);
+ *g = CLIP(( 298 * c - 100 * d - 208 * e + 128) >> RGBSHIFT);
+ *b = CLIP(( 298 * c + 516 * d + 128) >> RGBSHIFT);
+}
+
+void FormatConverter::convert(const unsigned char *src, unsigned char *dst)
+{
+ unsigned int src_x, src_y, dst_x, dst_y;
+ unsigned int src_stride;
+ unsigned int dst_stride;
+ unsigned int cr_pos;
+ int r, g, b, y, cr, cb;
+
+ cr_pos = (cb_pos_ + 2) % 4;
+ src_stride = width_ * 2;
+ dst_stride = width_ * 4;
+
+ for (src_y = 0, dst_y = 0; dst_y < height_; src_y++, dst_y++) {
+ for (src_x = 0, dst_x = 0; dst_x < width_; ) {
+ cb = src[src_y * src_stride + src_x * 4 + cb_pos_];
+ cr = src[src_y * src_stride + src_x * 4 + cr_pos];
+
+ y = src[src_y * src_stride + src_x * 4 + y_pos_];
+ yuv_to_rgb(y, cb, cr, &r, &g, &b);
+ dst[dst_y * dst_stride + 4 * dst_x + 0] = b;
+ dst[dst_y * dst_stride + 4 * dst_x + 1] = g;
+ dst[dst_y * dst_stride + 4 * dst_x + 2] = r;
+ dst[dst_y * dst_stride + 4 * dst_x + 3] = 0xff;
+ dst_x++;
+
+ y = src[src_y * src_stride + src_x * 4 + y_pos_ + 2];
+ yuv_to_rgb(y, cb, cr, &r, &g, &b);
+ dst[dst_y * dst_stride + 4 * dst_x + 0] = b;
+ dst[dst_y * dst_stride + 4 * dst_x + 1] = g;
+ dst[dst_y * dst_stride + 4 * dst_x + 2] = r;
+ dst[dst_y * dst_stride + 4 * dst_x + 3] = 0xff;
+ dst_x++;
+
+ src_x++;
+ }
+ }
+}