summaryrefslogtreecommitdiff
path: root/qt
diff options
context:
space:
mode:
authorAlexandre Moreno <alexmorenocano@gmail.com>2015-06-12 01:47:56 +0800
committerSebastian Dröge <sebastian@centricular.com>2015-10-04 19:09:50 +0100
commit2a015d082611b41efee8c8641985ca63189fb585 (patch)
tree3be26885573ab49a4f73c0e6323cbd165b2438eb /qt
parentd70f5d7782ae0fd83e7ae1300af5cb68db6492c1 (diff)
Add Qt bindings and player
Diffstat (limited to 'qt')
-rw-r--r--qt/deployment.pri27
-rw-r--r--qt/fontawesome-webfont.ttfbin0 -> 122092 bytes
-rw-r--r--qt/fontawesome-webfont.ttf.txt10
-rw-r--r--qt/fontawesome.js214
-rw-r--r--qt/main.cpp52
-rw-r--r--qt/main.qml461
-rw-r--r--qt/play.pro53
-rw-r--r--qt/player.cpp41
-rw-r--r--qt/player.h44
-rw-r--r--qt/qgstplayer.cpp435
-rw-r--r--qt/qgstplayer.h162
-rw-r--r--qt/qml.qrc9
-rw-r--r--qt/quickrenderer.cpp56
-rw-r--r--qt/quickrenderer.h42
14 files changed, 1606 insertions, 0 deletions
diff --git a/qt/deployment.pri b/qt/deployment.pri
new file mode 100644
index 0000000..5441b63
--- /dev/null
+++ b/qt/deployment.pri
@@ -0,0 +1,27 @@
+android-no-sdk {
+ target.path = /data/user/qt
+ export(target.path)
+ INSTALLS += target
+} else:android {
+ x86 {
+ target.path = /libs/x86
+ } else: armeabi-v7a {
+ target.path = /libs/armeabi-v7a
+ } else {
+ target.path = /libs/armeabi
+ }
+ export(target.path)
+ INSTALLS += target
+} else:unix {
+ isEmpty(target.path) {
+ qnx {
+ target.path = /tmp/$${TARGET}/bin
+ } else {
+ target.path = /opt/$${TARGET}/bin
+ }
+ export(target.path)
+ }
+ INSTALLS += target
+}
+
+export(INSTALLS)
diff --git a/qt/fontawesome-webfont.ttf b/qt/fontawesome-webfont.ttf
new file mode 100644
index 0000000..ed9372f
--- /dev/null
+++ b/qt/fontawesome-webfont.ttf
Binary files differ
diff --git a/qt/fontawesome-webfont.ttf.txt b/qt/fontawesome-webfont.ttf.txt
new file mode 100644
index 0000000..946b3cb
--- /dev/null
+++ b/qt/fontawesome-webfont.ttf.txt
@@ -0,0 +1,10 @@
+
+Font Awesome
+
+URL: http://fontawesome.io
+
+Font License
+
+License: SIL OFL 1.1
+URL: http://scripts.sil.org/OFL
+
diff --git a/qt/fontawesome.js b/qt/fontawesome.js
new file mode 100644
index 0000000..8d135e1
--- /dev/null
+++ b/qt/fontawesome.js
@@ -0,0 +1,214 @@
+var Icon = {
+ Glass : "\uf000",
+ Music : "\uf001",
+ Search : "\uf002",
+ Envelope : "\uf003",
+ Heart : "\uf004",
+ Star : "\uf005",
+ StarEmpty : "\uf006",
+ User : "\uf007",
+ Film : "\uf008",
+ ThLarge : "\uf009",
+ Th : "\uf00a",
+ ThList : "\uf00b",
+ Ok : "\uf00c",
+ Remove : "\uf00d",
+ ZoomIn : "\uf00e",
+ ZoomOut : "\uf010",
+ Off : "\uf011",
+ Signal : "\uf012",
+ Cog : "\uf013",
+ Trash : "\uf014",
+ Home : "\uf015",
+ File : "\uf016",
+ Time : "\uf017",
+ Road : "\uf018",
+ DownloadAlt : "\uf019",
+ Download : "\uf01a",
+ Upload : "\uf01b",
+ Inbox : "\uf01c",
+ PlayCircle : "\uf01d",
+ Repeat : "\uf01e",
+ Refresh : "\uf021",
+ ListAlt : "\uf022",
+ Lock : "\uf023",
+ Flag : "\uf024",
+ Headphones : "\uf025",
+ VolumeOff : "\uf026",
+ VolumeDown : "\uf027",
+ VolumeUp : "\uf028",
+ Qrcode : "\uf029",
+ Barcode : "\uf02a",
+ Tag : "\uf02b",
+ Tags : "\uf02c",
+ Book : "\uf02d",
+ Bookmark : "\uf02e",
+ Print : "\uf02f",
+ Camera : "\uf030",
+ Font : "\uf031",
+ Bold : "\uf032",
+ Italic : "\uf033",
+ TextHeight : "\uf034",
+ TextWidth : "\uf035",
+ AlignLeft : "\uf036",
+ AlignCenter : "\uf037",
+ AlignRight : "\uf038",
+ AlignJustify : "\uf039",
+ List : "\uf03a",
+ IndentLeft : "\uf03b",
+ IndentRight : "\uf03c",
+ FacetimeVideo : "\uf03d",
+ Picture : "\uf03e",
+ Pencil : "\uf040",
+ MapMarker : "\uf041",
+ Adjust : "\uf042",
+ Tint : "\uf043",
+ Edit : "\uf044",
+ Share : "\uf045",
+ Check : "\uf046",
+ Move : "\uf047",
+ StepBackward : "\uf048",
+ StepForward : "\uf049",
+ Backward : "\uf04a",
+ Play : "\uf04b",
+ Pause : "\uf04c",
+ Stop : "\uf04d",
+ Forward : "\uf04e",
+ FastForward : "\uf050",
+ StepForward : "\uf051",
+ Eject : "\uf052",
+ ChevronLeft : "\uf053",
+ ChevronRight : "\uf054",
+ PlusSign : "\uf055",
+ MinusSign : "\uf056",
+ RemoveSign : "\uf057",
+ OkSign : "\uf058",
+ QuestionSign : "\uf059",
+ InfoSign : "\uf05a",
+ Screenshot : "\uf05b",
+ RemoveCircle : "\uf05c",
+ OkCircle : "\uf05d",
+ BanCircle : "\uf05e",
+ ArrowLeft : "\uf060",
+ ArrowRight : "\uf061",
+ ArrowUp : "\uf062",
+ ArrowDown : "\uf063",
+ ShareAlt : "\uf064",
+ ResizeFull : "\uf065",
+ ResizeSmall : "\uf066",
+ Plus : "\uf067",
+ Minus : "\uf068",
+ Asterish : "\uf069",
+ ExclamationSign : "\uf06a",
+ Gift : "\uf06b",
+ Leave : "\uf06c",
+ Fire : "\uf06d",
+ EyeOpen : "\uf06e",
+ EyeClose : "\uf070",
+ WarningSign : "\uf071",
+ Plane : "\uf072",
+ Calendar : "\uf073",
+ Random : "\uf074",
+ Comment : "\uf075",
+ Magnet : "\uf076",
+ ChevronUp : "\uf077",
+ ChevronDown : "\uf078",
+ Retweet : "\uf079",
+ ShoppingCart : "\uf07a",
+ FolderClose : "\uf07b",
+ FolderOpen : "\uf07c",
+ ResizeVertical : "\uf07d",
+ ResizeHorizontal : "\uf07e",
+ BarChart : "\uf080",
+ TwitterSign : "\uf081",
+ FacebookSign : "\uf082",
+ CameraRetro : "\uf083",
+ Key : "\uf084",
+ Cogs : "\uf085",
+ Comments : "\uf086",
+ ThumbsUp : "\uf087",
+ ThumbsDown : "\uf088",
+ StarHalf : "\uf089",
+ HeartEmpty : "\uf08a",
+ Signout : "\uf08b",
+ LinkedinSign : "\uf08c",
+ Pushpin : "\uf08d",
+ ExternalLink : "\uf08e",
+ Signin : "\uf090",
+ Trophy : "\uf091",
+ GithubSign : "\uf092",
+ UploadAlt : "\uf093",
+ Lemon : "\uf094",
+ Phone : "\uf095",
+ CheckEmpty : "\uf096",
+ BookmarkEmpty : "\uf097",
+ PhoneSign : "\uf098",
+ Twitter : "\uf099",
+ Facebook : "\uf09a",
+ Github : "\uf09b",
+ Unlock : "\uf09c",
+ CreditCard : "\uf09d",
+ Rss : "\uf09e",
+ Hdd : "\uf0a0",
+ Bullhorn : "\uf0a1",
+ Bell : "\uf0a2",
+ Certificate : "\uf0a3",
+ HandRight : "\uf0a4",
+ HandLeft : "\uf0a5",
+ HandUp : "\uf0a6",
+ HandDown : "\uf0a7",
+ CircleArrowLeft : "\uf0a8",
+ CircleArrowRight : "\uf0a9",
+ CircleArrowUp : "\uf0aa",
+ CircleArrowDown : "\uf0ab",
+ Globe : "\uf0ac",
+ Wrench : "\uf0ad",
+ Tasks : "\uf0ae",
+ Filter : "\uf0b0",
+ Briefcase : "\uf0b1",
+ Fullscreen : "\uf0b2",
+ Group : "\uf0c0",
+ Link : "\uf0c1",
+ Cloud : "\uf0c2",
+ Beaker : "\uf0c3",
+ Cut : "\uf0c4",
+ Copy : "\uf0c5",
+ PaperClip : "\uf0c6",
+ Save : "\uf0c7",
+ SignBlank : "\uf0c8",
+ Reorder : "\uf0c9",
+ ListUl : "\uf0ca",
+ ListOl : "\uf0cb",
+ Strikethrough : "\uf0cc",
+ Underline : "\uf0cd",
+ Table : "\uf0ce",
+ Magic : "\uf0d0",
+ Truck : "\uf0d1",
+ Pinterest : "\uf0d2",
+ PinterestSign : "\uf0d3",
+ GooglePlusSign : "\uf0d4",
+ GooglePlus : "\uf0d5",
+ Money : "\uf0d6",
+ CaretDown : "\uf0d7",
+ CaretUp : "\uf0d8",
+ CaretLeft : "\uf0d9",
+ CaretRight : "\uf0da",
+ Columns : "\uf0db",
+ Sort : "\uf0dc",
+ SortDown : "\uf0dd",
+ SortUp : "\uf0de",
+ EnvelopeAlt : "\uf0e0",
+ Linkedin : "\uf0e1",
+ Undo : "\uf0e2",
+ Legal : "\uf0e3",
+ Dashboard : "\uf0e4",
+ CommentAlt : "\uf0e5",
+ CommentsAlt : "\uf0e6",
+ Bolt : "\uf0e7",
+ Sitemap : "\uf0e8",
+ Unbrella : "\uf0e9",
+ Paste : "\uf0ea",
+ ClosedCaptions : "\uf20a",
+ UserMd : "\uf200",
+};
+
diff --git a/qt/main.cpp b/qt/main.cpp
new file mode 100644
index 0000000..5634732
--- /dev/null
+++ b/qt/main.cpp
@@ -0,0 +1,52 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <QApplication>
+#include <QQmlApplicationEngine>
+
+#include "player.h"
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<Player>("Player", 1, 0, "Player");
+
+ /* the plugin must be loaded before loading the qml file to register the
+ * GstGLVideoItem qml item
+ * FIXME Add a QQmlExtensionPlugin into qmlglsink to register GstGLVideoItem
+ * with the QML engine, then remove this */
+ gst_init(NULL,NULL);
+ GstElement *sink = gst_element_factory_make ("qmlglsink", NULL);
+ gst_object_unref(sink);
+
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ QObject *rootObject = engine.rootObjects().first();
+
+ Player *player = rootObject->findChild<Player*>("player");
+ QQuickItem *videoItem = rootObject->findChild<QQuickItem*>("videoItem");
+ player->setVideoOutput(videoItem);
+
+
+ return app.exec();
+}
diff --git a/qt/main.qml b/qt/main.qml
new file mode 100644
index 0000000..c7fe424
--- /dev/null
+++ b/qt/main.qml
@@ -0,0 +1,461 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.4
+import QtQuick.Controls 1.1
+import QtQuick.Controls.Styles 1.3
+import QtQuick.Dialogs 1.2
+import QtQuick.Window 2.1
+import Player 1.0
+import org.freedesktop.gstreamer.GLVideoItem 1.0
+
+import "fontawesome.js" as FontAwesome
+
+ApplicationWindow {
+ id: window
+ visible: true
+ width: 640
+ height: 480
+ x: 30
+ y: 30
+ color: "black"
+// title : player.mediaInfo.title
+
+ Player {
+ id: player
+ objectName: "player"
+ volume: 0.5
+ onStateChanged: {
+ if (state === Player.STOPPED) {
+ playbutton.text = FontAwesome.Icon.Play
+ }
+ }
+ onResolutionChanged: {
+ if (player.videoAvailable) {
+ window.width = resolution.width
+ window.height = resolution.height
+ }
+ }
+ }
+
+ GstGLVideoItem {
+ id: video
+ objectName: "videoItem"
+ anchors.centerIn: parent
+ width: 640
+ height: 480
+ }
+
+ FileDialog {
+ id: fileDialog
+ //nameFilters: [TODO globs from mime types]
+ onAccepted: player.source = fileUrl
+ }
+
+ Action {
+ id: fileOpenAction
+ text: "Open"
+ onTriggered: fileDialog.open()
+ }
+
+ menuBar: MenuBar {
+ Menu {
+ title: "&File"
+ MenuItem { action: fileOpenAction }
+ MenuItem { text: "Quit"; onTriggered: Qt.quit() }
+ }
+ }
+
+ Item {
+ anchors.fill: parent
+ FontLoader {
+ source: "fonts/fontawesome-webfont.ttf"
+ }
+
+ Rectangle {
+ id : playbar
+ color: Qt.rgba(1, 1, 1, 0.7)
+ border.width: 1
+ border.color: "white"
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 15
+ anchors.horizontalCenter: parent.horizontalCenter
+ width : grid.width + 20
+ height: 40//childrenRect.height + 20
+ radius: 5
+
+ MouseArea {
+ id: mousearea
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: {
+ parent.opacity = 1.0
+ hidetimer.start()
+ }
+ }
+
+ Timer {
+ id: hidetimer
+ interval: 10000
+ onTriggered: {
+ parent.opacity = 0.0
+ stop()
+ }
+ }
+
+ Grid {
+ id: grid
+ anchors.horizontalCenter: parent.horizontalCenter
+// anchors.top: parent.top
+// anchors.topMargin: 5
+
+ spacing: 7
+ rows: 1
+ verticalItemAlignment: Qt.AlignVCenter
+
+ Text {
+ id : openmedia
+ font.pointSize: 17
+ font.family: "FontAwesome"
+ text: FontAwesome.Icon.FolderOpen
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: fileDialog.open()
+ }
+ }
+
+ Item {
+ width: 17
+ height: 17
+
+ Text {
+ anchors.centerIn: parent
+ font.pointSize: 17
+ font.family: "FontAwesome"
+ text: FontAwesome.Icon.StepBackward
+ }
+ }
+
+ Item {
+ width: 25
+ height: 25
+
+ Text {
+ anchors.centerIn: parent
+ id : playbutton
+ font.pointSize: 25
+ font.family: "FontAwesome"
+ //font.weight: Font.Light
+ text: FontAwesome.Icon.PlayCircle
+ }
+
+ MouseArea {
+ id: playArea
+ anchors.fill: parent
+ onPressed: {
+ if (player.state !== Player.PLAYING) {
+ player.play()
+ playbutton.text = FontAwesome.Icon.Pause
+ playbutton.font.pointSize = 17
+ } else {
+ player.pause()
+ playbutton.text = FontAwesome.Icon.PlayCircle
+ playbutton.font.pointSize = 25
+ }
+ }
+ }
+ }
+
+ Item {
+ width: 17
+ height: 17
+
+ Text {
+ anchors.centerIn: parent
+ font.pointSize: 17
+ font.family: "FontAwesome"
+ text: FontAwesome.Icon.StepForward
+ }
+ }
+
+ Item {
+ width: 40
+ height: 17
+ Text {
+ id: timelabel
+ anchors.centerIn: parent
+ font.pointSize: 13
+ color: "black"
+ text: {
+ var current = new Date(Math.floor(slider.value / 1e6));
+ current.getMinutes() + ":" + ('0'+current.getSeconds()).slice(-2)
+ }
+ }
+ }
+
+ Item {
+ width: 200
+ height: 38
+ Text {
+ anchors.centerIn: parent
+ text: player.mediaInfo.title
+ font.pointSize: 15
+ }
+ }
+
+
+
+ Item {
+ width: 40
+ height: 17
+ Text {
+ id: durationlabel
+ anchors.centerIn: parent
+ font.pointSize: 13
+ color: "black"
+ text: {
+ var duration = new Date(Math.floor(player.duration / 1e6));
+ duration.getMinutes() + ":" + ('0'+duration.getSeconds()).slice(-2)
+ }
+ }
+ }
+
+ Item {
+ width: 17
+ height: 17
+
+
+ Text {
+ id : volume
+ anchors.centerIn: parent
+ font.pointSize: 17
+ font.family: "FontAwesome"
+ text: {
+ if (volumeslider.value > volumeslider.maximumValue / 2) {
+ FontAwesome.Icon.VolumeUp
+ } else if (volumeslider.value === 0) {
+ FontAwesome.Icon.VolumeOff
+ } else {
+ FontAwesome.Icon.VolumeDown
+ }
+ }
+ }
+
+ Rectangle {
+ id : volumebar
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.top
+ //anchors.bottomMargin:3
+ color: "lightgray"
+ width: 17
+ height: 66
+ visible: false
+ radius: 5
+
+ Slider {
+ id: volumeslider
+ value: player.volume
+ minimumValue: 0.0
+ maximumValue: 1.0
+ stepSize: 0.001
+ anchors.centerIn: parent
+ orientation: Qt.Vertical
+ onPressedChanged: player.volume = value
+
+ style: SliderStyle {
+ groove: Item {
+ implicitWidth: 47
+ implicitHeight: 3
+ anchors.centerIn: parent
+
+ Rectangle {
+ antialiasing: true
+ height: parent.height
+ width: parent.width
+ color: "gray"
+ opacity: 0.8
+ radius: 5
+
+ Rectangle {
+ antialiasing: true
+ height: parent.height
+ width: parent.width * control.value / control.maximumValue
+ color: "red"
+ radius: 5
+ }
+ }
+ }
+ handle: Rectangle {
+ anchors.centerIn: parent
+ color: control.pressed ? "white" : "lightgray"
+ border.color: "gray"
+ border.width: 1
+ implicitWidth: 11
+ implicitHeight: 11
+ radius: 90
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: {
+ volumebar.visible = !volumebar.visible
+ }
+ }
+
+ MouseArea {
+ anchors.fill: volumebar
+ hoverEnabled: true
+ propagateComposedEvents: true
+
+ onClicked: mouse.accepted = false;
+ onPressed: mouse.accepted = false;
+ onReleased: mouse.accepted = false;
+ onDoubleClicked: mouse.accepted = false;
+ onPositionChanged: mouse.accepted = false;
+ onPressAndHold: mouse.accepted = false;
+
+ onExited: {
+ volumebar.visible = false
+ }
+ }
+
+ }
+
+ Text {
+ id: sub
+ font.pointSize: 17
+ font.family: "FontAwesome"
+ text: FontAwesome.Icon.ClosedCaptions
+ }
+
+ Text {
+ id : fullscreen
+ font.pointSize: 17
+ font.family: "FontAwesome"
+ text: FontAwesome.Icon.ResizeFull
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (window.visibility === Window.FullScreen) {
+ window.showNormal()
+ fullscreen.text = FontAwesome.Icon.ResizeFull
+ } else {
+ window.showFullScreen()
+ fullscreen.text = FontAwesome.Icon.ResizeSmall
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ width: playbar.width
+ height: 5
+ anchors.bottom: playbar.bottom
+
+ Slider {
+ id: slider
+ maximumValue: player.duration
+ value: player.position
+ onPressedChanged: player.seek(value)
+ enabled: player.mediaInfo.isSeekable
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ MouseArea {
+ id: sliderMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ propagateComposedEvents: true
+
+ onClicked: mouse.accepted = false;
+ onPressed: mouse.accepted = false;
+ onReleased: mouse.accepted = false;
+ onDoubleClicked: mouse.accepted = false;
+ onPositionChanged: mouse.accepted = false;
+ onPressAndHold: mouse.accepted = false;
+ }
+
+ Rectangle {
+ id: hoveredcliptime
+ width: 40
+ height: 17
+ color: "lightgray"
+ anchors.verticalCenter: parent.verticalCenter
+ visible: sliderMouseArea.containsMouse
+ x: sliderMouseArea.mouseX
+
+ Text {
+ font.pointSize: 13
+ color: "black"
+ anchors.centerIn: parent
+ text: {
+ var value = (sliderMouseArea.mouseX - slider.x) * player.duration / (slider.width - slider.x)
+ var date = new Date(Math.floor(value / 1e6));
+ date.getMinutes() + ":" + ('0' + date.getSeconds()).slice(-2)
+ }
+ }
+ }
+
+ style: SliderStyle {
+ groove: Item {
+ implicitWidth: playbar.width
+ implicitHeight: 5
+
+ Rectangle {
+ height: parent.height
+ width: parent.width
+ anchors.verticalCenter: parent.verticalCenter
+ color: "gray"
+ opacity: 0.8
+
+ Rectangle {
+ antialiasing: true
+ color: "red"
+ height: parent.height
+ width: parent.width * control.value / control.maximumValue
+ }
+
+ Rectangle {
+ antialiasing: true
+ color: "yellow"
+ height: parent.height
+ width: parent.width * player.buffering / 100
+ }
+ }
+ }
+ handle: Rectangle {
+ anchors.centerIn: parent
+ color: control.pressed ? "white" : "lightgray"
+ implicitWidth: 4
+ implicitHeight: 5
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/qt/play.pro b/qt/play.pro
new file mode 100644
index 0000000..c8b2954
--- /dev/null
+++ b/qt/play.pro
@@ -0,0 +1,53 @@
+TEMPLATE = app
+
+QT += qml quick widgets
+
+CONFIG += c++11
+
+DEFINES += GST_USE_UNSTABLE_API
+
+INCLUDEPATH += ../lib
+
+RESOURCES += qml.qrc
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Default rules for deployment.
+include(deployment.pri)
+
+# not tested (yet)
+unix:!macx {
+QT_CONFIG -= no-pkg-config
+CONFIG += link_pkgconfig
+PKGCONFIG = \
+ gstreamer-1.0 \
+ gstreamer-audio-1.0 \
+ gstreamer-tag-1.0 \
+ gstreamer-pbutils-1.0 \
+ gstreamer-video-1.0 \
+ gstreamer-gl-1.0
+}
+
+macx {
+ QMAKE_MAC_SDK = macosx10.9
+ INCLUDEPATH += /Library/Frameworks/GStreamer.framework/Headers
+
+ LIBS += \
+ -framework AppKit \
+ -F/Library/Frameworks -framework GStreamer
+}
+
+HEADERS += \
+ qgstplayer.h \
+ player.h \
+ quickrenderer.h
+
+SOURCES += main.cpp \
+ qgstplayer.cpp \
+ ../lib/gst/player/gstplayer.c \
+ ../lib/gst/player/gstplayer-media-info.c \
+ player.cpp \
+ quickrenderer.cpp
+
+DISTFILES +=
diff --git a/qt/player.cpp b/qt/player.cpp
new file mode 100644
index 0000000..ec4b78c
--- /dev/null
+++ b/qt/player.cpp
@@ -0,0 +1,41 @@
+
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "player.h"
+#include "quickrenderer.h"
+
+Player::Player(QObject *parent)
+ : Player(parent, new QuickRenderer)
+{
+
+}
+
+Player::Player(QObject *parent, QuickRenderer *renderer)
+ : QGstPlayer(parent, renderer)
+ , renderer_(renderer)
+{
+ renderer_->setParent(this);
+}
+
+void Player::setVideoOutput(QQuickItem *output)
+{
+ renderer_->setVideoItem(output);
+}
diff --git a/qt/player.h b/qt/player.h
new file mode 100644
index 0000000..88586f4
--- /dev/null
+++ b/qt/player.h
@@ -0,0 +1,44 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PLAYER_H
+#define PLAYER_H
+
+#include <QObject>
+#include <QQuickItem>
+#include "qgstplayer.h"
+
+class QuickRenderer;
+
+class Player : public QGstPlayer
+{
+ Q_OBJECT
+public:
+ Player(QObject *parent = 0);
+ void setVideoOutput(QQuickItem *output);
+
+private:
+ Player(QObject *parent, QuickRenderer *renderer);
+ QuickRenderer *renderer_;
+};
+
+Q_DECLARE_METATYPE(Player*)
+
+#endif // PLAYER_H
diff --git a/qt/qgstplayer.cpp b/qt/qgstplayer.cpp
new file mode 100644
index 0000000..c2fb3fb
--- /dev/null
+++ b/qt/qgstplayer.cpp
@@ -0,0 +1,435 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "qgstplayer.h"
+#include <QDebug>
+#include <QSize>
+
+#include <QMetaObject>
+
+class QGstPlayerRegisterMetaTypes
+{
+public:
+ QGstPlayerRegisterMetaTypes()
+ {
+ qRegisterMetaType<QGstPlayer::State>("State");
+ }
+
+} _register;
+
+QGstPlayer::MediaInfo::MediaInfo(GstPlayerMediaInfo *media_info)
+ : mediaInfo_(media_info)
+{
+
+}
+
+QString QGstPlayer::MediaInfo::title() const
+{
+ QString title = QString::fromLocal8Bit
+ (gst_player_media_info_get_title(mediaInfo_));
+
+ // if media has no title, return the file name
+ if (title.isEmpty()) {
+ QUrl url(gst_player_media_info_get_uri(mediaInfo_));
+ title = url.fileName();
+ }
+
+ return title;
+}
+
+bool QGstPlayer::MediaInfo::isSeekable() const
+{
+ return gst_player_media_info_is_seekable(mediaInfo_);
+}
+
+bool QGstPlayer::isVideoAvailable() const
+{
+ GstPlayerVideoInfo *video_info;
+
+ video_info = gst_player_get_current_video_track (player_);
+ if (video_info) {
+ g_object_unref (video_info);
+ return true;
+ }
+
+ return false;
+}
+
+QQmlPropertyMap *QGstPlayer::mediaInfo() const
+{
+ return mediaInfoMap_;
+}
+
+QGstPlayer::QGstPlayer(QObject *parent, QGstPlayer::VideoRenderer *renderer)
+ : QObject(parent)
+ , player_()
+ , state_(STOPPED)
+ , videoDimensions_(QSize())
+ , mediaInfoMap_()
+ , videoAvailable_(false)
+{
+
+ player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, 0);
+
+ g_object_connect(player_,
+ "swapped-signal::state-changed", G_CALLBACK (QGstPlayer::onStateChanged), this,
+ "swapped-signal::position-updated", G_CALLBACK (QGstPlayer::onPositionUpdated), this,
+ "swapped-signal::duration-changed", G_CALLBACK (QGstPlayer::onDurationChanged), this,
+ "swapped-signal::buffering", G_CALLBACK (QGstPlayer::onBufferingChanged), this,
+ "swapped-signal::video-dimensions-changed", G_CALLBACK (QGstPlayer::onVideoDimensionsChanged), this,
+ "swapped-signal::volume-changed", G_CALLBACK (QGstPlayer::onVolumeChanged), this,
+ "swapped-signal::mute-changed", G_CALLBACK (QGstPlayer::onMuteChanged), this,
+ "swapped-signal::media-info-updated", G_CALLBACK (QGstPlayer::onMediaInfoUpdated), this, NULL);
+
+ mediaInfoMap_ = new QQmlPropertyMap(this);
+}
+
+void
+QGstPlayer::onStateChanged(QGstPlayer * player, GstPlayerState state)
+{
+ player->state_ = static_cast<QGstPlayer::State>(state);
+
+ emit player->stateChanged(player->state_);
+}
+
+void
+QGstPlayer::onPositionUpdated(QGstPlayer * player, GstClockTime position)
+{
+ emit player->positionChanged(position);
+}
+
+void
+QGstPlayer::onDurationChanged(QGstPlayer * player, GstClockTime duration)
+{
+ emit player->durationChanged(duration);
+}
+
+void
+QGstPlayer::onBufferingChanged(QGstPlayer * player, int percent)
+{
+ emit player->bufferingChanged(percent);
+}
+
+void
+QGstPlayer::onVideoDimensionsChanged(QGstPlayer * player, int w, int h)
+{
+ QSize res(w,h);
+
+ player->setResolution(res);
+
+ emit player->resolutionChanged(res);
+}
+
+void
+QGstPlayer::onVolumeChanged(QGstPlayer *player)
+{
+ qreal new_val;
+
+ new_val = gst_player_get_volume (player->player_);
+
+ emit player->volumeChanged(new_val);
+}
+
+void
+QGstPlayer::onMuteChanged(QGstPlayer *player)
+{
+ bool new_val;
+
+ new_val = gst_player_get_mute (player->player_);
+
+ emit player->mutedChanged(new_val);
+}
+
+void
+QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_info)
+{
+ MediaInfo mediaInfo(media_info);
+
+ player->mediaInfoMap_->insert(QLatin1String("title"),
+ QVariant(mediaInfo.title()));
+ player->mediaInfoMap_->insert(QLatin1String("isSeekable"),
+ QVariant(mediaInfo.isSeekable()));
+
+ bool val = player->isVideoAvailable();
+
+ if (player->videoAvailable_ != val) {
+ player->videoAvailable_ = val;
+ emit player->videoAvailableChanged(val);
+ }
+
+ emit player->mediaInfoChanged();
+}
+
+QUrl QGstPlayer::source() const
+{
+ Q_ASSERT(player_ != 0);
+ QString url = QString::fromLocal8Bit(gst_player_get_uri(player_));
+
+ return QUrl(url);
+}
+
+qint64 QGstPlayer::duration() const
+{
+ Q_ASSERT(player_ != 0);
+
+ return gst_player_get_duration(player_);
+}
+
+qint64 QGstPlayer::position() const
+{
+ Q_ASSERT(player_ != 0);
+
+ return gst_player_get_position(player_);
+}
+
+qreal QGstPlayer::volume() const
+{
+ Q_ASSERT(player_ != 0);
+
+ return gst_player_get_volume(player_);
+}
+
+bool QGstPlayer::isMuted() const
+{
+ Q_ASSERT(player_ != 0);
+
+ return gst_player_get_mute(player_);
+}
+
+int QGstPlayer::buffering() const
+{
+ return 0;
+}
+
+QSize QGstPlayer::resolution() const
+{
+ return videoDimensions_;
+}
+
+void QGstPlayer::setResolution(QSize size)
+{
+ videoDimensions_ = size;
+}
+
+QGstPlayer::State QGstPlayer::state() const
+{
+ return state_;
+}
+
+GstElement *QGstPlayer::pipeline() const
+{
+ Q_ASSERT(player_ != 0);
+
+ return gst_player_get_pipeline(player_);
+}
+
+void QGstPlayer::play()
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_play(player_);
+}
+
+void QGstPlayer::pause()
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_pause(player_);
+}
+
+void QGstPlayer::stop()
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_stop(player_);
+}
+
+void QGstPlayer::seek(qint64 position)
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_seek(player_, position);
+}
+
+void QGstPlayer::setSource(QUrl const& url)
+{
+ Q_ASSERT(player_ != 0);
+ QByteArray uri = url.toString().toLocal8Bit();
+
+ gst_player_set_uri(player_, uri.data());
+
+ emit sourceChanged(url);
+}
+
+void QGstPlayer::setVolume(qreal val)
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_set_volume(player_, val);
+}
+
+void QGstPlayer::setMuted(bool val)
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_set_mute(player_, val);
+}
+
+void QGstPlayer::setPosition(qint64 pos)
+{
+ Q_ASSERT(player_ != 0);
+
+ gst_player_seek(player_, pos);
+}
+
+GstPlayerVideoRenderer *QGstPlayer::VideoRenderer::renderer()
+{
+ return renderer_;
+}
+
+QGstPlayer::VideoRenderer::VideoRenderer()
+{
+ renderer_ = static_cast<GstPlayerVideoRenderer*>
+ (g_object_new (GST_TYPE_PLAYER_QT_VIDEO_RENDERER, "renderer", this, NULL));
+}
+
+QGstPlayer::VideoRenderer::~VideoRenderer()
+{
+ if (renderer_) gst_object_unref(renderer_);
+}
+
+struct _GstPlayerQtVideoRenderer
+{
+ GObject parent;
+
+ gpointer renderer;
+};
+
+struct _GstPlayerQtVideoRendererClass
+{
+ GObjectClass parent_class;
+};
+
+static void
+gst_player_qt_video_renderer_interface_init
+ (GstPlayerVideoRendererInterface * iface);
+
+G_DEFINE_TYPE_WITH_CODE (GstPlayerQtVideoRenderer,
+ gst_player_qt_video_renderer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_VIDEO_RENDERER,
+ gst_player_qt_video_renderer_interface_init))
+
+enum
+{
+ QT_VIDEO_RENDERER_PROP_0,
+ QT_VIDEO_RENDERER_PROP_RENDERER,
+ QT_VIDEO_RENDERER_PROP_LAST
+};
+
+static GParamSpec * qt_video_renderer_param_specs
+ [QT_VIDEO_RENDERER_PROP_LAST] = { NULL, };
+
+static void
+gst_player_qt_video_renderer_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object);
+
+ switch (prop_id) {
+ case QT_VIDEO_RENDERER_PROP_RENDERER:
+ qDebug() << "setting renderer";
+ self->renderer = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_player_qt_video_renderer_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object);
+
+ switch (prop_id) {
+ case QT_VIDEO_RENDERER_PROP_RENDERER:
+ g_value_set_pointer (value, self->renderer);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_player_qt_video_renderer_finalize (GObject * object)
+{
+ GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object);
+
+ G_OBJECT_CLASS
+ (gst_player_qt_video_renderer_parent_class)->finalize(object);
+}
+
+static void
+gst_player_qt_video_renderer_class_init
+ (GstPlayerQtVideoRendererClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property =
+ gst_player_qt_video_renderer_set_property;
+ gobject_class->get_property =
+ gst_player_qt_video_renderer_get_property;
+ gobject_class->finalize = gst_player_qt_video_renderer_finalize;
+
+ qt_video_renderer_param_specs
+ [QT_VIDEO_RENDERER_PROP_RENDERER] =
+ g_param_spec_pointer ("renderer", "Qt Renderer", "",
+ static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (gobject_class,
+ QT_VIDEO_RENDERER_PROP_LAST,
+ qt_video_renderer_param_specs);
+}
+
+static void
+gst_player_qt_video_renderer_init (GstPlayerQtVideoRenderer * self)
+{
+
+}
+
+static GstElement *
+gst_player_qt_video_renderer_create_video_sink
+ (GstPlayerVideoRenderer * iface, GstPlayer *player)
+{
+ GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (iface);
+
+ g_assert(self->renderer != NULL);
+
+ return static_cast<QGstPlayer::VideoRenderer*>(self->renderer)->createVideoSink();
+}
+
+static void
+gst_player_qt_video_renderer_interface_init
+ (GstPlayerVideoRendererInterface * iface)
+{
+ iface->create_video_sink = gst_player_qt_video_renderer_create_video_sink;
+}
diff --git a/qt/qgstplayer.h b/qt/qgstplayer.h
new file mode 100644
index 0000000..aeb45a5
--- /dev/null
+++ b/qt/qgstplayer.h
@@ -0,0 +1,162 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef QGSTPLAYER_H
+#define QGSTPLAYER_H
+
+#include <QObject>
+#include <QUrl>
+#include <QSize>
+//#include <QtGui/qwindowdefs.h>
+#include <QtQml/QQmlPropertyMap>
+#include <gst/player/player.h>
+
+class QGstPlayer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged)
+ Q_PROPERTY(qint64 position READ position NOTIFY positionChanged)
+ Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
+ Q_PROPERTY(int buffering READ buffering NOTIFY bufferingChanged)
+ Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged)
+ Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged)
+
+ Q_ENUMS(State)
+
+public:
+
+ class VideoRenderer;
+
+ explicit QGstPlayer(QObject *parent = 0, VideoRenderer *renderer = 0);
+
+ typedef GstPlayerError Error;
+ enum State {
+ STOPPED = GST_PLAYER_STATE_STOPPED,
+ BUFFERING = GST_PLAYER_STATE_BUFFERING,
+ PAUSED = GST_PLAYER_STATE_PAUSED,
+ PLAYING = GST_PLAYER_STATE_PLAYING
+ };
+
+ class VideoRenderer
+ {
+ public:
+ GstPlayerVideoRenderer *renderer();
+ virtual GstElement *createVideoSink() = 0;
+ protected:
+ VideoRenderer();
+ virtual ~VideoRenderer();
+ private:
+ GstPlayerVideoRenderer *renderer_;
+ };
+
+ // TODO add remaining bits
+ class MediaInfo
+ {
+ public:
+ MediaInfo(GstPlayerMediaInfo *media_info);
+ QString title() const;
+ bool isSeekable() const;
+ private:
+ GstPlayerMediaInfo *mediaInfo_;
+ };
+
+ QUrl source() const;
+ qint64 duration() const;
+ qint64 position() const;
+ qreal volume() const;
+ bool isMuted() const;
+ int buffering() const;
+ State state() const;
+ GstElement *pipeline() const;
+ QSize resolution() const;
+ void setResolution(QSize size);
+ bool isVideoAvailable() const;
+ QQmlPropertyMap *mediaInfo() const;
+
+
+signals:
+ void stateChanged(State new_state);
+ void bufferingChanged(int percent);
+ void enfOfStream();
+ void positionChanged(qint64 new_position);
+ void durationChanged(qint64 duration);
+ void resolutionChanged(QSize resolution);
+ void volumeChanged(qreal volume);
+ void mutedChanged(bool muted);
+ void mediaInfoChanged();
+ void sourceChanged(QUrl new_url);
+ void videoAvailableChanged(bool videoAvailable);
+
+public slots:
+ void play();
+ void pause();
+ void stop();
+ void seek(qint64 position);
+ void setSource(QUrl const& url);
+ void setVolume(qreal val);
+ void setMuted(bool val);
+ void setPosition(qint64 pos);
+
+private:
+ Q_DISABLE_COPY(QGstPlayer)
+ static void onStateChanged(QGstPlayer *, GstPlayerState state);
+ static void onPositionUpdated(QGstPlayer *, GstClockTime position);
+ static void onDurationChanged(QGstPlayer *, GstClockTime duration);
+ static void onBufferingChanged(QGstPlayer *, int percent);
+ static void onVideoDimensionsChanged(QGstPlayer *, int w, int h);
+ static void onVolumeChanged(QGstPlayer *);
+ static void onMuteChanged(QGstPlayer *);
+ static void onMediaInfoUpdated(QGstPlayer *, GstPlayerMediaInfo *media_info);
+
+ GstPlayer *player_;
+ State state_;
+ QSize videoDimensions_;
+ QQmlPropertyMap *mediaInfoMap_;
+ bool videoAvailable_;
+};
+
+G_BEGIN_DECLS
+
+typedef struct _GstPlayerQtVideoRenderer
+ GstPlayerQtVideoRenderer;
+
+typedef struct _GstPlayerQtVideoRendererClass
+ GstPlayerQtVideoRendererClass;
+
+#define GST_TYPE_PLAYER_QT_VIDEO_RENDERER (gst_player_qt_video_renderer_get_type ())
+#define GST_IS_PLAYER_QT_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER))
+#define GST_IS_PLAYER_QT_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_QT_VIDEO_RENDERER))
+#define GST_PLAYER_QT_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRendererClass))
+#define GST_PLAYER_QT_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRenderer))
+#define GST_PLAYER_QT_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRendererClass))
+#define GST_PLAYER_QT_VIDEO_RENDERER_CAST(obj) ((GstPlayerQtVideoRenderer*)(obj))
+
+GType gst_player_qt_video_renderer_get_type (void);
+
+G_END_DECLS
+
+Q_DECLARE_METATYPE(QGstPlayer*)
+Q_DECLARE_METATYPE(QGstPlayer::State)
+
+#endif // QGSTPLAYER_H
diff --git a/qt/qml.qrc b/qt/qml.qrc
new file mode 100644
index 0000000..1052217
--- /dev/null
+++ b/qt/qml.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>fontawesome.js</file>
+ </qresource>
+ <qresource prefix="/fonts">
+ <file>fontawesome-webfont.ttf</file>
+ </qresource>
+</RCC>
diff --git a/qt/quickrenderer.cpp b/qt/quickrenderer.cpp
new file mode 100644
index 0000000..5dd6853
--- /dev/null
+++ b/qt/quickrenderer.cpp
@@ -0,0 +1,56 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "quickrenderer.h"
+
+QuickRenderer::QuickRenderer(QObject *parent)
+ : QObject(parent)
+ , QGstPlayer::VideoRenderer()
+ , sink()
+{
+
+}
+
+QuickRenderer::~QuickRenderer()
+{
+ if (sink) gst_object_unref(sink);
+}
+
+GstElement *QuickRenderer::createVideoSink()
+{
+ GstElement *qmlglsink = gst_element_factory_make("qmlglsink", NULL);
+
+ GstElement *glsinkbin = gst_element_factory_make ("glsinkbin", NULL);
+
+ Q_ASSERT(qmlglsink && glsinkbin);
+
+ g_object_set (glsinkbin, "sink", qmlglsink, NULL);
+
+ sink = static_cast<GstElement*>(gst_object_ref_sink(qmlglsink));
+
+ return glsinkbin;
+}
+
+void QuickRenderer::setVideoItem(QQuickItem *item)
+{
+ Q_ASSERT(item);
+
+ g_object_set(sink, "widget", item, NULL);
+}
diff --git a/qt/quickrenderer.h b/qt/quickrenderer.h
new file mode 100644
index 0000000..99519fb
--- /dev/null
+++ b/qt/quickrenderer.h
@@ -0,0 +1,42 @@
+/* GStreamer
+ *
+ * Copyright (C) 2015 Alexandre Moreno <alexmorenocano@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef QUICKPLAYER_H
+#define QUICKPLAYER_H
+
+#include <QObject>
+#include <QQuickItem>
+#include "qgstplayer.h"
+
+class QuickRenderer : public QObject, public QGstPlayer::VideoRenderer
+{
+ Q_OBJECT
+public:
+ QuickRenderer(QObject *parent = 0);
+ ~QuickRenderer();
+
+ GstElement *createVideoSink();
+ void setVideoItem(QQuickItem *item);
+
+private:
+ GstElement *sink;
+};
+
+#endif // QUICKPLAYER_H