mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-13 12:51:16 +00:00
playback/player: qt: add stream selection support
This commit is contained in:
parent
2ea1c9aee7
commit
c8d7277d70
5 changed files with 739 additions and 129 deletions
|
@ -44,7 +44,7 @@ ApplicationWindow {
|
||||||
volume: 0.5
|
volume: 0.5
|
||||||
onStateChanged: {
|
onStateChanged: {
|
||||||
if (state === Player.STOPPED) {
|
if (state === Player.STOPPED) {
|
||||||
playbutton.text = FontAwesome.Icon.Play
|
playbutton.state = "play"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onResolutionChanged: {
|
onResolutionChanged: {
|
||||||
|
@ -116,16 +116,236 @@ ApplicationWindow {
|
||||||
interval: 10000
|
interval: 10000
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
parent.opacity = 0.0
|
parent.opacity = 0.0
|
||||||
|
settings.visible = false
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: settings
|
||||||
|
width: 150; height: settingsView.contentHeight
|
||||||
|
color: Qt.rgba(1, 1, 1, 0.7)
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: 3
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
radius: 5
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: settingsModel
|
||||||
|
ListElement {
|
||||||
|
name: "Video"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Audio"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Subtitle"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: settingsDelegate
|
||||||
|
Item {
|
||||||
|
width: 150; height: 20
|
||||||
|
Text {
|
||||||
|
text: model.name
|
||||||
|
font.pointSize: 13
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
font.pointSize: 13
|
||||||
|
font.family: "FontAwesome"
|
||||||
|
text: FontAwesome.Icon.ChevronRight
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
switch(name) {
|
||||||
|
case 'Video':
|
||||||
|
videos.visible = true
|
||||||
|
break
|
||||||
|
case 'Audio':
|
||||||
|
audios.visible = true
|
||||||
|
break
|
||||||
|
case 'Subtitle' :
|
||||||
|
subtitles.visible = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
settings.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: settingsView
|
||||||
|
anchors.fill: parent
|
||||||
|
model: settingsModel
|
||||||
|
delegate: settingsDelegate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: videos
|
||||||
|
width: 150; height: videoView.contentHeight
|
||||||
|
color: Qt.rgba(1, 1, 1, 0.7)
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: 3
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
property bool selected: ListView.isCurrentItem
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: videoDelegate
|
||||||
|
Item {
|
||||||
|
width: 150; height: 20
|
||||||
|
Text {
|
||||||
|
text: model.modelData.resolution.width + 'x' + model.modelData.resolution.height
|
||||||
|
font.pointSize: 13
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
parent.ListView.view.currentIndex = index
|
||||||
|
player.currentVideo = model.modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id : videoView
|
||||||
|
anchors.fill: parent
|
||||||
|
model: player.mediaInfo.videoStreams
|
||||||
|
delegate: videoDelegate
|
||||||
|
highlight: Rectangle {
|
||||||
|
color: "white"
|
||||||
|
radius: 5
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
}
|
||||||
|
focus: true
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: audios
|
||||||
|
width: 150; height: audioView.contentHeight
|
||||||
|
color: Qt.rgba(1, 1, 1, 0.7)
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: 3
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
property bool selected: ListView.isCurrentItem
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: audioDelegate
|
||||||
|
Item {
|
||||||
|
width: 150; height: 20
|
||||||
|
Text {
|
||||||
|
text: model.modelData.channels + 'channels'
|
||||||
|
font.pointSize: 13
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
parent.ListView.view.currentIndex = index
|
||||||
|
player.currentAudio = model.modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id : audioView
|
||||||
|
anchors.fill: parent
|
||||||
|
model: player.mediaInfo.audioStreams
|
||||||
|
delegate: audioDelegate
|
||||||
|
highlight: Rectangle {
|
||||||
|
color: "white"
|
||||||
|
radius: 5
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
}
|
||||||
|
focus: true
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: subtitles
|
||||||
|
width: 150; height: subtitleView.contentHeight
|
||||||
|
color: Qt.rgba(1, 1, 1, 0.7)
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: 3
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
property bool selected: ListView.isCurrentItem
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: subtitleDelegate
|
||||||
|
Item {
|
||||||
|
width: 150; height: 20
|
||||||
|
Text {
|
||||||
|
text: model.modelData.language
|
||||||
|
font.pointSize: 13
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
parent.ListView.view.currentIndex = index
|
||||||
|
player.currentSubtitle = model.modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id : subtitleView
|
||||||
|
anchors.fill: parent
|
||||||
|
model: player.mediaInfo.subtitleStreams
|
||||||
|
delegate: subtitleDelegate
|
||||||
|
highlight: Rectangle {
|
||||||
|
color: "white"
|
||||||
|
radius: 5
|
||||||
|
border.width: 1
|
||||||
|
border.color: "white"
|
||||||
|
}
|
||||||
|
focus: true
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
id: grid
|
id: grid
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
// anchors.top: parent.top
|
|
||||||
// anchors.topMargin: 5
|
|
||||||
|
|
||||||
spacing: 7
|
spacing: 7
|
||||||
rows: 1
|
rows: 1
|
||||||
verticalItemAlignment: Qt.AlignVCenter
|
verticalItemAlignment: Qt.AlignVCenter
|
||||||
|
@ -161,10 +381,27 @@ ApplicationWindow {
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
id : playbutton
|
id : playbutton
|
||||||
font.pointSize: 25
|
|
||||||
font.family: "FontAwesome"
|
font.family: "FontAwesome"
|
||||||
//font.weight: Font.Light
|
state: "play"
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "play"
|
||||||
|
PropertyChanges {
|
||||||
|
target: playbutton
|
||||||
text: FontAwesome.Icon.PlayCircle
|
text: FontAwesome.Icon.PlayCircle
|
||||||
|
font.pointSize: 25
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "pause"
|
||||||
|
PropertyChanges {
|
||||||
|
target: playbutton
|
||||||
|
text: FontAwesome.Icon.Pause
|
||||||
|
font.pointSize: 17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
@ -173,12 +410,10 @@ ApplicationWindow {
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (player.state !== Player.PLAYING) {
|
if (player.state !== Player.PLAYING) {
|
||||||
player.play()
|
player.play()
|
||||||
playbutton.text = FontAwesome.Icon.Pause
|
playbutton.state = "pause"
|
||||||
playbutton.font.pointSize = 17
|
|
||||||
} else {
|
} else {
|
||||||
player.pause()
|
player.pause()
|
||||||
playbutton.text = FontAwesome.Icon.PlayCircle
|
playbutton.state = "play"
|
||||||
playbutton.font.pointSize = 25
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,8 +456,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: 40
|
width: 40
|
||||||
height: 17
|
height: 17
|
||||||
|
@ -238,11 +471,25 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: sub
|
||||||
|
font.pointSize: 17
|
||||||
|
font.family: "FontAwesome"
|
||||||
|
text: FontAwesome.Icon.ClosedCaptions
|
||||||
|
color: player.subtitleEnabled ? "red" : "black"
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
player.subtitleEnabled = !player.subtitleEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: 17
|
width: 17
|
||||||
height: 17
|
height: 17
|
||||||
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id : volume
|
id : volume
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
@ -343,10 +590,22 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: sub
|
id: cog
|
||||||
font.pointSize: 17
|
font.pointSize: 17
|
||||||
font.family: "FontAwesome"
|
font.family: "FontAwesome"
|
||||||
text: FontAwesome.Icon.ClosedCaptions
|
text: FontAwesome.Icon.Cog
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
settings.visible = !settings.visible
|
||||||
|
videos.visible = false
|
||||||
|
audios.visible = false
|
||||||
|
subtitles.visible = false
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@ -380,7 +639,7 @@ ApplicationWindow {
|
||||||
maximumValue: player.duration
|
maximumValue: player.duration
|
||||||
value: player.position
|
value: player.position
|
||||||
onPressedChanged: player.seek(value)
|
onPressedChanged: player.seek(value)
|
||||||
enabled: player.mediaInfo.isSeekable
|
enabled: player.mediaInfo.seekable
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
@ -455,7 +714,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ Player::Player(QObject *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::Player(QObject *parent, QuickRenderer *renderer)
|
Player::Player(QObject *parent, QuickRenderer *renderer)
|
||||||
: QGstPlayer(parent, renderer)
|
: QGstPlayer::Player(parent, renderer)
|
||||||
, renderer_(renderer)
|
, renderer_(renderer)
|
||||||
{
|
{
|
||||||
renderer_->setParent(this);
|
renderer_->setParent(this);
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
class QuickRenderer;
|
class QuickRenderer;
|
||||||
|
|
||||||
class Player : public QGstPlayer
|
class Player : public QGstPlayer::Player
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -24,43 +24,200 @@
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QtAlgorithms>
|
||||||
|
|
||||||
class QGstPlayerRegisterMetaTypes
|
namespace QGstPlayer {
|
||||||
|
|
||||||
|
class RegisterMetaTypes
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QGstPlayerRegisterMetaTypes()
|
RegisterMetaTypes()
|
||||||
{
|
{
|
||||||
qRegisterMetaType<QGstPlayer::State>("State");
|
qRegisterMetaType<Player::State>("State");
|
||||||
}
|
}
|
||||||
|
|
||||||
} _register;
|
} _register;
|
||||||
|
|
||||||
QGstPlayer::MediaInfo::MediaInfo(GstPlayerMediaInfo *media_info)
|
MediaInfo::MediaInfo(Player *player)
|
||||||
: mediaInfo_(media_info)
|
: QObject(player)
|
||||||
|
, uri_()
|
||||||
|
, title_()
|
||||||
|
, isSeekable_(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QGstPlayer::MediaInfo::title() const
|
QString MediaInfo::uri() const
|
||||||
{
|
{
|
||||||
QString title = QString::fromLocal8Bit
|
return uri_;
|
||||||
(gst_player_media_info_get_title(mediaInfo_));
|
}
|
||||||
|
|
||||||
|
QString MediaInfo::title() const
|
||||||
|
{
|
||||||
|
return title_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaInfo::isSeekable() const
|
||||||
|
{
|
||||||
|
return isSeekable_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<QObject *> &MediaInfo::videoStreams() const
|
||||||
|
{
|
||||||
|
return videoStreams_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<QObject *> &MediaInfo::audioStreams() const
|
||||||
|
{
|
||||||
|
return audioStreams_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<QObject*> &MediaInfo::subtitleStreams() const
|
||||||
|
{
|
||||||
|
return subtitleStreams_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaInfo::update(GstPlayerMediaInfo *info)
|
||||||
|
{
|
||||||
|
Q_ASSERT(info != 0);
|
||||||
|
|
||||||
|
// FIXME since media-info signal gets emitted
|
||||||
|
// several times, we just update info iff the
|
||||||
|
// media uri has changed.
|
||||||
|
if (uri_ == gst_player_media_info_get_uri(info)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uri_ = QString(gst_player_media_info_get_uri(info));
|
||||||
|
|
||||||
|
title_ = QString::fromLocal8Bit(gst_player_media_info_get_title(info));
|
||||||
|
|
||||||
// if media has no title, return the file name
|
// if media has no title, return the file name
|
||||||
if (title.isEmpty()) {
|
if (title_.isEmpty()) {
|
||||||
QUrl url(gst_player_media_info_get_uri(mediaInfo_));
|
QUrl url(gst_player_media_info_get_uri(info));
|
||||||
title = url.fileName();
|
title_ = url.fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return title;
|
emit titleChanged();
|
||||||
|
|
||||||
|
if (isSeekable_ != gst_player_media_info_is_seekable(info)) {
|
||||||
|
isSeekable_ = !isSeekable_;
|
||||||
|
emit seekableChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QGstPlayer::MediaInfo::isSeekable() const
|
if (!subtitleStreams_.isEmpty()) {
|
||||||
|
qDeleteAll(subtitleStreams_);
|
||||||
|
subtitleStreams_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!videoStreams_.isEmpty()) {
|
||||||
|
qDeleteAll(videoStreams_);
|
||||||
|
videoStreams_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!audioStreams_.isEmpty()) {
|
||||||
|
qDeleteAll(audioStreams_);
|
||||||
|
audioStreams_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *list = gst_player_get_subtitle_streams(info);
|
||||||
|
|
||||||
|
g_list_foreach (list, [](gpointer data, gpointer user_data) {
|
||||||
|
GstPlayerSubtitleInfo *info = static_cast<GstPlayerSubtitleInfo*>(data);
|
||||||
|
QList<QObject*> *subs = static_cast<QList<QObject*>*>(user_data);
|
||||||
|
|
||||||
|
subs->append(new SubtitleInfo(info));
|
||||||
|
}, &subtitleStreams_);
|
||||||
|
|
||||||
|
list = gst_player_get_video_streams(info);
|
||||||
|
|
||||||
|
g_list_foreach (list, [](gpointer data, gpointer user_data) {
|
||||||
|
GstPlayerVideoInfo *info = static_cast<GstPlayerVideoInfo*>(data);
|
||||||
|
QList<QObject*> *videos = static_cast<QList<QObject*>*>(user_data);
|
||||||
|
|
||||||
|
videos->append(new VideoInfo(info));
|
||||||
|
}, &videoStreams_);
|
||||||
|
|
||||||
|
list = gst_player_get_audio_streams(info);
|
||||||
|
|
||||||
|
g_list_foreach (list, [](gpointer data, gpointer user_data) {
|
||||||
|
GstPlayerAudioInfo *info = static_cast<GstPlayerAudioInfo*>(data);
|
||||||
|
QList<QObject*> *audios = static_cast<QList<QObject*>*>(user_data);
|
||||||
|
|
||||||
|
audios->append(new AudioInfo(info));
|
||||||
|
}, &audioStreams_);
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoInfo::VideoInfo(GstPlayerVideoInfo *info)
|
||||||
|
: StreamInfo(reinterpret_cast<GstPlayerStreamInfo*>(info))
|
||||||
|
, video_(info)
|
||||||
|
, resolution_(gst_player_video_info_get_width(info), gst_player_video_info_get_height(info))
|
||||||
{
|
{
|
||||||
return gst_player_media_info_is_seekable(mediaInfo_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QGstPlayer::isVideoAvailable() const
|
QSize VideoInfo::resolution() const
|
||||||
|
{
|
||||||
|
return resolution_;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioInfo::AudioInfo(GstPlayerAudioInfo *info)
|
||||||
|
: StreamInfo(reinterpret_cast<GstPlayerStreamInfo*>(info))
|
||||||
|
, audio_(info)
|
||||||
|
, language_(gst_player_audio_info_get_language(info))
|
||||||
|
, channels_(gst_player_audio_info_get_channels(info))
|
||||||
|
, bitRate_(gst_player_audio_info_get_bitrate(info))
|
||||||
|
, sampleRate_(gst_player_audio_info_get_sample_rate(info))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &AudioInfo::language() const
|
||||||
|
{
|
||||||
|
return language_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioInfo::channels() const
|
||||||
|
{
|
||||||
|
return channels_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioInfo::bitRate() const
|
||||||
|
{
|
||||||
|
return bitRate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioInfo::sampleRate() const
|
||||||
|
{
|
||||||
|
return sampleRate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubtitleInfo::SubtitleInfo(GstPlayerSubtitleInfo *info)
|
||||||
|
: StreamInfo(reinterpret_cast<GstPlayerStreamInfo*>(info))
|
||||||
|
, subtitle_(info)
|
||||||
|
, language_(gst_player_subtitle_info_get_language(info))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &SubtitleInfo::language() const
|
||||||
|
{
|
||||||
|
return language_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StreamInfo::index() const
|
||||||
|
{
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamInfo::StreamInfo(GstPlayerStreamInfo *info)
|
||||||
|
: stream_(info)
|
||||||
|
, index_(gst_player_stream_info_get_index(info))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Player::isVideoAvailable() const
|
||||||
{
|
{
|
||||||
GstPlayerVideoInfo *video_info;
|
GstPlayerVideoInfo *video_info;
|
||||||
|
|
||||||
|
@ -73,74 +230,163 @@ bool QGstPlayer::isVideoAvailable() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlPropertyMap *QGstPlayer::mediaInfo() const
|
MediaInfo *Player::mediaInfo() const
|
||||||
{
|
{
|
||||||
return mediaInfoMap_;
|
return mediaInfo_;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGstPlayer::QGstPlayer(QObject *parent, QGstPlayer::VideoRenderer *renderer)
|
QVariant Player::currentVideo() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
GstPlayerVideoInfo *track = gst_player_get_current_video_track(player_);
|
||||||
|
|
||||||
|
if (!track)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
return QVariant::fromValue(new VideoInfo(track));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Player::currentAudio() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
GstPlayerAudioInfo *track = gst_player_get_current_audio_track(player_);
|
||||||
|
|
||||||
|
if (!track)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
return QVariant::fromValue(new AudioInfo(track));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Player::currentSubtitle() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
GstPlayerSubtitleInfo *track = gst_player_get_current_subtitle_track(player_);
|
||||||
|
|
||||||
|
if (!track)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
return QVariant::fromValue(new SubtitleInfo(track));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::setCurrentVideo(QVariant track)
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
VideoInfo* info = track.value<VideoInfo*>();
|
||||||
|
Q_ASSERT(info);
|
||||||
|
|
||||||
|
gst_player_set_video_track(player_, info->index());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::setCurrentAudio(QVariant track)
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
AudioInfo* info = track.value<AudioInfo*>();
|
||||||
|
Q_ASSERT(info);
|
||||||
|
|
||||||
|
gst_player_set_audio_track(player_, info->index());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::setCurrentSubtitle(QVariant track)
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
SubtitleInfo* info = track.value<SubtitleInfo*>();
|
||||||
|
Q_ASSERT(info);
|
||||||
|
|
||||||
|
gst_player_set_subtitle_track(player_, info->index());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Player::isSubtitleEnabled() const
|
||||||
|
{
|
||||||
|
return subtitleEnabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::setSubtitleEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
|
subtitleEnabled_ = enabled;
|
||||||
|
|
||||||
|
gst_player_set_subtitle_track_enabled(player_, enabled);
|
||||||
|
|
||||||
|
emit subtitleEnabledChanged(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
Player::Player(QObject *parent, VideoRenderer *renderer)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, player_()
|
, player_()
|
||||||
, state_(STOPPED)
|
, state_(STOPPED)
|
||||||
, videoDimensions_(QSize())
|
, videoDimensions_(QSize())
|
||||||
, mediaInfoMap_()
|
, mediaInfo_()
|
||||||
, videoAvailable_(false)
|
, videoAvailable_(false)
|
||||||
|
, subtitleEnabled_(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
player_ = gst_player_new_full(renderer ? renderer->renderer() : 0,
|
player_ = gst_player_new_full(renderer ? renderer->renderer() : 0,
|
||||||
gst_player_qt_signal_dispatcher_new(this));
|
gst_player_qt_signal_dispatcher_new(this));
|
||||||
|
|
||||||
g_object_connect(player_,
|
g_object_connect(player_,
|
||||||
"swapped-signal::state-changed", G_CALLBACK (QGstPlayer::onStateChanged), this,
|
"swapped-signal::state-changed", G_CALLBACK (Player::onStateChanged), this,
|
||||||
"swapped-signal::position-updated", G_CALLBACK (QGstPlayer::onPositionUpdated), this,
|
"swapped-signal::position-updated", G_CALLBACK (Player::onPositionUpdated), this,
|
||||||
"swapped-signal::duration-changed", G_CALLBACK (QGstPlayer::onDurationChanged), this,
|
"swapped-signal::duration-changed", G_CALLBACK (Player::onDurationChanged), this,
|
||||||
"swapped-signal::buffering", G_CALLBACK (QGstPlayer::onBufferingChanged), this,
|
"swapped-signal::buffering", G_CALLBACK (Player::onBufferingChanged), this,
|
||||||
"swapped-signal::video-dimensions-changed", G_CALLBACK (QGstPlayer::onVideoDimensionsChanged), this,
|
"swapped-signal::video-dimensions-changed", G_CALLBACK (Player::onVideoDimensionsChanged), this,
|
||||||
"swapped-signal::volume-changed", G_CALLBACK (QGstPlayer::onVolumeChanged), this,
|
"swapped-signal::volume-changed", G_CALLBACK (Player::onVolumeChanged), this,
|
||||||
"swapped-signal::mute-changed", G_CALLBACK (QGstPlayer::onMuteChanged), this,
|
"swapped-signal::mute-changed", G_CALLBACK (Player::onMuteChanged), this,
|
||||||
"swapped-signal::media-info-updated", G_CALLBACK (QGstPlayer::onMediaInfoUpdated), this, NULL);
|
"swapped-signal::media-info-updated", G_CALLBACK (Player::onMediaInfoUpdated), this, NULL);
|
||||||
|
|
||||||
mediaInfoMap_ = new QQmlPropertyMap(this);
|
mediaInfo_ = new MediaInfo(this);
|
||||||
|
gst_player_set_subtitle_track_enabled(player_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onStateChanged(QGstPlayer * player, GstPlayerState state)
|
Player::onStateChanged(Player * player, GstPlayerState state)
|
||||||
{
|
{
|
||||||
player->state_ = static_cast<QGstPlayer::State>(state);
|
player->state_ = static_cast<Player::State>(state);
|
||||||
|
|
||||||
emit player->stateChanged(player->state_);
|
emit player->stateChanged(player->state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onPositionUpdated(QGstPlayer * player, GstClockTime position)
|
Player::onPositionUpdated(Player * player, GstClockTime position)
|
||||||
{
|
{
|
||||||
emit player->positionChanged(position);
|
emit player->positionChanged(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onDurationChanged(QGstPlayer * player, GstClockTime duration)
|
Player::onDurationChanged(Player * player, GstClockTime duration)
|
||||||
{
|
{
|
||||||
emit player->durationChanged(duration);
|
emit player->durationChanged(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onBufferingChanged(QGstPlayer * player, int percent)
|
Player::onBufferingChanged(Player * player, int percent)
|
||||||
{
|
{
|
||||||
emit player->bufferingChanged(percent);
|
emit player->bufferingChanged(percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onVideoDimensionsChanged(QGstPlayer * player, int w, int h)
|
Player::onVideoDimensionsChanged(Player * player, int w, int h)
|
||||||
{
|
{
|
||||||
QSize res(w,h);
|
QSize res(w,h);
|
||||||
|
|
||||||
|
if (res == player->videoDimensions_)
|
||||||
|
return;
|
||||||
|
player->videoDimensions_ = res;
|
||||||
|
|
||||||
player->setResolution(res);
|
player->setResolution(res);
|
||||||
|
|
||||||
emit player->resolutionChanged(res);
|
emit player->resolutionChanged(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onVolumeChanged(QGstPlayer *player)
|
Player::onVolumeChanged(Player *player)
|
||||||
{
|
{
|
||||||
qreal new_val;
|
qreal new_val;
|
||||||
|
|
||||||
|
@ -150,7 +396,7 @@ QGstPlayer::onVolumeChanged(QGstPlayer *player)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onMuteChanged(QGstPlayer *player)
|
Player::onMuteChanged(Player *player)
|
||||||
{
|
{
|
||||||
bool new_val;
|
bool new_val;
|
||||||
|
|
||||||
|
@ -160,15 +406,8 @@ QGstPlayer::onMuteChanged(QGstPlayer *player)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_info)
|
Player::onMediaInfoUpdated(Player *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();
|
bool val = player->isVideoAvailable();
|
||||||
|
|
||||||
if (player->videoAvailable_ != val) {
|
if (player->videoAvailable_ != val) {
|
||||||
|
@ -176,10 +415,12 @@ QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_inf
|
||||||
emit player->videoAvailableChanged(val);
|
emit player->videoAvailableChanged(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
player->mediaInfo()->update(media_info);
|
||||||
|
|
||||||
emit player->mediaInfoChanged();
|
emit player->mediaInfoChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl QGstPlayer::source() const
|
QUrl Player::source() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
QString url = QString::fromLocal8Bit(gst_player_get_uri(player_));
|
QString url = QString::fromLocal8Bit(gst_player_get_uri(player_));
|
||||||
|
@ -187,90 +428,90 @@ QUrl QGstPlayer::source() const
|
||||||
return QUrl(url);
|
return QUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QGstPlayer::duration() const
|
qint64 Player::duration() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
return gst_player_get_duration(player_);
|
return gst_player_get_duration(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QGstPlayer::position() const
|
qint64 Player::position() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
return gst_player_get_position(player_);
|
return gst_player_get_position(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal QGstPlayer::volume() const
|
qreal Player::volume() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
return gst_player_get_volume(player_);
|
return gst_player_get_volume(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QGstPlayer::isMuted() const
|
bool Player::isMuted() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
return gst_player_get_mute(player_);
|
return gst_player_get_mute(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
int QGstPlayer::buffering() const
|
int Player::buffering() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize QGstPlayer::resolution() const
|
QSize Player::resolution() const
|
||||||
{
|
{
|
||||||
return videoDimensions_;
|
return videoDimensions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::setResolution(QSize size)
|
void Player::setResolution(QSize size)
|
||||||
{
|
{
|
||||||
videoDimensions_ = size;
|
videoDimensions_ = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGstPlayer::State QGstPlayer::state() const
|
Player::State Player::state() const
|
||||||
{
|
{
|
||||||
return state_;
|
return state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstElement *QGstPlayer::pipeline() const
|
GstElement *Player::pipeline() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
return gst_player_get_pipeline(player_);
|
return gst_player_get_pipeline(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::play()
|
void Player::play()
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_play(player_);
|
gst_player_play(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::pause()
|
void Player::pause()
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_pause(player_);
|
gst_player_pause(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::stop()
|
void Player::stop()
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_stop(player_);
|
gst_player_stop(player_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::seek(qint64 position)
|
void Player::seek(qint64 position)
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_seek(player_, position);
|
gst_player_seek(player_, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::setSource(QUrl const& url)
|
void Player::setSource(QUrl const& url)
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
QByteArray uri = url.toString().toLocal8Bit();
|
QByteArray uri = url.toString().toLocal8Bit();
|
||||||
|
@ -280,43 +521,45 @@ void QGstPlayer::setSource(QUrl const& url)
|
||||||
emit sourceChanged(url);
|
emit sourceChanged(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::setVolume(qreal val)
|
void Player::setVolume(qreal val)
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_set_volume(player_, val);
|
gst_player_set_volume(player_, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::setMuted(bool val)
|
void Player::setMuted(bool val)
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_set_mute(player_, val);
|
gst_player_set_mute(player_, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGstPlayer::setPosition(qint64 pos)
|
void Player::setPosition(qint64 pos)
|
||||||
{
|
{
|
||||||
Q_ASSERT(player_ != 0);
|
Q_ASSERT(player_ != 0);
|
||||||
|
|
||||||
gst_player_seek(player_, pos);
|
gst_player_seek(player_, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
GstPlayerVideoRenderer *QGstPlayer::VideoRenderer::renderer()
|
GstPlayerVideoRenderer *VideoRenderer::renderer()
|
||||||
{
|
{
|
||||||
return renderer_;
|
return renderer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGstPlayer::VideoRenderer::VideoRenderer()
|
VideoRenderer::VideoRenderer()
|
||||||
{
|
{
|
||||||
renderer_ = static_cast<GstPlayerVideoRenderer*>
|
renderer_ = static_cast<GstPlayerVideoRenderer*>
|
||||||
(g_object_new (GST_TYPE_PLAYER_QT_VIDEO_RENDERER, "renderer", this, NULL));
|
(g_object_new (GST_TYPE_PLAYER_QT_VIDEO_RENDERER, "renderer", this, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
QGstPlayer::VideoRenderer::~VideoRenderer()
|
VideoRenderer::~VideoRenderer()
|
||||||
{
|
{
|
||||||
if (renderer_) gst_object_unref(renderer_);
|
if (renderer_) gst_object_unref(renderer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
struct _GstPlayerQtVideoRenderer
|
struct _GstPlayerQtVideoRenderer
|
||||||
{
|
{
|
||||||
GObject parent;
|
GObject parent;
|
||||||
|
@ -527,7 +770,7 @@ static void
|
||||||
|
|
||||||
qt_signal_dispatcher_param_specs
|
qt_signal_dispatcher_param_specs
|
||||||
[QT_SIGNAL_DISPATCHER_PROP_PLAYER] =
|
[QT_SIGNAL_DISPATCHER_PROP_PLAYER] =
|
||||||
g_param_spec_pointer ("player", "QGstPlayer instance", "",
|
g_param_spec_pointer ("player", "Player instance", "",
|
||||||
static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
g_object_class_install_properties (gobject_class,
|
g_object_class_install_properties (gobject_class,
|
||||||
|
|
|
@ -28,7 +28,16 @@
|
||||||
#include <QtQml/QQmlPropertyMap>
|
#include <QtQml/QQmlPropertyMap>
|
||||||
#include <gst/player/player.h>
|
#include <gst/player/player.h>
|
||||||
|
|
||||||
class QGstPlayer : public QObject
|
namespace QGstPlayer {
|
||||||
|
|
||||||
|
class VideoRenderer;
|
||||||
|
class MediaInfo;
|
||||||
|
class StreamInfo;
|
||||||
|
class VideInfo;
|
||||||
|
class AudioInfo;
|
||||||
|
class SubtitleInfo;
|
||||||
|
|
||||||
|
class Player : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
||||||
|
@ -41,14 +50,16 @@ class QGstPlayer : public QObject
|
||||||
Q_PROPERTY(State state READ state NOTIFY stateChanged)
|
Q_PROPERTY(State state READ state NOTIFY stateChanged)
|
||||||
Q_PROPERTY(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged)
|
Q_PROPERTY(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged)
|
||||||
Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged)
|
Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged)
|
||||||
|
Q_PROPERTY(QVariant currentVideo READ currentVideo WRITE setCurrentVideo)
|
||||||
|
Q_PROPERTY(QVariant currentAudio READ currentAudio WRITE setCurrentAudio)
|
||||||
|
Q_PROPERTY(QVariant currentSubtitle READ currentSubtitle WRITE setCurrentSubtitle)
|
||||||
|
Q_PROPERTY(bool subtitleEnabled READ isSubtitleEnabled WRITE setSubtitleEnabled
|
||||||
|
NOTIFY subtitleEnabledChanged)
|
||||||
|
|
||||||
Q_ENUMS(State)
|
Q_ENUMS(State)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit Player(QObject *parent = 0, VideoRenderer *renderer = 0);
|
||||||
class VideoRenderer;
|
|
||||||
|
|
||||||
explicit QGstPlayer(QObject *parent = 0, VideoRenderer *renderer = 0);
|
|
||||||
|
|
||||||
typedef GstPlayerError Error;
|
typedef GstPlayerError Error;
|
||||||
enum State {
|
enum State {
|
||||||
|
@ -58,6 +69,70 @@ public:
|
||||||
PLAYING = GST_PLAYER_STATE_PLAYING
|
PLAYING = GST_PLAYER_STATE_PLAYING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
MediaInfo *mediaInfo() const;
|
||||||
|
QVariant currentVideo() const;
|
||||||
|
QVariant currentAudio() const;
|
||||||
|
QVariant currentSubtitle() const;
|
||||||
|
bool isSubtitleEnabled() 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);
|
||||||
|
void subtitleEnabledChanged(bool enabled);
|
||||||
|
|
||||||
|
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);
|
||||||
|
void setCurrentVideo(QVariant track);
|
||||||
|
void setCurrentAudio(QVariant track);
|
||||||
|
void setCurrentSubtitle(QVariant track);
|
||||||
|
void setSubtitleEnabled(bool enabled);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(Player)
|
||||||
|
static void onStateChanged(Player *, GstPlayerState state);
|
||||||
|
static void onPositionUpdated(Player *, GstClockTime position);
|
||||||
|
static void onDurationChanged(Player *, GstClockTime duration);
|
||||||
|
static void onBufferingChanged(Player *, int percent);
|
||||||
|
static void onVideoDimensionsChanged(Player *, int w, int h);
|
||||||
|
static void onVolumeChanged(Player *);
|
||||||
|
static void onMuteChanged(Player *);
|
||||||
|
static void onMediaInfoUpdated(Player *, GstPlayerMediaInfo *media_info);
|
||||||
|
|
||||||
|
GstPlayer *player_;
|
||||||
|
State state_;
|
||||||
|
QSize videoDimensions_;
|
||||||
|
MediaInfo *mediaInfo_;
|
||||||
|
bool videoAvailable_;
|
||||||
|
bool subtitleEnabled_;
|
||||||
|
};
|
||||||
|
|
||||||
class VideoRenderer
|
class VideoRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -70,74 +145,108 @@ public:
|
||||||
GstPlayerVideoRenderer *renderer_;
|
GstPlayerVideoRenderer *renderer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO add remaining bits
|
class MediaInfo : public QObject
|
||||||
class MediaInfo
|
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString uri READ uri NOTIFY uriChanged)
|
||||||
|
Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged)
|
||||||
|
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||||
|
Q_PROPERTY(QList<QObject*> videoStreams READ videoStreams CONSTANT)
|
||||||
|
Q_PROPERTY(QList<QObject*> audioStreams READ audioStreams CONSTANT)
|
||||||
|
Q_PROPERTY(QList<QObject*> subtitleStreams READ subtitleStreams CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MediaInfo(GstPlayerMediaInfo *media_info);
|
explicit MediaInfo(Player *player = 0);
|
||||||
|
QString uri() const;
|
||||||
QString title() const;
|
QString title() const;
|
||||||
bool isSeekable() const;
|
bool isSeekable() const;
|
||||||
private:
|
const QList<QObject*> &videoStreams() const;
|
||||||
GstPlayerMediaInfo *mediaInfo_;
|
const QList<QObject*> &audioStreams() const;
|
||||||
};
|
const QList<QObject*> &subtitleStreams() const;
|
||||||
|
|
||||||
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:
|
signals:
|
||||||
void stateChanged(State new_state);
|
void uriChanged();
|
||||||
void bufferingChanged(int percent);
|
void seekableChanged();
|
||||||
void enfOfStream();
|
void titleChanged();
|
||||||
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);
|
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void update(GstPlayerMediaInfo *info);
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(QGstPlayer)
|
QString uri_;
|
||||||
static void onStateChanged(QGstPlayer *, GstPlayerState state);
|
QString title_;
|
||||||
static void onPositionUpdated(QGstPlayer *, GstClockTime position);
|
bool isSeekable_;
|
||||||
static void onDurationChanged(QGstPlayer *, GstClockTime duration);
|
QList<QObject*> videoStreams_;
|
||||||
static void onBufferingChanged(QGstPlayer *, int percent);
|
QList<QObject*> audioStreams_;
|
||||||
static void onVideoDimensionsChanged(QGstPlayer *, int w, int h);
|
QList<QObject*> subtitleStreams_;
|
||||||
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_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QGstPlayer*)
|
class StreamInfo : public QObject
|
||||||
Q_DECLARE_METATYPE(QGstPlayer::State)
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int index READ index CONSTANT)
|
||||||
|
public:
|
||||||
|
int index() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StreamInfo(GstPlayerStreamInfo* info);
|
||||||
|
private:
|
||||||
|
GstPlayerStreamInfo *stream_;
|
||||||
|
int index_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VideoInfo : public StreamInfo
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QSize resolution READ resolution CONSTANT)
|
||||||
|
public:
|
||||||
|
VideoInfo(GstPlayerVideoInfo *info);
|
||||||
|
QSize resolution() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GstPlayerVideoInfo *video_;
|
||||||
|
QSize resolution_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioInfo : public StreamInfo
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString language READ language CONSTANT)
|
||||||
|
Q_PROPERTY(int channels READ channels CONSTANT)
|
||||||
|
Q_PROPERTY(int bitRate READ bitRate CONSTANT)
|
||||||
|
Q_PROPERTY(int sampleRate READ sampleRate CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioInfo(GstPlayerAudioInfo *info);
|
||||||
|
QString const& language() const;
|
||||||
|
int channels() const;
|
||||||
|
int bitRate() const;
|
||||||
|
int sampleRate() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GstPlayerAudioInfo *audio_;
|
||||||
|
QString language_;
|
||||||
|
int channels_;
|
||||||
|
int bitRate_;
|
||||||
|
int sampleRate_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SubtitleInfo : public StreamInfo
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString language READ language CONSTANT)
|
||||||
|
public:
|
||||||
|
SubtitleInfo(GstPlayerSubtitleInfo *info);
|
||||||
|
QString const& language() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GstPlayerSubtitleInfo *subtitle_;
|
||||||
|
QString language_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QGstPlayer::Player*)
|
||||||
|
Q_DECLARE_METATYPE(QGstPlayer::Player::State)
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue