QtMobility Reference Documentation

QML Video Example

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.

Overview

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.

Application structure

The video/qmlvideo/qml/qmlvideo/main.qml file creates a UI which includes the following elements:

  • Two Button elements, each of which displays a filename, and can be used to launch a FileBrowser
  • An exit Button
  • A SceneSelectionPanel, which is a flickable list displaying the available scenes
  • At the lower left, an item which displays the QML repainting rate - the upper number is the instantaneous frame rate and the lower number is the average over the past second.
  • At the lower right (on Symbian only), an item which displays graphics memory consumption information:total memory used; memory used by current process; total memory.

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.

Calculating and displaying QML painting rate

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()));

Querying and displaying graphics memory consumption

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

  • Total graphics memory
  • Total currently used graphics memory
  • Graphics memory used by calling process

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:

X

Thank you for giving your feedback.

Make sure it is related to this specific page. For more general bugs and requests, please use the Qt Bug Tracker.