Files:
Images:
The QML Video Example demonstrates the various manipulations (move; resize; rotate; change aspect ratio) which can be applied to QML Video and Camera items.
This example demonstrates the various manipulations (move; resize; rotate; change aspect ratio) which can be applied to QML Video and Camera items.
It also shows how native code can be combined with QML to implement more advanced functionality - in this case, C++ code is used to calculate the QML frame rate and (on Symbian) the graphics memory consumption; these metrics are rendered in QML as semi-transparent items overlaid on the video content.
The following image shows the application executing the video-overlay scene, which creates a dummy overlay item (just a semi-transparent Rectangle), which moves across the Video item.
The video/qmlvideo/qml/qmlvideo/main.qml file creates a UI which includes the following elements:
Each scene in the flickable list is implemented in its own QML file - for example the video-basic scene (which just displays a static Video element in the center of the screen) is implemented in the VideoBasic.qml file. As you can see from the code, this makes use of a type of inheritance: a VideoBasic element ...
import QtQuick 1.0 SceneBasic { contentType: "video" }
... is-a SceneBasic ...
import QtQuick 1.0 Scene { id: root property string contentType ... Content { id: content ... } Text { anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom margins: 20 } text: content.started ? "Tap the screen to stop content" : "Tap the screen to start content" color: "yellow" font.pixelSize: 20 z: 2.0 } MouseArea { anchors.fill: parent onClicked: { console.log("[qmlvideo] SceneBasic.onClicked, started = " + content.started) if (content.started) content.stop() else content.start() } } Component.onCompleted: root.content = content }
... which is-a Scene:
import QtQuick 1.0 Rectangle { id: root ... property QtObject content ... Button { id: closeButton anchors { top: parent.top right: parent.right margins: root.margins } width: 50 height: 30 z: 2.0 text: "Back" onClicked: root.close() } }
SceneBasic describes the structure and behaviour of the scene, but is agnostic of the type of content which will be displayed - this is abstracted by the Content element.
This pattern allows us to define a particular use case (in this case, simply display a static piece of content), and then instantiate that use case for both video content (VideoBasic) and cameracontent (CameraBasic). This approach is used to implement many of the other scenes - for example, "repeatedly slide the content from left to right and back again" is implemented by SceneMove, on which VideoMove and CameraMove are based.
Depending on the value of the contentType property in the top-level scene element, the embedded Content item creates either a Video or Camera item.
The QML painting rate is calculated by first creating a QObject-derived class called PaintEventMonitor, which allows its client to provide a QWidget to be monitored, and which emits a signal when that widget is repainted:
class PaintEventMonitor : public QObject { Q_OBJECT Q_PROPERTY(QWidget *target READ target WRITE setTarget NOTIFY targetChanged) ... protected: bool eventFilter(QObject *object, QEvent *event); signals: void targetPainted(); private: QWidget *m_target; };
The signal is generated by installing an event filter on the target QWidget:
bool PaintEventMonitor::eventFilter(QObject *object, QEvent *event) { if (m_target == object && event->type() == QEvent::Paint) emit targetPainted(); return QObject::eventFilter(object, event); }
A second class, FrequencyMonitor, is used to turn the stream of targetPainted() signals into an instantaneous and an averaged frequency:
class FrequencyMonitor : public QObject { Q_OBJECT Q_PROPERTY(qreal instantaneousFrequency READ instantaneousFrequency NOTIFY instantaneousFrequencyChanged) Q_PROPERTY(qreal averageFrequency READ averageFrequency NOTIFY averageFrequencyChanged) public: ... static void qmlRegisterType(); public slots: Q_INVOKABLE void notify(); };
The FrequencyMonitor class is exposed to QML like this
void FrequencyMonitor::qmlRegisterType() { ::qmlRegisterType<FrequencyMonitor>("FrequencyMonitor", 1, 0, "FrequencyMonitor"); }
and its data is displayed by defining a QML item called FrequencyItem, like this:
import FrequencyMonitor 1.0 Rectangle { id: root ... function notify() { monitor.notify() } FrequencyMonitor { id: monitor onAverageFrequencyChanged: {
The result looks like this:
All that remains is to create a PaintEventMonitor in the C++ main() function, tell it to monitor the QML viewport widget, and to connect its framePainted() signal to a JavaScript function, which will eventually call frequencyItem.notify():
QmlApplicationViewer viewer; ... QGraphicsObject *rootObject = viewer.rootObject(); ... PaintEventMonitor paintEventMonitor; paintEventMonitor.setTarget(viewer.viewport()); QObject::connect(&paintEventMonitor, SIGNAL(targetPainted()), rootObject, SLOT(qmlFramePainted()));
On Symbian, graphics memory consumption is an important consideration, because many of the current devices have a limited amount of graphics memory, which is shared by both the graphics stack (for OpenGLES / OpenVG rendering) and the camera/video stack. For this reason, being able to track the amount of graphics memory being consumed by a given use case can be useful during application development. This application demonstrates how this can be done, by using some native code to query graphics memory consumption information from a platform API, and a QML element to display this on screen in an overlay item.
Starting with Symbian Anna, the platform implements an EGL extension called EGL_NOK_resource_profiling. This allows the client to query
Being an EGL extension, this API isn't particularly friendly to use, so this example provides a simple Qt wrapper:
class GraphicsMemoryMonitor : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(GraphicsMemoryMonitor) Q_PROPERTY(bool active READ active NOTIFY activeChanged) Q_PROPERTY(qint64 totalMemory READ totalMemory NOTIFY totalMemoryChanged) Q_PROPERTY(QString totalMemoryHumanReadable READ totalMemoryHumanReadable NOTIFY totalMemoryHumanReadableChanged) Q_PROPERTY(qint64 usedMemory READ usedMemory NOTIFY usedMemoryChanged) Q_PROPERTY(QString usedMemoryHumanReadable READ usedMemoryHumanReadable NOTIFY usedMemoryHumanReadableChanged) Q_PROPERTY(qint64 availableMemory READ availableMemory NOTIFY availableMemoryChanged) Q_PROPERTY(QString availableMemoryHumanReadable READ availableMemoryHumanReadable NOTIFY availableMemoryHumanReadableChanged) Q_PROPERTY(qint64 currentProcessUsage READ currentProcessUsage NOTIFY currentProcessUsageChanged) Q_PROPERTY(QString currentProcessUsageHumanReadable READ currentProcessUsageHumanReadable NOTIFY currentProcessUsageHumanReadableChanged) Q_PROPERTY(qint64 updateInterval READ updateInterval WRITE setUpdateInterval NOTIFY updateIntervalChanged) ... };
This class is exposed to QML like this:
void GraphicsMemoryMonitor::qmlRegisterType() { ::qmlRegisterType<GraphicsMemoryMonitor>("GraphicsMemoryMonitor", 1, 0, "GraphicsMemoryMonitor"); }
And then the information is displayed by the GraphicsMemoryItem element:
import QtQuick 1.0 import GraphicsMemoryMonitor 1.0 Rectangle { id: root property bool logging: true property bool displayed: true property bool enabled: logging || displayed property int updateInterval: 500 property color textColor: "yellow" property int textSize: 20 border.width: 1 border.color: "yellow" width: 5.6 * root.textSize height: 4.3 * root.textSize color: "black" opacity: 0.5 radius: 10 visible: displayed && monitor.active // This should ensure that the monitor is on top of all other content z: 999 GraphicsMemoryMonitor { id: monitor updateInterval: root.enabled ? root.updateInterval : 0 onChanged: if (root.logging) trace() } Text { anchors { right: parent.right top: parent.top margins: 10 } color: root.textColor font.pixelSize: root.textSize text: monitor.usedMemoryHumanReadable } Text { anchors { right: parent.right verticalCenter: parent.verticalCenter margins: 10 } color: root.textColor font.pixelSize: root.textSize text: monitor.currentProcessUsageHumanReadable } Text { anchors { right: parent.right bottom: parent.bottom margins: 10 } color: root.textColor font.pixelSize: root.textSize text: monitor.totalMemoryHumanReadable } }
The result looks like this: