Create a QDeclarativeItem Viewfinder subclass
authorMohammed Sameer <msameer@foolab.org>
Fri, 26 Jul 2013 19:59:25 +0000 (22:59 +0300)
committerMohammed Sameer <msameer@foolab.org>
Fri, 26 Jul 2013 19:59:25 +0000 (22:59 +0300)
declarative/camera.cpp
declarative/camera.h
declarative/declarative.pro
declarative/plugin.cpp
declarative/viewfinder.cpp [new file with mode: 0644]
declarative/viewfinder.h [new file with mode: 0644]
qml/CameraView.qml
qml/FocusReticle.qml

index 252a6c2..5d22fd9 100644 (file)
@@ -54,7 +54,6 @@ Camera::Camera(QDeclarativeItem *parent) :
   QDeclarativeItem(parent),
   m_cam(new QtCamera(this)),
   m_dev(0),
-  m_vf(new QtCamGraphicsViewfinder(m_cam->config(), this)),
   m_mode(Camera::UnknownMode),
   m_notifications(new NotificationsContainer(this)),
   m_zoom(0),
@@ -76,10 +75,6 @@ Camera::Camera(QDeclarativeItem *parent) :
   m_config(new CameraConfig(this)) {
 
   m_config->componentComplete();
-
-  QObject::connect(m_vf, SIGNAL(renderAreaChanged()), this, SIGNAL(renderAreaChanged()));
-  QObject::connect(m_vf, SIGNAL(videoResolutionChanged()), this, SIGNAL(videoResolutionChanged()));
-  QObject::connect(m_vf, SIGNAL(renderingEnabledChanged()), this, SIGNAL(renderingEnabledChanged()));
 }
 
 Camera::~Camera() {
@@ -178,8 +173,6 @@ bool Camera::setDeviceId(const QVariant& deviceId) {
 
   m_id = deviceId;
 
-  m_vf->setDevice(m_dev);
-
   QObject::connect(m_dev, SIGNAL(runningStateChanged(bool)),
                      this, SIGNAL(runningStateChanged()));
   QObject::connect(m_dev, SIGNAL(idleStateChanged(bool)), this, SIGNAL(idleStateChanged()));
@@ -197,10 +190,6 @@ QVariant Camera::deviceId() const {
 
 void Camera::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) {
   QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
-
-  // TODO: seems setting geometry breaks rendering somehow
-  //  m_vf->setGeometry(newGeometry);
-  m_vf->resize(newGeometry.size());
 }
 
 QtCamDevice *Camera::device() const {
@@ -290,14 +279,6 @@ void Camera::setSounds(Sounds *sounds) {
   }
 }
 
-QRectF Camera::renderArea() const {
-  return m_vf->renderArea();
-}
-
-QSizeF Camera::videoResolution() const {
-  return m_vf->videoResolution();
-}
-
 void Camera::resetCapabilities() {
   QtCamDevice *dev = device();
 
@@ -430,14 +411,6 @@ VideoTorch *Camera::videoTorch() const {
   return m_videoTorch;
 }
 
-bool Camera::isRenderingEnabled() const {
-  return m_vf->isRenderingEnabled();
-}
-
-void Camera::setRenderingEnabled(bool enabled) {
-  m_vf->setRenderingEnabled(enabled);
-}
-
 CameraConfig *Camera::cameraConfig() const {
   return m_config;
 }
index 68e4d25..52cec37 100644 (file)
@@ -29,7 +29,6 @@
 
 class QtCamera;
 class QtCamDevice;
-class QtCamGraphicsViewfinder;
 class Sounds;
 class NotificationsContainer;
 class Zoom;
@@ -62,9 +61,6 @@ class Camera : public QDeclarativeItem {
   Q_PROPERTY(QString videoSuffix READ videoSuffix CONSTANT);
   Q_PROPERTY(Sounds *sounds READ sounds WRITE setSounds NOTIFY soundsChanged);
 
-  Q_PROPERTY(QRectF renderArea READ renderArea NOTIFY renderAreaChanged);
-  Q_PROPERTY(QSizeF videoResolution READ videoResolution NOTIFY videoResolutionChanged);
-
   Q_PROPERTY(Zoom *zoom READ zoom NOTIFY zoomChanged);
   Q_PROPERTY(Flash *flash READ flash NOTIFY flashChanged);
   Q_PROPERTY(Scene *scene READ scene NOTIFY sceneChanged);
@@ -83,7 +79,6 @@ class Camera : public QDeclarativeItem {
   Q_PROPERTY(VideoMute *videoMute READ videoMute NOTIFY videoMuteChanged);
   Q_PROPERTY(VideoTorch *videoTorch READ videoTorch NOTIFY videoTorchChanged);
 
-  Q_PROPERTY(bool renderingEnabled READ isRenderingEnabled WRITE setRenderingEnabled NOTIFY renderingEnabledChanged);
   // TODO: We need a setter here too.
   Q_PROPERTY(CameraConfig *cameraConfig READ cameraConfig CONSTANT);
 
@@ -143,12 +138,6 @@ public:
   VideoMute *videoMute() const;
   VideoTorch *videoTorch() const;
 
-  QRectF renderArea() const;
-  QSizeF videoResolution() const;
-
-  bool isRenderingEnabled() const;
-  void setRenderingEnabled(bool enabled);
-
   CameraConfig *cameraConfig() const;
 
 signals:
@@ -195,7 +184,6 @@ private:
   QtCamera *m_cam;
   QtCamDevice *m_dev;
   QVariant m_id;
-  QtCamGraphicsViewfinder *m_vf;
   CameraMode m_mode;
   NotificationsContainer *m_notifications;
 
index 3e5731f..1578489 100644 (file)
@@ -18,7 +18,7 @@ HEADERS += plugin.h previewprovider.h camera.h mode.h imagemode.h videomode.h \
            flickerreduction.h videomute.h metadata.h imagesettings.h \
            imageresolutionmodel.h videosettings.h videoresolutionmodel.h \
            notificationscontainer.h sounds.h focus.h autofocus.h \
-           roi.h cameraconfig.h videoplayer.h
+           roi.h cameraconfig.h videoplayer.h viewfinder.h
 
 SOURCES += plugin.cpp previewprovider.cpp camera.cpp mode.cpp imagemode.cpp videomode.cpp \
            zoom.cpp flash.cpp scene.cpp evcomp.cpp videotorch.cpp whitebalance.cpp \
@@ -26,7 +26,7 @@ SOURCES += plugin.cpp previewprovider.cpp camera.cpp mode.cpp imagemode.cpp vide
            flickerreduction.cpp videomute.cpp metadata.cpp imagesettings.cpp \
            imageresolutionmodel.cpp videosettings.cpp videoresolutionmodel.cpp \
            notificationscontainer.cpp sounds.cpp focus.cpp autofocus.cpp \
-           roi.cpp cameraconfig.cpp videoplayer.cpp
+           roi.cpp cameraconfig.cpp videoplayer.cpp viewfinder.cpp
 
 PLUGIN_IMPORT_PATH = QtCamera
 target.path = $$[QT_INSTALL_IMPORTS]/$$PLUGIN_IMPORT_PATH
index 7302341..bf0e68d 100644 (file)
@@ -47,6 +47,7 @@
 #include "sounds.h"
 #include "cameraconfig.h"
 #include "videoplayer.h"
+#include "viewfinder.h"
 #include <QtDeclarative>
 
 #define MAJOR 1
@@ -106,6 +107,7 @@ void Plugin::registerTypes(const char *uri) {
   qmlRegisterType<CameraConfig>(uri, MAJOR, MINOR, "CameraConfig");
 
   qmlRegisterType<VideoPlayer>("QtCameraExtras", MAJOR, MINOR, "VideoPlayer");
+  qmlRegisterType<Viewfinder>(uri, MAJOR, MINOR, "Viewfinder");
 }
 
 Q_EXPORT_PLUGIN2(declarativeqtcamera, Plugin);
diff --git a/declarative/viewfinder.cpp b/declarative/viewfinder.cpp
new file mode 100644 (file)
index 0000000..d212c35
--- /dev/null
@@ -0,0 +1,210 @@
+// -*- c++ -*-
+
+/*!
+ * This file is part of CameraPlus.
+ *
+ * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "viewfinder.h"
+#include "camera.h"
+#include "cameraconfig.h"
+#include "qtcamviewfinderrenderer.h"
+#include <QDeclarativeInfo>
+#include <QPainter>
+#include "qtcamdevice.h"
+
+Viewfinder::Viewfinder(QDeclarativeItem *parent) :
+  QDeclarativeItem(parent),
+  m_renderer(0),
+  m_cam(0),
+  m_conf(0),
+  m_enabled(true) {
+
+  setFlag(QGraphicsItem::ItemHasNoContents, false);
+}
+
+Viewfinder::~Viewfinder() {
+
+}
+
+bool Viewfinder::isRenderingEnabled() const {
+  return m_enabled;
+}
+
+void Viewfinder::setRenderingEnabled(bool enabled) {
+  if (m_enabled != enabled) {
+    m_enabled = enabled;
+    emit renderingEnabledChanged();
+  }
+}
+
+Camera *Viewfinder::camera() const {
+  return m_cam;
+}
+
+void Viewfinder::setCamera(Camera *camera) {
+  if (m_cam == camera) {
+    return;
+  }
+
+  if (m_cam && m_cam != camera) {
+    qmlInfo(this) << "Cannot reset Camera";
+    return;
+  }
+
+  if (!camera) {
+    qmlInfo(this) << "Camera cannot be empty";
+    return;
+  }
+
+  if (m_cam) {
+    QObject::disconnect(m_cam, SIGNAL(deviceChanged()), this, SLOT(deviceChanged()));
+  }
+
+  m_cam = camera;
+
+  if (m_cam) {
+    QObject::connect(m_cam, SIGNAL(deviceChanged()), this, SLOT(deviceChanged()));
+  }
+
+  if (isComponentComplete()) {
+    deviceChanged();
+  }
+
+  emit cameraChanged();
+}
+
+CameraConfig *Viewfinder::cameraConfig() const {
+  return m_conf;
+}
+
+void Viewfinder::setCameraConfig(CameraConfig *config) {
+  if (m_conf && m_conf != config) {
+    qmlInfo(this) << "Cannot reset CameraConfig";
+    return;
+  }
+
+  if (!config) {
+    qmlInfo(this) << "CameraConfig cannot be empty";
+    return;
+  }
+
+  if (m_conf == config) {
+    return;
+  }
+
+  m_conf = config;
+
+  if (isComponentComplete()) {
+    deviceChanged();
+  }
+
+  emit cameraConfigChanged();
+}
+
+void Viewfinder::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
+                      QWidget *widget) {
+
+  Q_UNUSED(widget);
+  Q_UNUSED(option);
+
+  painter->fillRect(boundingRect(), Qt::black);
+
+  if (!m_renderer || !m_enabled) {
+    return;
+  }
+
+  m_renderer->paint(painter);
+}
+
+QRectF Viewfinder::renderArea() const {
+  return m_renderer ? m_renderer->renderArea() : QRectF();
+}
+
+QSizeF Viewfinder::videoResolution() const {
+  return m_renderer ? m_renderer->videoResolution() : QSizeF();
+}
+
+void Viewfinder::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) {
+  QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
+
+  if (m_renderer) {
+    m_renderer->resize(newGeometry.size());
+  }
+}
+
+void Viewfinder::componentComplete() {
+  if (!m_cam) {
+    qmlInfo(this) << "Camera not set";
+    return;
+  }
+
+  if (!m_conf) {
+    qmlInfo(this) << "CameraConfig not set";
+    return;
+  }
+
+  m_renderer = QtCamViewfinderRenderer::create(m_conf->config(), this);
+  if (!m_renderer) {
+    qmlInfo(this) << "Failed to create viewfinder renderer";
+    return;
+  }
+
+  m_renderer->resize(QSizeF(width(), height()));
+  QObject::connect(m_renderer, SIGNAL(updateRequested()), this, SLOT(updateRequested()));
+  QObject::connect(m_renderer, SIGNAL(renderAreaChanged()), this, SIGNAL(renderAreaChanged()));
+  QObject::connect(m_renderer, SIGNAL(videoResolutionChanged()), this, SIGNAL(videoResolutionChanged()));
+}
+
+void Viewfinder::deviceChanged() {
+  if (!m_renderer) {
+    qmlInfo(this) << "No renderer";
+    return;
+  }
+
+  QtCamDevice *dev = m_cam->device();
+
+  if (dev) {
+    dev->setViewfinder(this);
+  }
+
+  emit renderAreaChanged();
+  emit videoResolutionChanged();
+}
+
+GstElement *Viewfinder::sinkElement() {
+  return m_renderer ? m_renderer->sinkElement() : 0;
+}
+
+bool Viewfinder::setDevice(QtCamDevice *device) {
+  Q_UNUSED(device);
+
+  return true;
+}
+
+void Viewfinder::stop() {
+  if (m_renderer) {
+    m_renderer->reset();
+  }
+}
+
+void Viewfinder::updateRequested() {
+  if (m_enabled) {
+    update();
+  }
+}
diff --git a/declarative/viewfinder.h b/declarative/viewfinder.h
new file mode 100644 (file)
index 0000000..42ea853
--- /dev/null
@@ -0,0 +1,86 @@
+// -*- c++ -*-
+
+/*!
+ * This file is part of CameraPlus.
+ *
+ * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef VIEWFINDER_H
+#define VIEWFINDER_H
+
+#include <QDeclarativeItem>
+#include "qtcamviewfinder.h"
+
+class QtCamViewfinderRenderer;
+class Camera;
+class CameraConfig;
+
+class Viewfinder : public QDeclarativeItem, public QtCamViewfinder {
+  Q_OBJECT
+
+  Q_PROPERTY(QRectF renderArea READ renderArea NOTIFY renderAreaChanged);
+  Q_PROPERTY(QSizeF videoResolution READ videoResolution NOTIFY videoResolutionChanged);
+  Q_PROPERTY(bool renderingEnabled READ isRenderingEnabled WRITE setRenderingEnabled NOTIFY renderingEnabledChanged);
+  Q_PROPERTY(Camera *camera READ camera WRITE setCamera NOTIFY cameraChanged);
+  Q_PROPERTY(CameraConfig *cameraConfig READ cameraConfig WRITE setCameraConfig NOTIFY cameraConfigChanged);
+
+public:
+  Viewfinder(QDeclarativeItem *parent = 0);
+  ~Viewfinder();
+
+  QRectF renderArea() const;
+  QSizeF videoResolution() const;
+
+  bool isRenderingEnabled() const;
+  void setRenderingEnabled(bool enabled);
+
+  Camera *camera() const;
+  void setCamera(Camera *camera);
+
+  CameraConfig *cameraConfig() const;
+  void setCameraConfig(CameraConfig *config);
+
+  void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+  GstElement *sinkElement();
+  bool setDevice(QtCamDevice *device);
+  void stop();
+
+signals:
+  void renderAreaChanged();
+  void videoResolutionChanged();
+  void renderingEnabledChanged();
+  void cameraChanged();
+  void cameraConfigChanged();
+
+protected:
+  void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry);
+  void componentComplete();
+
+private slots:
+  void deviceChanged();
+  void updateRequested();
+
+private:
+  QtCamViewfinderRenderer *m_renderer;
+  Camera *m_cam;
+  CameraConfig *m_conf;
+  bool m_enabled;
+};
+
+#endif /* VIEWFINDER_H */
index 813a098..7eaf88b 100644 (file)
@@ -31,7 +31,26 @@ Camera {
     property bool pressed: focusReticle.locked || (loader.item ? loader.item.pressed : false)
     property int policyMode: loader.item ? loader.item.policyMode : CameraResources.None
 
-    renderingEnabled: mainView.currentItem == cam
+    Viewfinder {
+        id: viewfinder
+        width: cam.width
+        height: cam.height
+        x: 0
+        y: 0
+
+        camera: cam
+        cameraConfig: cam.cameraConfig
+
+        renderingEnabled: mainView.currentItem == cam
+
+        GridLines {
+            x: viewfinder.renderArea.x
+            y: viewfinder.renderArea.y
+            width: viewfinder.renderArea.width
+            height: viewfinder.renderArea.height
+            visible: settings.gridEnabled
+        }
+    }
 
     function policyLost() {
         if (loader.item) {
@@ -120,17 +139,12 @@ Camera {
 
     onRoiChanged: roi.normalize = false
 
-    GridLines {
-        x: cam.renderArea.x
-        y: cam.renderArea.y
-        width: cam.renderArea.width
-        height: cam.renderArea.height
-        visible: settings.gridEnabled
-    }
-
     FocusReticle {
         id: focusReticle
         cam: cam
+        videoResolution: viewfinder.videoResolution
+        renderArea: viewfinder.renderArea
+
         visible: loader.item != null && loader.item.controlsVisible &&
             cam.autoFocus.canFocus(cam.scene.value)
         cafStatus: cam ? cam.autoFocus.cafStatus : -1
index d95eada..39fba6b 100644 (file)
@@ -29,15 +29,18 @@ import CameraPlus 1.0
 
 MouseArea {
     id: mouse
-    x: cam ? cam.renderArea.x : 0
-    y: cam ? cam.renderArea.y : 0
-    width: cam ? cam.renderArea.width : 0
-    height: cam ? cam.renderArea.height : 0
+    x: renderArea.x
+    y: renderArea.y
+    width: renderArea.width
+    height: renderArea.height
     drag.minimumX: 0
     drag.minimumY: 0
     drag.maximumX: width - reticle.width
     drag.maximumY: height - reticle.height
 
+    property variant videoResolution
+    property variant renderArea
+
     property bool locked: false
 
     property int cafStatus: AutoFocus.None
@@ -103,16 +106,16 @@ MouseArea {
 
         // TODO: rework this and move to unnormalized coordinates
         // in terms of video resolution:
-        var rx = (cam.videoResolution.width * reticle.x) / mouse.width
-        var rwidth = (cam.videoResolution.width * reticle.width) / mouse.width
-        var ry = (cam.videoResolution.height * reticle.y) / mouse.height
-        var rheight = (cam.videoResolution.height * reticle.height) / mouse.height
+        var rx = (videoResolution.width * reticle.x) / mouse.width
+        var rwidth = (videoResolution.width * reticle.width) / mouse.width
+        var ry = (videoResolution.height * reticle.y) / mouse.height
+        var rheight = (videoResolution.height * reticle.height) / mouse.height
 
         // Translate to normalized coordinates (1x1 square) as expected by our C++ backend
-        rx = rx / cam.videoResolution.width
-        rwidth = rwidth / cam.videoResolution.width
-        ry = ry / cam.videoResolution.height
-        rheight = rheight / cam.videoResolution.height
+        rx = rx / videoResolution.width
+        rwidth = rwidth / videoResolution.width
+        ry = ry / videoResolution.height
+        rheight = rheight / videoResolution.height
 
         // console.log("Setting ROI to: " + rx + "x" + ry)
         cam.roi.setRegionOfInterest(Qt.rect(rx, ry, rwidth, rheight))