From: Mohammed Sameer Date: Thu, 13 Sep 2012 19:26:17 +0000 (+0300) Subject: Added resource policy support (Still needs more testing) and refactored the pipeline... X-Git-Url: http://cgit.sxemacs.org/?p=harmattan%2Fcameraplus;a=commitdiff_plain;h=2f1d2f53a9949cddb795498edccc6ec690dc70ec Added resource policy support (Still needs more testing) and refactored the pipeline handling logic --- diff --git a/imports/camera.cpp b/imports/camera.cpp index cc27106..470afa2 100644 --- a/imports/camera.cpp +++ b/imports/camera.cpp @@ -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() { diff --git a/imports/camera.h b/imports/camera.h index 4cf978f..a9507ff 100644 --- a/imports/camera.h +++ b/imports/camera.h @@ -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(); diff --git a/lib/qtcamdevice.cpp b/lib/qtcamdevice.cpp index 637286b..6197dc3 100644 --- a/lib/qtcamdevice.cpp +++ b/lib/qtcamdevice.cpp @@ -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) { diff --git a/lib/qtcamgraphicsviewfinder.cpp b/lib/qtcamgraphicsviewfinder.cpp index 342255a..8ce2c69 100644 --- a/lib/qtcamgraphicsviewfinder.cpp +++ b/lib/qtcamgraphicsviewfinder.cpp @@ -109,3 +109,7 @@ void QtCamGraphicsViewfinder::resizeEvent(QGraphicsSceneResizeEvent *event) { void QtCamGraphicsViewfinder::updateRequested() { update(); } + +void QtCamGraphicsViewfinder::stop() { + d_ptr->resetBackend(); +} diff --git a/lib/qtcamgraphicsviewfinder.h b/lib/qtcamgraphicsviewfinder.h index b8bd811..157dd4c 100644 --- a/lib/qtcamgraphicsviewfinder.h +++ b/lib/qtcamgraphicsviewfinder.h @@ -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); diff --git a/lib/qtcamviewfinder.h b/lib/qtcamviewfinder.h index cefa84b..0601e8d 100644 --- a/lib/qtcamviewfinder.h +++ b/lib/qtcamviewfinder.h @@ -14,6 +14,7 @@ public: virtual GstElement *sinkElement() = 0; virtual bool setDevice(QtCamDevice *device) = 0; + virtual void stop() = 0; }; #endif /* QT_CAM_VIEWFINDER_H */ diff --git a/lib/qtcamviewfinderrenderermeego.cpp b/lib/qtcamviewfinderrenderermeego.cpp index 9c20ff3..90ac984 100644 --- a/lib/qtcamviewfinderrenderermeego.cpp +++ b/lib/qtcamviewfinderrenderermeego.cpp @@ -106,7 +106,8 @@ void QtCamViewfinderRendererMeeGo::resize(const QSizeF& size) { } void QtCamViewfinderRendererMeeGo::reset() { - // Nothing. + QMutexLocker locker(&m_frameMutex); + m_frame = -1; } GstElement *QtCamViewfinderRendererMeeGo::sinkElement() { diff --git a/qml/CameraPage.qml b/qml/CameraPage.qml index cde3fbd..4ba3bc0 100644 --- a/qml/CameraPage.qml +++ b/qml/CameraPage.qml @@ -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 { diff --git a/qml/ImageColorFilterPage.qml b/qml/ImageColorFilterPage.qml index e491b69..10d07e1 100644 --- a/qml/ImageColorFilterPage.qml +++ b/qml/ImageColorFilterPage.qml @@ -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" diff --git a/qml/ImagePage.qml b/qml/ImagePage.qml index 724c73e..3480808 100644 --- a/qml/ImagePage.qml +++ b/qml/ImagePage.qml @@ -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 { diff --git a/qml/ImageSettingsPage.qml b/qml/ImageSettingsPage.qml index 407612a..7b192ab 100644 --- a/qml/ImageSettingsPage.qml +++ b/qml/ImageSettingsPage.qml @@ -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" diff --git a/qml/ImageWhiteBalancePage.qml b/qml/ImageWhiteBalancePage.qml index 3e89c01..213ed98 100644 --- a/qml/ImageWhiteBalancePage.qml +++ b/qml/ImageWhiteBalancePage.qml @@ -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" diff --git a/qml/PostCapturePage.qml b/qml/PostCapturePage.qml index ea5d0e8..f6966e0 100644 --- a/qml/PostCapturePage.qml +++ b/qml/PostCapturePage.qml @@ -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(); } } } } } diff --git a/qml/VideoPage.qml b/qml/VideoPage.qml index 8dc4b2a..18ddd39 100644 --- a/qml/VideoPage.qml +++ b/qml/VideoPage.qml @@ -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 } diff --git a/qml/main.qml b/qml/main.qml index bb560a7..7b836eb 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -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 index 0000000..3c17741 --- /dev/null +++ b/src/cameraresources.cpp @@ -0,0 +1,142 @@ +#include "cameraresources.h" +#include + +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&)), + this, SLOT(resourcesGranted(const QList&))); + 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::VideoPlaybackType + << ResourcePolicy::VideoRecorderType + << ResourcePolicy::ScaleButtonType + << ResourcePolicy::SnapButtonType); + break; + + case Video: + updateSet(QList() + << ResourcePolicy::VideoPlaybackType + << ResourcePolicy::VideoRecorderType + << ResourcePolicy::ScaleButtonType + << ResourcePolicy::SnapButtonType); + break; + + case Recording: + updateSet(QList() + << ResourcePolicy::VideoPlaybackType + << ResourcePolicy::VideoRecorderType + << ResourcePolicy::ScaleButtonType + << ResourcePolicy::SnapButtonType + << ResourcePolicy::AudioRecorderType, + QList() + << ResourcePolicy::AudioPlaybackType); + break; + + case PostCapture: + updateSet(QList() + << ResourcePolicy::VideoPlaybackType + << ResourcePolicy::ScaleButtonType, + QList() + << 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& optional) { + Q_UNUSED(optional); + + m_acquired = true; + emit acquiredChanged(); +} + +void CameraResources::updateOK() { + m_acquired = true; + emit acquiredChanged(); +} + +QList CameraResources::listSet() { + QList resources = m_set->resources(); + QList set; + + foreach (Resource *r, resources) { + set << r->type(); + } + + return set; +} + +void CameraResources::updateSet(const QList& required, + const QList& optional) { + + QList 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 index 0000000..9c77608 --- /dev/null +++ b/src/cameraresources.h @@ -0,0 +1,54 @@ +// -*- c++ -*- + +#ifndef CAMERA_RESOURCES_H +#define CAMERA_RESOURCES_H + +#include +#include + +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& optional); + void updateOK(); + +private: + void updateSet(const QList& required, + const QList& optional = + QList()); + + QList listSet(); + + ResourcePolicy::ResourceSet *m_set; + Mode m_mode; + bool m_acquired; +}; + +#endif /* CAMERA_RESOURCES_H */ diff --git a/src/main.cpp b/src/main.cpp index 8184457..816b399 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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("CameraPlus", 1, 0, "QuillItem"); qmlRegisterType("CameraPlus", 1, 0, "DisplayState"); qmlRegisterType("CameraPlus", 1, 0, "FSMonitor"); + qmlRegisterType("CameraPlus", 1, 0, "CameraResources"); QUrl sourceUrl = QUrl::fromLocalFile(QDir::currentPath() + "/main.qml"); view.setSource(sourceUrl); diff --git a/src/src.pro b/src/src.pro index de19a5f..b00eac8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -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