Added resource policy support (Still needs more testing) and refactored the pipeline...
authorMohammed Sameer <msameer@foolab.org>
Thu, 13 Sep 2012 19:26:17 +0000 (22:26 +0300)
committerMohammed Sameer <msameer@foolab.org>
Thu, 13 Sep 2012 19:26:17 +0000 (22:26 +0300)
19 files changed:
imports/camera.cpp
imports/camera.h
lib/qtcamdevice.cpp
lib/qtcamgraphicsviewfinder.cpp
lib/qtcamgraphicsviewfinder.h
lib/qtcamviewfinder.h
lib/qtcamviewfinderrenderermeego.cpp
qml/CameraPage.qml
qml/ImageColorFilterPage.qml
qml/ImagePage.qml
qml/ImageSettingsPage.qml
qml/ImageWhiteBalancePage.qml
qml/PostCapturePage.qml
qml/VideoPage.qml
qml/main.qml
src/cameraresources.cpp [new file with mode: 0644]
src/cameraresources.h [new file with mode: 0644]
src/main.cpp
src/src.pro

index cc27106..470afa2 100644 (file)
@@ -126,10 +126,12 @@ bool Camera::start() {
   return m_dev->start();
 }
 
-void Camera::stop() {
+bool Camera::stop() {
   if (m_dev) {
-    m_dev->stop();
+    return m_dev->stop();
   }
+
+  return true;
 }
 
 bool Camera::isIdle() {
index 4cf978f..a9507ff 100644 (file)
@@ -46,6 +46,7 @@ public:
   QtCamDevice *device() const;
 
   Q_INVOKABLE bool start();
+  Q_INVOKABLE bool stop();
 
   bool isIdle();
   bool isRunning();
@@ -53,9 +54,6 @@ public:
   QString imageSuffix() const;
   QString videoSuffix() const;
 
-public slots:
-  void stop();
-
 signals:
   void deviceCountChanged();
   void deviceIdChanged();
index 637286b..6197dc3 100644 (file)
@@ -185,6 +185,8 @@ bool QtCamDevice::stop() {
     return false;
   }
 
+  d_ptr->viewfinder->stop();
+
   // First we go to ready:
   GstStateChangeReturn st = gst_element_set_state(d_ptr->cameraBin, GST_STATE_READY);
   if (st != GST_STATE_CHANGE_FAILURE) {
index 342255a..8ce2c69 100644 (file)
@@ -109,3 +109,7 @@ void QtCamGraphicsViewfinder::resizeEvent(QGraphicsSceneResizeEvent *event) {
 void QtCamGraphicsViewfinder::updateRequested() {
   update();
 }
+
+void QtCamGraphicsViewfinder::stop() {
+  d_ptr->resetBackend();
+}
index b8bd811..157dd4c 100644 (file)
@@ -18,6 +18,7 @@ public:
 
   virtual GstElement *sinkElement();
   virtual bool setDevice(QtCamDevice *device);
+  virtual void stop();
 
   virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                     QWidget *widget = 0);
index cefa84b..0601e8d 100644 (file)
@@ -14,6 +14,7 @@ public:
 
   virtual GstElement *sinkElement() = 0;
   virtual bool setDevice(QtCamDevice *device) = 0;
+  virtual void stop() = 0;
 };
 
 #endif /* QT_CAM_VIEWFINDER_H */
index 9c20ff3..90ac984 100644 (file)
@@ -106,7 +106,8 @@ void QtCamViewfinderRendererMeeGo::resize(const QSizeF& size) {
 }
 
 void QtCamViewfinderRendererMeeGo::reset() {
-  // Nothing.
+  QMutexLocker locker(&m_frameMutex);
+  m_frame = -1;
 }
 
 GstElement *QtCamViewfinderRendererMeeGo::sinkElement() {
index cde3fbd..4ba3bc0 100644 (file)
@@ -2,11 +2,92 @@
 import QtQuick 1.1
 import com.nokia.meego 1.1
 import QtCamera 1.0
+import CameraPlus 1.0
 
 Page {
+        id: page
 
         property alias standbyWidget: standby
 
+        property bool needsPipeline: true
+        property int policyMode: CameraResources.None
+
+        Component.onCompleted: {
+                if (platformWindow.active && needsPipeline) {
+                        resourcePolicy.acquire(page.policyMode);
+                }
+        }
+
+        onStatusChanged: {
+                if (platformWindow.active && status == PageStatus.Activating) {
+                        resourcePolicy.acquire(page.policyMode);
+                }
+        }
+/*
+        onStatusChanged: {
+                if (status == PageStatus.Active && !page.needsPipeline) {
+                        cam.stop();
+                }
+        }
+*/
+
+        onPolicyModeChanged: {
+                if (platformWindow.active) {
+                        resourcePolicy.acquire(page.policyMode);
+                }
+        }
+
+        function handlePipeline() {
+                if (!platformWindow.active) {
+                        // TODO: force if we lost resources ?
+                        cam.stop();
+                }
+                else if (resourcePolicy.acquired && page.needsPipeline && !cam.running) {
+                        // TODO: error
+                        cam.start();
+                }
+                else if (!resourcePolicy.acquired) {
+                        // TODO: force
+                        cam.stop();
+                }
+        }
+
+        Connections {
+                target: resourcePolicy
+                onAcquiredChanged: handlePipeline();
+        }
+
+        Connections {
+                target: platformWindow
+                onActiveChanged: {
+                        if (!platformWindow.active) {
+                                // This is a noop if camera is not
+                                // idle so calling it will not hurt
+                                if (cam.stop()) {
+                                        resourcePolicy.acquire(CameraResources.None);
+                                }
+                        }
+                        else if (page.needsPipeline) {
+                                resourcePolicy.acquire(page.policyMode);
+                        }
+                }
+        }
+
+        Connections {
+                target: cam
+                onIdleChanged: {
+                        if (cam.idle && !platformWindow.active) {
+                                cam.stop();
+                                resourcePolicy.acquire(CameraResources.None);
+                        }
+/*
+                        else if (cam.idle && !page.needsPipeline) {
+                                cam.stop();
+                        }
+*/
+                }
+        }
+
         Rectangle {
                 // TODO: color
                 // TODO: fade out transition
@@ -14,7 +95,7 @@ Page {
                 id: standby
                 color: "black"
                 anchors.fill: parent
-                visible: !platformWindow.active
+                visible: !platformWindow.active || !cam.running || !resourcePolicy.acquired
                 Image {
                         source: "image://theme/icon-l-camera-standby"
                         anchors.centerIn: parent
@@ -37,6 +118,7 @@ Page {
                 anchors.right: parent.right
                 anchors.rightMargin: 20
                 anchors.bottomMargin: 20
+                visible: controlsVisible
         }
 
         PreviewImage {
index e491b69..10d07e1 100644 (file)
@@ -2,11 +2,15 @@
 import QtQuick 1.1
 import com.nokia.meego 1.1
 import QtCamera 1.0
+import CameraPlus 1.0
 import "data.js" as Data
 
-Page {
+CameraPage {
         id: page
-        property Camera cam: null
+
+        controlsVisible: false
+        policyMode: CameraResources.Image
+        needsPipeline: true
 
         Rectangle {
                 color: "black"
index 724c73e..3480808 100644 (file)
@@ -2,10 +2,12 @@
 import QtQuick 1.1
 import com.nokia.meego 1.1
 import QtCamera 1.0
+import CameraPlus 1.0
 
 CameraPage {
         id: page
 
+        policyMode: CameraResources.Image
         controlsVisible: capture.visible && cam.running && !standbyWidget.visible
 
         Button {
index 407612a..7b192ab 100644 (file)
@@ -2,12 +2,15 @@
 import QtQuick 1.1
 import com.nokia.meego 1.1
 import QtCamera 1.0
+import CameraPlus 1.0
 
 import "data.js" as Data
 
-Page {
+CameraPage {
         id: page
-        property Camera cam: null
+        controlsVisible: false
+        policyMode: CameraResources.Image
+        needsPipeline: false
 
         Rectangle {
                 color: "black"
index 3e89c01..213ed98 100644 (file)
@@ -2,11 +2,15 @@
 import QtQuick 1.1
 import com.nokia.meego 1.1
 import QtCamera 1.0
+import CameraPlus 1.0
 import "data.js" as Data
 
-Page {
+CameraPage {
         id: page
-        property Camera cam: null
+
+        controlsVisible: false
+        policyMode: CameraResources.Image
+        needsPipeline: true
 
         Rectangle {
                 color: "black"
index ea5d0e8..f6966e0 100644 (file)
@@ -11,9 +11,28 @@ import CameraPlus 1.0
 
 // TODO: this is really basic.
 
-Page {
+CameraPage {
         id: page
-        property Camera cam: null
+
+        controlsVisible: false
+        policyMode: CameraResources.PostCapture
+        needsPipeline: true
+
+        onStatusChanged: {
+                if (status == PageStatus.Active) {
+                        cam.stop();
+                }
+        }
+
+        Connections {
+                // Unlikely that we need this.
+                target: cam
+                onIdleChanged: {
+                        if (cam.idle && page.status == PageStatus.Active) {
+                                cam.stop();
+                        }
+                }
+        }
 
         Rectangle {
                 color: "black"
@@ -45,12 +64,15 @@ Page {
                                 onStatusChanged: checkStatus(status)
 
                                 function checkStatus(status) {
-                                        if (status == SparqlConnection.Error)
-                                        console.log("Error = "+connection.errorString());
+                                        if (status == SparqlConnection.Error) {
+                                                console.log("Error = "+connection.errorString());
+                                        }
                                 }
                         }
                 }
 
+                // TODO: tap post capture and then immediately back and you can see the error
+                // and the standby widget underneath it.
                 delegate: Item {
                         width: view.width
                         height: view.height
@@ -83,7 +105,7 @@ Page {
                 anchors.bottom: parent.bottom
                 tools: ToolBarLayout {
                         id: layout
-                        ToolIcon { iconId: "icon-m-toolbar-back"; onClicked: pageStack.pop(); }
+                        ToolIcon { iconId: "icon-m-toolbar-back"; onClicked: { cam.start(); pageStack.pop(); } }
                 }
         }
 }
index 8dc4b2a..18ddd39 100644 (file)
@@ -7,6 +7,8 @@ import CameraPlus 1.0
 CameraPage {
         id: page
 
+        policyMode: CameraResources.Video
+
         controlsVisible: recording.visible && cam.running && !standbyWidget.visible
 
         orientationLock: PageOrientation.LockLandscape
@@ -24,20 +26,46 @@ CameraPage {
                 width: 75
                 height: 75
                 opacity: 0.5
+
                 onClicked: {
-                        if (!videoMode.recording) {
-                                if (!fileSystem.available) {
-                                        showError(qsTr("Camera cannot record videos in mass storage mode."));
-                                }
-                                else if (!videoMode.startRecording(fileNaming.videoFileName())) {
-                                        showError(qsTr("Failed to record video. Please restart the camera."));
-                                }
+                        if (!fileSystem.available) {
+                                showError(qsTr("Camera cannot record videos in mass storage mode."));
+                                return;
                         }
-                        else {
+
+                        // We only toggle the mode to video recording so
+                        // policy can acquire the needed resources
+
+                        if (policyMode == CameraResources.Video) {
+                                policyMode = CameraResources.Recording;
+                        }
+                        else if (videoMode.recording) {
+                                // We just ask to stop video.
                                 videoMode.stopRecording();
                         }
                 }
 
+                Connections {
+                        target: videoMode
+                        onRecordingChanged: {
+                                if (!videoMode.recording) {
+                                        policyMode = CameraResources.Video;
+                                }
+                        }
+                }
+
+                Connections {
+                        target: resourcePolicy
+                        onAcquiredChanged: {
+                                if (resourcePolicy.acquired && policyMode == CameraResources.Recording) {
+                                        if (!videoMode.startRecording(fileNaming.videoFileName())) {
+                                                showError(qsTr("Failed to record video. Please restart the camera."));
+                                                policyMode = CameraResources.Video
+}
+                                }
+                        }
+                }
+
                 visible: (videoMode.recording || videoMode.canCapture) && !cameraMode.animationRunning && !previewAnimationRunning && !standbyWidget.visible
         }
 
index bb560a7..7b836eb 100644 (file)
@@ -50,6 +50,18 @@ PageStackWindow {
                 error.show();
         }
 
+        CameraResources {
+                id: resourcePolicy
+                onAcquiredChanged: {
+                        if (resourcePolicy.acquired) {
+                                // TODO:
+                        }
+                        else {
+                                // TODO: We need a way to force a stop.
+                        }
+                }
+        }
+
         DeviceInfo {
                 id: deviceInfo
         }
@@ -100,35 +112,15 @@ PageStackWindow {
                 background: " "
         }
 
-        Connections {
-                target: platformWindow
-                onActiveChanged: {
-                        if (platformWindow.active) {
-                                if (!cam.start()) {
-                                        showError("Camera failed to start. Please restart the camera.");
-                                }
-                        }
-                        else {
-                                // This is a noop if camera is not idle so calling it will not hurt
-                                cam.stop();
-                        }
-                }
-        }
-
         Camera {
-                onIdleChanged: {
-                        if (idle && !platformWindow.active) {
-                                stop();
-                        }
-                }
-
+/*
                 onDeviceIdChanged: {
                         // TODO: is this needed ?
                         if (platformWindow.active) {
                                 cam.start();
                         }
                 }
-
+*/
                 id: cam
                 anchors.fill: parent
 
diff --git a/src/cameraresources.cpp b/src/cameraresources.cpp
new file mode 100644 (file)
index 0000000..3c17741
--- /dev/null
@@ -0,0 +1,142 @@
+#include "cameraresources.h"
+#include <QDebug>
+
+using namespace ResourcePolicy;
+
+CameraResources::CameraResources(QObject *parent) :
+  QObject(parent),
+  m_set(new ResourceSet("camera", this, true, true)),
+  m_mode(None), m_acquired(false) {
+
+  QObject::connect(m_set, SIGNAL(resourcesReleased()), this, SLOT(resourcesReleased()));
+  QObject::connect(m_set, SIGNAL(lostResources()), this, SLOT(lostResources()));
+  QObject::connect(m_set, SIGNAL(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)),
+                  this, SLOT(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)));
+  QObject::connect(m_set, SIGNAL(updateOK()), this, SLOT(updateOK()));
+
+  if (!m_set->initAndConnect()) {
+    qCritical() << "Failed to connect to resource policy engine";
+  }
+}
+
+CameraResources::~CameraResources() {
+  acquire(None);
+}
+
+void CameraResources::acquire(const CameraResources::Mode& mode) {
+  if (mode == m_mode) {
+    // We need to emit this because the UI migh be waiting
+    emit acquiredChanged();
+    return;
+  }
+
+  m_mode = mode;
+
+  switch (m_mode) {
+  case None:
+    m_set->release();
+    break;
+
+  case Image:
+    updateSet(QList<ResourcePolicy::ResourceType>()
+             << ResourcePolicy::VideoPlaybackType
+             << ResourcePolicy::VideoRecorderType
+             << ResourcePolicy::ScaleButtonType
+             << ResourcePolicy::SnapButtonType);
+    break;
+
+  case Video:
+    updateSet(QList<ResourcePolicy::ResourceType>()
+             << ResourcePolicy::VideoPlaybackType
+             << ResourcePolicy::VideoRecorderType
+             << ResourcePolicy::ScaleButtonType
+             << ResourcePolicy::SnapButtonType);
+    break;
+
+  case Recording:
+    updateSet(QList<ResourcePolicy::ResourceType>()
+             << ResourcePolicy::VideoPlaybackType
+             << ResourcePolicy::VideoRecorderType
+             << ResourcePolicy::ScaleButtonType
+             << ResourcePolicy::SnapButtonType
+             << ResourcePolicy::AudioRecorderType,
+             QList<ResourcePolicy::ResourceType>()
+             << ResourcePolicy::AudioPlaybackType);
+    break;
+
+  case PostCapture:
+    updateSet(QList<ResourcePolicy::ResourceType>()
+             << ResourcePolicy::VideoPlaybackType
+             << ResourcePolicy::ScaleButtonType,
+             QList<ResourcePolicy::ResourceType>()
+             << ResourcePolicy::AudioPlaybackType);
+
+    break;
+
+  default:
+    qWarning() << "Unknown mode" << mode;
+
+    break;
+  }
+}
+
+bool CameraResources::acquired() const {
+  return m_acquired;
+}
+
+void CameraResources::resourcesReleased() {
+  m_mode = None;
+  m_acquired = false;
+  emit acquiredChanged();
+}
+
+void CameraResources::lostResources() {
+  m_mode = None;
+  m_acquired = false;
+  emit acquiredChanged();
+}
+
+void CameraResources::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
+  Q_UNUSED(optional);
+
+  m_acquired = true;
+  emit acquiredChanged();
+}
+
+void CameraResources::updateOK() {
+  m_acquired = true;
+  emit acquiredChanged();
+}
+
+QList<ResourcePolicy::ResourceType> CameraResources::listSet() {
+  QList<Resource *> resources = m_set->resources();
+  QList<ResourcePolicy::ResourceType> set;
+
+  foreach (Resource *r, resources) {
+    set << r->type();
+  }
+
+  return set;
+}
+
+void CameraResources::updateSet(const QList<ResourcePolicy::ResourceType>& required,
+                               const QList<ResourcePolicy::ResourceType>& optional) {
+
+  QList<ResourcePolicy::ResourceType> set = listSet();
+
+  foreach (ResourceType r, set) {
+    // Check for acquired resources that should be dropped.
+    if (required.indexOf(r) == -1) {
+      m_set->deleteResource(r);
+    }
+  }
+
+  foreach (ResourceType r, required) {
+    // TODO: AudioPlayback needs special handling
+    m_set->addResource(r);
+  }
+
+  // TODO: optional resources
+
+  m_set->update();
+}
diff --git a/src/cameraresources.h b/src/cameraresources.h
new file mode 100644 (file)
index 0000000..9c77608
--- /dev/null
@@ -0,0 +1,54 @@
+// -*- c++ -*-
+
+#ifndef CAMERA_RESOURCES_H
+#define CAMERA_RESOURCES_H
+
+#include <QObject>
+#include <policy/resource-set.h>
+
+class CameraResources : public QObject {
+  Q_OBJECT
+
+  Q_PROPERTY(bool acquired READ acquired NOTIFY acquiredChanged);
+
+  Q_ENUMS(Mode);
+
+public:
+  typedef enum {
+    None,
+    Image,
+    Video,
+    Recording,
+    PostCapture,
+  } Mode;
+
+  CameraResources(QObject *parent = 0);
+  ~CameraResources();
+
+  bool acquired() const;
+
+public slots:
+  void acquire(const Mode& mode);
+
+signals:
+  void acquiredChanged();
+
+private slots:
+  void resourcesReleased();
+  void lostResources();
+  void resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional);
+  void updateOK();
+
+private:
+  void updateSet(const QList<ResourcePolicy::ResourceType>& required,
+                const QList<ResourcePolicy::ResourceType>& optional =
+                QList<ResourcePolicy::ResourceType>());
+
+  QList<ResourcePolicy::ResourceType> listSet();
+
+  ResourcePolicy::ResourceSet *m_set;
+  Mode m_mode;
+  bool m_acquired;
+};
+
+#endif /* CAMERA_RESOURCES_H */
index 8184457..816b399 100644 (file)
@@ -12,6 +12,7 @@
 #include "quillitem.h"
 #include "displaystate.h"
 #include "fsmonitor.h"
+#include "cameraresources.h"
 
 Q_DECL_EXPORT int main(int argc, char *argv[]) {
   QApplication::setAttribute(Qt::AA_X11InitThreads, true);
@@ -28,6 +29,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) {
   qmlRegisterType<QuillItem>("CameraPlus", 1, 0, "QuillItem");
   qmlRegisterType<DisplayState>("CameraPlus", 1, 0, "DisplayState");
   qmlRegisterType<FSMonitor>("CameraPlus", 1, 0, "FSMonitor");
+  qmlRegisterType<CameraResources>("CameraPlus", 1, 0, "CameraResources");
 
   QUrl sourceUrl = QUrl::fromLocalFile(QDir::currentPath() + "/main.qml");
   view.setSource(sourceUrl);
index de19a5f..b00eac8 100644 (file)
@@ -8,9 +8,13 @@ QT += declarative opengl
 CONFIG += link_pkgconfig debug static
 
 PKGCONFIG = gstreamer-0.10 gstreamer-interfaces-0.10 gstreamer-video-0.10 gstreamer-tag-0.10 \
-            gstreamer-pbutils-0.10 meego-gstreamer-interfaces-0.10 quill qmsystem2
+            gstreamer-pbutils-0.10 meego-gstreamer-interfaces-0.10 quill qmsystem2 libresourceqt1
+
 
 LIBS +=  -L../imports/ -limports -L../lib/ -lqtcamera
 
-SOURCES += main.cpp settings.cpp filenaming.cpp quillitem.cpp displaystate.cpp fsmonitor.cpp
-HEADERS += settings.h filenaming.h quillitem.h displaystate.h fsmonitor.h
+SOURCES += main.cpp settings.cpp filenaming.cpp quillitem.cpp displaystate.cpp fsmonitor.cpp \
+           cameraresources.cpp
+
+HEADERS += settings.h filenaming.h quillitem.h displaystate.h fsmonitor.h \
+           cameraresources.h