aboutsummaryrefslogtreecommitdiffstats
path: root/com.pelagicore.camera
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@pelagicore.com>2018-08-31 16:14:03 +0200
committerDominik Holland <dominik.holland@pelagicore.com>2018-08-31 14:18:05 +0000
commit78e7aacd7dd8b404ba4e2450ccd407a6ced22bc8 (patch)
treee50890c766a0ec773cc593822270d8d8c1730126 /com.pelagicore.camera
parent292aac5144efc7eec48e3dd0e5b017009c7f3ec0 (diff)
Add initial camera application for Neptune 3 UI
Change-Id: I04848271012128eef9654c3bd6a7bdcd868cf6f2 Reviewed-by: Bramastyo Harimukti Santoso <bramastyo.harimukti.santoso@pelagicore.com>
Diffstat (limited to 'com.pelagicore.camera')
-rw-r--r--com.pelagicore.camera/app/Camera.qml163
-rw-r--r--com.pelagicore.camera/app/app.pro7
-rw-r--r--com.pelagicore.camera/app/icon.pngbin0 -> 974 bytes
-rw-r--r--com.pelagicore.camera/app/info.yaml13
-rw-r--r--com.pelagicore.camera/com.pelagicore.camera.pro5
-rw-r--r--com.pelagicore.camera/plugin/camera_plugin.cpp60
-rw-r--r--com.pelagicore.camera/plugin/camera_plugin.h68
-rw-r--r--com.pelagicore.camera/plugin/camerastream.cpp258
-rw-r--r--com.pelagicore.camera/plugin/camerastream.h109
-rw-r--r--com.pelagicore.camera/plugin/plugin.pro19
-rw-r--r--com.pelagicore.camera/plugin/qmldir2
11 files changed, 704 insertions, 0 deletions
diff --git a/com.pelagicore.camera/app/Camera.qml b/com.pelagicore.camera/app/Camera.qml
new file mode 100644
index 0000000..a70d067
--- /dev/null
+++ b/com.pelagicore.camera/app/Camera.qml
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtAuto Extra Apps.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.2
+import QtGraphicalEffects 1.0
+import utils 1.0
+import controls 1.0
+
+import com.pelagicore.styles.neptune 3.0
+import camera 0.1
+
+PrimaryWindow {
+ id: root
+ readonly property var angles: [qsTr("Front"), qsTr("Rear"), qsTr("Left"), qsTr("Right")]
+ property bool play: !videofeed.lastError
+ property real buttonWidth: NeptuneStyle.dp(100)
+
+ function prevCamera() {
+ videofeed.angle = (videofeed.angle+3) % 4;
+ camlabel.text = root.angles[videofeed.angle];
+ }
+
+ function nextCamera() {
+ videofeed.angle = (videofeed.angle+1) % 4;
+ camlabel.text = root.angles[videofeed.angle];
+ }
+
+ Timer {
+ id: timer
+ interval: 5000; running: root.play; repeat: true
+ onTriggered: root.nextCamera()
+ }
+
+
+ Item {
+ x: root.exposedRect.x
+ y: root.exposedRect.y
+ width: root.exposedRect.width
+ height: root.exposedRect.height
+ CameraStream {
+ id: videofeed
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: NeptuneStyle.dp(1280)
+ height: NeptuneStyle.dp(1080)
+
+ Row {
+ id: controls
+ anchors.top: parent.top
+ width: 3*root.buttonWidth
+ height: NeptuneStyle.dp(100)
+ anchors.horizontalCenter: parent.horizontalCenter
+ ToolButton {
+ width: root.buttonWidth
+ height: parent.height
+ enabled: !videofeed.lastError
+ icon.name: "ic_skipprevious"
+ icon.color: "white"
+ onClicked: root.prevCamera()
+ }
+ ToolButton {
+ width: root.buttonWidth
+ height: parent.height
+ enabled: !videofeed.lastError
+ icon.name: root.play ? "ic-pause" : "ic_play"
+ icon.color: "white"
+ onClicked: {
+ root.play = !root.play;
+ timer.running = root.play;
+ }
+ background: Image {
+ id: playButtonBackground
+ anchors.centerIn: parent
+ width: NeptuneStyle.dp(sourceSize.width)
+ height: NeptuneStyle.dp(sourceSize.height)
+ source: Style.symbol("ic_button-bg")
+ fillMode: Image.PreserveAspectFit
+ layer.enabled: true
+ layer.effect: ColorOverlay {
+ source: playButtonBackground
+ color: NeptuneStyle.accentColor
+ }
+ }
+ }
+ ToolButton {
+ width: root.buttonWidth
+ height: parent.height
+ enabled: !videofeed.lastError
+ icon.name: "ic_skipnext"
+ icon.color: "white"
+ onClicked: root.nextCamera()
+ }
+ }
+
+ Label {
+ anchors.centerIn: parent
+ text: qsTr("No Camera")
+ color: "white"
+ visible: videofeed.lastError
+ }
+
+ Label {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: NeptuneStyle.dp(10)
+
+ id: camlabel
+ text: root.angles[videofeed.angle]
+ color: "white"
+ }
+ }
+ }
+}
diff --git a/com.pelagicore.camera/app/app.pro b/com.pelagicore.camera/app/app.pro
new file mode 100644
index 0000000..ff6386e
--- /dev/null
+++ b/com.pelagicore.camera/app/app.pro
@@ -0,0 +1,7 @@
+FILES += info.yaml \
+ icon.png \
+ Camera.qml
+
+NAME = com.pelagicore.camera
+
+load(app)
diff --git a/com.pelagicore.camera/app/icon.png b/com.pelagicore.camera/app/icon.png
new file mode 100644
index 0000000..504313d
--- /dev/null
+++ b/com.pelagicore.camera/app/icon.png
Binary files differ
diff --git a/com.pelagicore.camera/app/info.yaml b/com.pelagicore.camera/app/info.yaml
new file mode 100644
index 0000000..79b0391
--- /dev/null
+++ b/com.pelagicore.camera/app/info.yaml
@@ -0,0 +1,13 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'com.pelagicore.camera'
+icon: 'icon.png'
+code: 'Camera.qml'
+runtime: 'qml'
+runtimeParameters:
+ importPaths: [ 'imports' ]
+name:
+ en: 'Camera'
+
+categories: [ 'app', 'widget' ]
diff --git a/com.pelagicore.camera/com.pelagicore.camera.pro b/com.pelagicore.camera/com.pelagicore.camera.pro
new file mode 100644
index 0000000..0740149
--- /dev/null
+++ b/com.pelagicore.camera/com.pelagicore.camera.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+SUBDIRS += plugin \
+ app
+
+app.depends = plugin
diff --git a/com.pelagicore.camera/plugin/camera_plugin.cpp b/com.pelagicore.camera/plugin/camera_plugin.cpp
new file mode 100644
index 0000000..05939e9
--- /dev/null
+++ b/com.pelagicore.camera/plugin/camera_plugin.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtAuto Extra Apps.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+#include "camera_plugin.h"
+#include "camerastream.h"
+
+void CameraPlugin::registerTypes(const char* uri)
+{
+ Q_ASSERT(uri == QLatin1String("camera"));
+
+ qmlRegisterType<CameraStream>(uri, 0, 1, "CameraStream");
+}
diff --git a/com.pelagicore.camera/plugin/camera_plugin.h b/com.pelagicore.camera/plugin/camera_plugin.h
new file mode 100644
index 0000000..3dfd991
--- /dev/null
+++ b/com.pelagicore.camera/plugin/camera_plugin.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtAuto Extra Apps.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+#ifndef CAMERAPLUGIN_H
+#define CAMERAPLUGIN_H
+
+#include <QObject>
+#include <QQmlExtensionPlugin>
+#include <QtQml>
+
+class CameraPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ void registerTypes(const char* uri) override;
+};
+
+#endif // CAMERAPLUGIN_H
diff --git a/com.pelagicore.camera/plugin/camerastream.cpp b/com.pelagicore.camera/plugin/camerastream.cpp
new file mode 100644
index 0000000..3a0d862
--- /dev/null
+++ b/com.pelagicore.camera/plugin/camerastream.cpp
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtAuto Extra Apps.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+#include "camerastream.h"
+#include "QQuickWindow"
+#include <QSGSimpleTextureNode>
+#include <QSGTexture>
+#include <QOpenGLTexture>
+#include <QOpenGLContext>
+#include <QOpenGLExtraFunctions>
+#include <QtGui>
+
+#ifdef Q_OS_UNIX
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#endif
+
+#define WIDTH 1280
+#define HEIGHT 1080
+
+//--------------------------------------------
+#define SWAP_COLORS
+//--------------------------------------------
+
+CameraStream::CameraStream(QQuickItem* parent)
+ : QQuickItem(parent)
+ , m_enableBenchmarkFirstFrameRendered(true)
+{
+ m_renderTimer.setInterval(30);
+ m_renderTimer.setSingleShot(false);
+
+ m_framecount = 0;
+
+ m_fb = new uint8_t[WIDTH*HEIGHT*4];
+ m_tfb = new uint8_t[WIDTH*HEIGHT*4];
+
+ connect(this, &QQuickItem::visibleChanged, this, &CameraStream::cameraVisibleChanged);
+ connect(&m_renderTimer, &QTimer::timeout, this, &QQuickItem::update);
+
+ this->setFlag(QQuickItem::ItemHasContents, true);
+
+ m_image = new QImage(m_fb, WIDTH, HEIGHT, QImage::Format_RGB888);
+
+ m_renderTimer.start();
+
+ m_angle = 0;
+}
+
+CameraStream::~CameraStream()
+{
+ delete m_fb;
+ delete m_tfb;
+ delete m_image;
+}
+
+void CameraStream::cameraVisibleChanged()
+{
+ if (isVisible()) {
+ m_renderTimer.start();
+ } else {
+ m_renderTimer.stop();
+ }
+}
+
+int CameraStream::angle() const
+{
+ return m_angle;
+}
+
+void CameraStream::setAngle(int angle)
+{
+ if (angle < 0)
+ angle = 0;
+ if (angle >= NUM_CAMERAS)
+ angle = NUM_CAMERAS-1;
+
+ if (m_angle != angle) {
+ m_angle = angle;
+#ifdef Q_OS_UNIX
+ int f;
+ f = open("/dev/framegrabber", O_RDONLY);
+ if (f >= 0) {
+ ioctl(f, 0, m_angle);
+ close(f);
+ }
+#endif
+ emit angleChanged(angle);
+ }
+}
+
+int CameraStream::hdmiAngle() const
+{
+ return m_hdmi_angle;
+}
+
+void CameraStream::setHdmiAngle(int angle)
+{
+ if (angle < 0)
+ angle = 0;
+ if (angle >= NUM_CAMERAS)
+ angle = NUM_CAMERAS-1;
+
+ if (m_hdmi_angle != angle) {
+ m_hdmi_angle = angle;
+#ifdef Q_OS_UNIX
+ int f;
+ f = open("/dev/framegrabber", O_RDONLY);
+ if (f >= 0) {
+ ioctl(f, 1, m_hdmi_angle);
+ close(f);
+ }
+#endif
+ emit hdmiAngleChanged(angle);
+ }
+}
+
+QString CameraStream::lastError() const
+{
+ return m_lastError;
+}
+
+void CameraStream::firstFrameRenderBenchmark()
+{
+ emit firstFrameRendered();
+ disconnect(this->window(), &QQuickWindow::frameSwapped, this, &CameraStream::firstFrameRenderBenchmark);
+}
+
+QSGNode* CameraStream::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*)
+{
+ QQuickWindow *win = QQuickItem::window();
+
+ QSGSimpleTextureNode *textureNode = static_cast<QSGSimpleTextureNode *>(oldNode);
+ if (!textureNode)
+ textureNode = new QSGSimpleTextureNode();
+
+ if (textureNode->texture()) {
+ delete textureNode->texture();
+ }
+
+ copyFrame();
+
+ QImage resizedImage = m_image->scaled(width(), height(), Qt::KeepAspectRatio);
+ auto texture = win->createTextureFromImage(resizedImage);
+ textureNode->setTexture(texture);
+
+ textureNode->markDirty(QSGNode::DirtyMaterial);
+
+ textureNode->setRect(0, 0, width(), height());
+
+ m_framecount++;
+ //enable capturing first frame swap signal after refreshing the first paint of this node.
+ if (m_enableBenchmarkFirstFrameRendered && isVisible()) {
+ connect(this->window(), &QQuickWindow::frameSwapped, this, &CameraStream::firstFrameRenderBenchmark);
+ m_enableBenchmarkFirstFrameRendered = false;
+ }
+
+ return textureNode;
+}
+
+void CameraStream::copyFrame() {
+#ifdef ABGR
+ int x, y;
+ uint32_t tmp;
+#endif
+ uint32_t *s, *t;
+
+ s = reinterpret_cast<uint32_t *>(m_tfb);
+ t = reinterpret_cast<uint32_t *>(m_fb);
+
+#ifdef Q_OS_UNIX
+ int f;
+ f = open("/dev/framegrabber", O_RDONLY);
+ if (f >= 0) {
+ m_lastError.clear();
+ ssize_t num;
+ num = read(f, m_tfb, WIDTH*HEIGHT*3);
+ if (num < WIDTH*HEIGHT*3)
+ qCritical() << "read() returned " << num;
+ close(f);
+ } else {
+ m_lastError = QLatin1String(strerror(errno));
+ emit lastErrorChanged(m_lastError);
+ }
+#else
+ m_lastError = QLatin1String("no camera support on windows");
+ emit lastErrorChanged(m_lastError);
+#endif
+
+#ifdef ABGR
+ for (y = 0; y < HEIGHT;y++) {
+ for (x = 0; x < WIDTH;x++) {
+ tmp = s[y * WIDTH + x];
+#ifdef SWAP_COLORS
+ tmp =
+ ((tmp & 0x00ff0000) >> 16) |
+ ((tmp & 0x000000ff) << 16) |
+ (tmp & 0x0000ff00);
+#endif
+ tmp |= 0xff000000;
+ *t++ = tmp;
+ }
+ }
+#else
+ memcpy(t, s, WIDTH*HEIGHT*3);
+#endif
+}
diff --git a/com.pelagicore.camera/plugin/camerastream.h b/com.pelagicore.camera/plugin/camerastream.h
new file mode 100644
index 0000000..e94481c
--- /dev/null
+++ b/com.pelagicore.camera/plugin/camerastream.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtAuto Extra Apps.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+#ifndef CAMERASTREAM_H
+#define CAMERASTREAM_H
+
+#include <QQuickItem>
+#include <QSGSimpleRectNode>
+#include <QTimer>
+
+#define NUM_CAMERAS 4
+
+class CameraStream : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(int hdmi_angle READ hdmiAngle WRITE setHdmiAngle NOTIFY hdmiAngleChanged)
+ Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
+
+public:
+ CameraStream(QQuickItem* parent = nullptr);
+ ~CameraStream() override;
+
+ int angle() const;
+ void setAngle(int angle);
+
+ int hdmiAngle() const;
+ void setHdmiAngle(int angle);
+
+ QString lastError() const;
+
+signals:
+ void firstFrameRendered();
+ void angleChanged(int mode);
+ void hdmiAngleChanged(int mode);
+ void lastErrorChanged(QString lastError);
+
+private slots:
+ void cameraVisibleChanged();
+ void firstFrameRenderBenchmark();
+
+protected:
+ QSGNode* updatePaintNode(QSGNode*, UpdatePaintNodeData*) override;
+
+private:
+ void copyFrame();
+
+ QTimer m_renderTimer;
+
+ bool m_enableBenchmarkFirstFrameRendered;
+ int m_framecount;
+ uint8_t *m_fb;
+ uint8_t *m_tfb;
+ QImage *m_image;
+ int m_angle;
+ int m_hdmi_angle;
+ QString m_lastError;
+};
+
+#endif // CAMERASTREAM_H
diff --git a/com.pelagicore.camera/plugin/plugin.pro b/com.pelagicore.camera/plugin/plugin.pro
new file mode 100644
index 0000000..8988a37
--- /dev/null
+++ b/com.pelagicore.camera/plugin/plugin.pro
@@ -0,0 +1,19 @@
+TEMPLATE = lib
+TARGET = camera
+QT += qml quick
+CONFIG += plugin
+
+TARGET = $$qtLibraryTarget($$TARGET)
+uri = camera
+load(qmlplugin)
+
+# Input
+SOURCES += \
+ camera_plugin.cpp \
+ camerastream.cpp
+
+HEADERS += \
+ camera_plugin.h \
+ camerastream.h
+
+OTHER_FILES = qmldir
diff --git a/com.pelagicore.camera/plugin/qmldir b/com.pelagicore.camera/plugin/qmldir
new file mode 100644
index 0000000..ff5dd50
--- /dev/null
+++ b/com.pelagicore.camera/plugin/qmldir
@@ -0,0 +1,2 @@
+module camera
+plugin camera .