summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Moreno <alexmorenocano@gmail.com>2015-10-22 23:05:35 +0800
committerSebastian Dröge <sebastian@centricular.com>2015-10-23 00:20:17 +0300
commitc8d7277d70378affb9096544f3b3edaa87fcf2c3 (patch)
treece59e719a13dcd58226456482b183b7a935a676e
parent2ea1c9aee74a6ce994279cb81e443675150959c8 (diff)
playback/player: qt: add stream selection support
-rw-r--r--playback/player/qt/main.qml294
-rw-r--r--playback/player/qt/player.cpp2
-rw-r--r--playback/player/qt/player.h2
-rw-r--r--playback/player/qt/qgstplayer.cpp375
-rw-r--r--playback/player/qt/qgstplayer.h193
5 files changed, 738 insertions, 128 deletions
diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml
index c7fe424..9825026 100644
--- a/playback/player/qt/main.qml
+++ b/playback/player/qt/main.qml
@@ -44,7 +44,7 @@ ApplicationWindow {
volume: 0.5
onStateChanged: {
if (state === Player.STOPPED) {
- playbutton.text = FontAwesome.Icon.Play
+ playbutton.state = "play"
}
}
onResolutionChanged: {
@@ -116,16 +116,236 @@ ApplicationWindow {
interval: 10000
onTriggered: {
parent.opacity = 0.0
+ settings.visible = false
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 {
id: grid
anchors.horizontalCenter: parent.horizontalCenter
-// anchors.top: parent.top
-// anchors.topMargin: 5
-
spacing: 7
rows: 1
verticalItemAlignment: Qt.AlignVCenter
@@ -161,10 +381,27 @@ ApplicationWindow {
Text {
anchors.centerIn: parent
id : playbutton
- font.pointSize: 25
font.family: "FontAwesome"
- //font.weight: Font.Light
- text: FontAwesome.Icon.PlayCircle
+ state: "play"
+
+ states: [
+ State {
+ name: "play"
+ PropertyChanges {
+ target: playbutton
+ text: FontAwesome.Icon.PlayCircle
+ font.pointSize: 25
+ }
+ },
+ State {
+ name: "pause"
+ PropertyChanges {
+ target: playbutton
+ text: FontAwesome.Icon.Pause
+ font.pointSize: 17
+ }
+ }
+ ]
}
MouseArea {
@@ -173,12 +410,10 @@ ApplicationWindow {
onPressed: {
if (player.state !== Player.PLAYING) {
player.play()
- playbutton.text = FontAwesome.Icon.Pause
- playbutton.font.pointSize = 17
+ playbutton.state = "pause"
} else {
player.pause()
- playbutton.text = FontAwesome.Icon.PlayCircle
- playbutton.font.pointSize = 25
+ playbutton.state = "play"
}
}
}
@@ -221,8 +456,6 @@ ApplicationWindow {
}
}
-
-
Item {
width: 40
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 {
width: 17
height: 17
-
Text {
id : volume
anchors.centerIn: parent
@@ -343,10 +590,22 @@ ApplicationWindow {
}
Text {
- id: sub
+ id: cog
font.pointSize: 17
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 {
@@ -380,7 +639,7 @@ ApplicationWindow {
maximumValue: player.duration
value: player.position
onPressedChanged: player.seek(value)
- enabled: player.mediaInfo.isSeekable
+ enabled: player.mediaInfo.seekable
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
@@ -455,7 +714,6 @@ ApplicationWindow {
}
}
}
-
}
}
}
diff --git a/playback/player/qt/player.cpp b/playback/player/qt/player.cpp
index ec4b78c..3e2cade 100644
--- a/playback/player/qt/player.cpp
+++ b/playback/player/qt/player.cpp
@@ -29,7 +29,7 @@ Player::Player(QObject *parent)
}
Player::Player(QObject *parent, QuickRenderer *renderer)
- : QGstPlayer(parent, renderer)
+ : QGstPlayer::Player(parent, renderer)
, renderer_(renderer)
{
renderer_->setParent(this);
diff --git a/playback/player/qt/player.h b/playback/player/qt/player.h
index 88586f4..34a0002 100644
--- a/playback/player/qt/player.h
+++ b/playback/player/qt/player.h
@@ -27,7 +27,7 @@
class QuickRenderer;
-class Player : public QGstPlayer
+class Player : public QGstPlayer::Player
{
Q_OBJECT
public:
diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp
index c2c0ee0..e6fc476 100644
--- a/playback/player/qt/qgstplayer.cpp
+++ b/playback/player/qt/qgstplayer.cpp
@@ -24,43 +24,200 @@
#include <QMetaObject>
#include <functional>
#include <QThread>
+#include <QtAlgorithms>
-class QGstPlayerRegisterMetaTypes
+namespace QGstPlayer {
+
+class RegisterMetaTypes
{
public:
- QGstPlayerRegisterMetaTypes()
+ RegisterMetaTypes()
{
- qRegisterMetaType<QGstPlayer::State>("State");
+ qRegisterMetaType<Player::State>("State");
}
} _register;
-QGstPlayer::MediaInfo::MediaInfo(GstPlayerMediaInfo *media_info)
- : mediaInfo_(media_info)
+MediaInfo::MediaInfo(Player *player)
+ : QObject(player)
+ , uri_()
+ , title_()
+ , isSeekable_(false)
{
}
-QString QGstPlayer::MediaInfo::title() const
+QString MediaInfo::uri() const
{
- QString title = QString::fromLocal8Bit
- (gst_player_media_info_get_title(mediaInfo_));
+ return uri_;
+}
+
+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 (title.isEmpty()) {
- QUrl url(gst_player_media_info_get_uri(mediaInfo_));
- title = url.fileName();
+ if (title_.isEmpty()) {
+ QUrl url(gst_player_media_info_get_uri(info));
+ title_ = url.fileName();
+ }
+
+ emit titleChanged();
+
+ if (isSeekable_ != gst_player_media_info_is_seekable(info)) {
+ isSeekable_ = !isSeekable_;
+ emit seekableChanged();
+ }
+
+ if (!subtitleStreams_.isEmpty()) {
+ qDeleteAll(subtitleStreams_);
+ subtitleStreams_.clear();
+ }
+
+ if (!videoStreams_.isEmpty()) {
+ qDeleteAll(videoStreams_);
+ videoStreams_.clear();
+ }
+
+ if (!audioStreams_.isEmpty()) {
+ qDeleteAll(audioStreams_);
+ audioStreams_.clear();
}
- return title;
+ 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))
+{
+
+}
+
+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_;
}
-bool QGstPlayer::MediaInfo::isSeekable() const
+int StreamInfo::index() const
{
- return gst_player_media_info_is_seekable(mediaInfo_);
+ return index_;
+}
+
+StreamInfo::StreamInfo(GstPlayerStreamInfo *info)
+ : stream_(info)
+ , index_(gst_player_stream_info_get_index(info))
+{
+
}
-bool QGstPlayer::isVideoAvailable() const
+bool Player::isVideoAvailable() const
{
GstPlayerVideoInfo *video_info;
@@ -73,74 +230,163 @@ bool QGstPlayer::isVideoAvailable() const
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)
, player_()
, state_(STOPPED)
, videoDimensions_(QSize())
- , mediaInfoMap_()
+ , mediaInfo_()
, videoAvailable_(false)
+ , subtitleEnabled_(false)
{
player_ = gst_player_new_full(renderer ? renderer->renderer() : 0,
gst_player_qt_signal_dispatcher_new(this));
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);
+ "swapped-signal::state-changed", G_CALLBACK (Player::onStateChanged), this,
+ "swapped-signal::position-updated", G_CALLBACK (Player::onPositionUpdated), this,
+ "swapped-signal::duration-changed", G_CALLBACK (Player::onDurationChanged), this,
+ "swapped-signal::buffering", G_CALLBACK (Player::onBufferingChanged), this,
+ "swapped-signal::video-dimensions-changed", G_CALLBACK (Player::onVideoDimensionsChanged), this,
+ "swapped-signal::volume-changed", G_CALLBACK (Player::onVolumeChanged), this,
+ "swapped-signal::mute-changed", G_CALLBACK (Player::onMuteChanged), this,
+ "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
-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_);
}
void
-QGstPlayer::onPositionUpdated(QGstPlayer * player, GstClockTime position)
+Player::onPositionUpdated(Player * player, GstClockTime position)
{
emit player->positionChanged(position);
}
void
-QGstPlayer::onDurationChanged(QGstPlayer * player, GstClockTime duration)
+Player::onDurationChanged(Player * player, GstClockTime duration)
{
emit player->durationChanged(duration);
}
void
-QGstPlayer::onBufferingChanged(QGstPlayer * player, int percent)
+Player::onBufferingChanged(Player * player, int percent)
{
emit player->bufferingChanged(percent);
}
void
-QGstPlayer::onVideoDimensionsChanged(QGstPlayer * player, int w, int h)
+Player::onVideoDimensionsChanged(Player * player, int w, int h)
{
QSize res(w,h);
+ if (res == player->videoDimensions_)
+ return;
+ player->videoDimensions_ = res;
+
player->setResolution(res);
emit player->resolutionChanged(res);
}
void
-QGstPlayer::onVolumeChanged(QGstPlayer *player)
+Player::onVolumeChanged(Player *player)
{
qreal new_val;
@@ -150,7 +396,7 @@ QGstPlayer::onVolumeChanged(QGstPlayer *player)
}
void
-QGstPlayer::onMuteChanged(QGstPlayer *player)
+Player::onMuteChanged(Player *player)
{
bool new_val;
@@ -160,15 +406,8 @@ QGstPlayer::onMuteChanged(QGstPlayer *player)
}
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();
if (player->videoAvailable_ != val) {
@@ -176,10 +415,12 @@ QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_inf
emit player->videoAvailableChanged(val);
}
+ player->mediaInfo()->update(media_info);
+
emit player->mediaInfoChanged();
}
-QUrl QGstPlayer::source() const
+QUrl Player::source() const
{
Q_ASSERT(player_ != 0);
QString url = QString::fromLocal8Bit(gst_player_get_uri(player_));
@@ -187,90 +428,90 @@ QUrl QGstPlayer::source() const
return QUrl(url);
}
-qint64 QGstPlayer::duration() const
+qint64 Player::duration() const
{
Q_ASSERT(player_ != 0);
return gst_player_get_duration(player_);
}
-qint64 QGstPlayer::position() const
+qint64 Player::position() const
{
Q_ASSERT(player_ != 0);
return gst_player_get_position(player_);
}
-qreal QGstPlayer::volume() const
+qreal Player::volume() const
{
Q_ASSERT(player_ != 0);
return gst_player_get_volume(player_);
}
-bool QGstPlayer::isMuted() const
+bool Player::isMuted() const
{
Q_ASSERT(player_ != 0);
return gst_player_get_mute(player_);
}
-int QGstPlayer::buffering() const
+int Player::buffering() const
{
return 0;
}
-QSize QGstPlayer::resolution() const
+QSize Player::resolution() const
{
return videoDimensions_;
}
-void QGstPlayer::setResolution(QSize size)
+void Player::setResolution(QSize size)
{
videoDimensions_ = size;
}
-QGstPlayer::State QGstPlayer::state() const
+Player::State Player::state() const
{
return state_;
}
-GstElement *QGstPlayer::pipeline() const
+GstElement *Player::pipeline() const
{
Q_ASSERT(player_ != 0);
return gst_player_get_pipeline(player_);
}
-void QGstPlayer::play()
+void Player::play()
{
Q_ASSERT(player_ != 0);
gst_player_play(player_);
}
-void QGstPlayer::pause()
+void Player::pause()
{
Q_ASSERT(player_ != 0);
gst_player_pause(player_);
}
-void QGstPlayer::stop()
+void Player::stop()
{
Q_ASSERT(player_ != 0);
gst_player_stop(player_);
}
-void QGstPlayer::seek(qint64 position)
+void Player::seek(qint64 position)
{
Q_ASSERT(player_ != 0);
gst_player_seek(player_, position);
}
-void QGstPlayer::setSource(QUrl const& url)
+void Player::setSource(QUrl const& url)
{
Q_ASSERT(player_ != 0);
QByteArray uri = url.toString().toLocal8Bit();
@@ -280,43 +521,45 @@ void QGstPlayer::setSource(QUrl const& url)
emit sourceChanged(url);
}
-void QGstPlayer::setVolume(qreal val)
+void Player::setVolume(qreal val)
{
Q_ASSERT(player_ != 0);
gst_player_set_volume(player_, val);
}
-void QGstPlayer::setMuted(bool val)
+void Player::setMuted(bool val)
{
Q_ASSERT(player_ != 0);
gst_player_set_mute(player_, val);
}
-void QGstPlayer::setPosition(qint64 pos)
+void Player::setPosition(qint64 pos)
{
Q_ASSERT(player_ != 0);
gst_player_seek(player_, pos);
}
-GstPlayerVideoRenderer *QGstPlayer::VideoRenderer::renderer()
+GstPlayerVideoRenderer *VideoRenderer::renderer()
{
return renderer_;
}
-QGstPlayer::VideoRenderer::VideoRenderer()
+VideoRenderer::VideoRenderer()
{
renderer_ = static_cast<GstPlayerVideoRenderer*>
(g_object_new (GST_TYPE_PLAYER_QT_VIDEO_RENDERER, "renderer", this, NULL));
}
-QGstPlayer::VideoRenderer::~VideoRenderer()
+VideoRenderer::~VideoRenderer()
{
if (renderer_) gst_object_unref(renderer_);
}
+}
+
struct _GstPlayerQtVideoRenderer
{
GObject parent;
@@ -527,7 +770,7 @@ static void
qt_signal_dispatcher_param_specs
[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));
g_object_class_install_properties (gobject_class,
diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h
index c0c39d0..1f4dc6f 100644
--- a/playback/player/qt/qgstplayer.h
+++ b/playback/player/qt/qgstplayer.h
@@ -28,7 +28,16 @@
#include <QtQml/QQmlPropertyMap>
#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_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(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged)
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)
public:
-
- class VideoRenderer;
-
- explicit QGstPlayer(QObject *parent = 0, VideoRenderer *renderer = 0);
+ explicit Player(QObject *parent = 0, VideoRenderer *renderer = 0);
typedef GstPlayerError Error;
enum State {
@@ -58,29 +69,6 @@ public:
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;
@@ -92,8 +80,11 @@ public:
QSize resolution() const;
void setResolution(QSize size);
bool isVideoAvailable() const;
- QQmlPropertyMap *mediaInfo() const;
-
+ MediaInfo *mediaInfo() const;
+ QVariant currentVideo() const;
+ QVariant currentAudio() const;
+ QVariant currentSubtitle() const;
+ bool isSubtitleEnabled() const;
signals:
void stateChanged(State new_state);
@@ -107,6 +98,7 @@ signals:
void mediaInfoChanged();
void sourceChanged(QUrl new_url);
void videoAvailableChanged(bool videoAvailable);
+ void subtitleEnabledChanged(bool enabled);
public slots:
void play();
@@ -117,27 +109,144 @@ public slots:
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(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);
+ 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_;
- QQmlPropertyMap *mediaInfoMap_;
+ MediaInfo *mediaInfo_;
bool videoAvailable_;
+ bool subtitleEnabled_;
+};
+
+class VideoRenderer
+{
+public:
+ GstPlayerVideoRenderer *renderer();
+ virtual GstElement *createVideoSink() = 0;
+protected:
+ VideoRenderer();
+ virtual ~VideoRenderer();
+private:
+ GstPlayerVideoRenderer *renderer_;
+};
+
+class MediaInfo : public QObject
+{
+ 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:
+ explicit MediaInfo(Player *player = 0);
+ QString uri() const;
+ QString title() const;
+ bool isSeekable() const;
+ const QList<QObject*> &videoStreams() const;
+ const QList<QObject*> &audioStreams() const;
+ const QList<QObject*> &subtitleStreams() const;
+
+signals:
+ void uriChanged();
+ void seekableChanged();
+ void titleChanged();
+
+public Q_SLOTS:
+ void update(GstPlayerMediaInfo *info);
+private:
+ QString uri_;
+ QString title_;
+ bool isSeekable_;
+ QList<QObject*> videoStreams_;
+ QList<QObject*> audioStreams_;
+ QList<QObject*> subtitleStreams_;
+};
+
+class StreamInfo : public QObject
+{
+ 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*)
-Q_DECLARE_METATYPE(QGstPlayer::State)
+}
+
+Q_DECLARE_METATYPE(QGstPlayer::Player*)
+Q_DECLARE_METATYPE(QGstPlayer::Player::State)
extern "C" {