mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-11 11:51:34 +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
|
||||
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
|
||||
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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
class QuickRenderer;
|
||||
|
||||
class Player : public QGstPlayer
|
||||
class Player : public QGstPlayer::Player
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -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,6 +69,70 @@ public:
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -70,74 +145,108 @@ public:
|
|||
GstPlayerVideoRenderer *renderer_;
|
||||
};
|
||||
|
||||
// TODO add remaining bits
|
||||
class MediaInfo
|
||||
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:
|
||||
MediaInfo(GstPlayerMediaInfo *media_info);
|
||||
explicit MediaInfo(Player *player = 0);
|
||||
QString uri() const;
|
||||
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;
|
||||
|
||||
const QList<QObject*> &videoStreams() const;
|
||||
const QList<QObject*> &audioStreams() const;
|
||||
const QList<QObject*> &subtitleStreams() 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);
|
||||
void uriChanged();
|
||||
void seekableChanged();
|
||||
void titleChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void update(GstPlayerMediaInfo *info);
|
||||
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_;
|
||||
QString uri_;
|
||||
QString title_;
|
||||
bool isSeekable_;
|
||||
QList<QObject*> videoStreams_;
|
||||
QList<QObject*> audioStreams_;
|
||||
QList<QObject*> subtitleStreams_;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QGstPlayer*)
|
||||
Q_DECLARE_METATYPE(QGstPlayer::State)
|
||||
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::Player*)
|
||||
Q_DECLARE_METATYPE(QGstPlayer::Player::State)
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
|
Loading…
Reference in a new issue