playback/player: Add Qt bindings and player

This commit is contained in:
Alexandre Moreno 2015-06-12 01:47:56 +08:00 committed by Sebastian Dröge
parent 09864feff4
commit 82b2c53618
14 changed files with 1606 additions and 0 deletions

View file

@ -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)

Binary file not shown.

View file

@ -0,0 +1,10 @@
Font Awesome
URL: http://fontawesome.io
Font License
License: SIL OFL 1.1
URL: http://scripts.sil.org/OFL

View file

@ -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",
};

View file

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

461
playback/player/qt/main.qml Normal file
View file

@ -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
}
}
}
}
}
}
}

View file

@ -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 +=

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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>

View file

@ -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);
}

View file

@ -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