diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/player/CMakeLists.txt | 5 | ||||
-rw-r--r-- | examples/player/main.cpp | 195 | ||||
-rw-r--r-- | examples/player/mediaapp.cpp | 183 | ||||
-rw-r--r-- | examples/player/mediaapp.h | 68 | ||||
-rw-r--r-- | examples/player/player.cpp | 195 | ||||
-rw-r--r-- | examples/player/player.h | 76 | ||||
-rw-r--r-- | examples/player/player.pro | 3 |
7 files changed, 539 insertions, 186 deletions
diff --git a/examples/player/CMakeLists.txt b/examples/player/CMakeLists.txt index 6fb9305..a3e50d6 100644 --- a/examples/player/CMakeLists.txt +++ b/examples/player/CMakeLists.txt @@ -5,5 +5,6 @@ find_package(QtGStreamer REQUIRED) include_directories(${QTGSTREAMER_INCLUDES}) add_definitions(${QTGSTREAMER_DEFINITIONS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${QTGSTREAMER_FLAGS}") -add_executable(player main.cpp) -target_link_libraries(player ${QTGSTREAMER_LIBRARIES}) +set(player_SOURCES main.cpp player.cpp mediaapp.cpp) +automoc4_add_executable(player ${player_SOURCES}) +target_link_libraries(player ${QTGSTREAMER_UI_LIBRARIES}) diff --git a/examples/player/main.cpp b/examples/player/main.cpp index 492691f..515e5a7 100644 --- a/examples/player/main.cpp +++ b/examples/player/main.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 Marco Ballesio <gibrovacco@gmail.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -14,192 +15,20 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <iostream> -#include <signal.h> -#include <QtCore/QCoreApplication> -#include <QtCore/QFile> -#include <QtCore/QTime> -#include <QGlib/Connect> -#include <QGst/Init> -#include <QGst/Pipeline> -#include <QGst/ElementFactory> -#include <QGst/GhostPad> -#include <QGst/Structure> -#include <QGst/Bus> -#include <QGst/Message> -#include <QGst/Query> -#include <QGst/Clock> -#include <QGst/Event> +#include <QtGui/QApplication> +#include <QGst/Global> +#include "mediaapp.h" -/* This is a simple example of a command-line audio player. It accepts the filename of - * an audio file as the first command line argument and then constructs a pipeline - * that uses decodebin2 to decode the audio stream and autoaudiosink to output it to - * the sound card. In the future this example will be expanded to handle video as well - * and perhaps it will gain a simple GUI too. */ - -class Player : public QObject -{ -public: - Player(const QString & fileName); - ~Player(); - -private: - void onBusSyncMessage(const QGst::MessagePtr & message); - void onNewDecodedPad(QGst::PadPtr newPad); - static QGst::BinPtr createAudioSinkBin(); - - /* This smart pointer is needed to keep a reference to the underlying GstPipeline object. - * Even if we are not going to use it, we must keep a reference to the pipeline, - * so that it remains in memory, together with all its child elements. If this - * reference is gone, the pipeline and all the elements will be destroyed. - * Note that we don't need to keep references to the individual elements, because - * when they are added in the pipeline, the pipeline keeps a reference on them. */ - QGst::PipelinePtr m_pipeline; -}; - -Player::Player(const QString & fileName) -{ - m_pipeline = QGst::Pipeline::create(); - - QGst::ElementPtr filesrc = QGst::ElementFactory::make("filesrc"); - QGst::ElementPtr decodebin = QGst::ElementFactory::make("decodebin2"); - - filesrc->setProperty("location", fileName); - QGlib::connect(decodebin, "new-decoded-pad", this, &Player::onNewDecodedPad); - - m_pipeline->add(filesrc); - m_pipeline->add(decodebin); - filesrc->link(decodebin); - - QGst::BusPtr bus = m_pipeline->bus(); - bus->enableSyncMessageEmission(); - QGlib::connect(bus, "sync-message", this, &Player::onBusSyncMessage); - - m_pipeline->setState(QGst::StatePlaying); -} - -Player::~Player() -{ - m_pipeline->setState(QGst::StateNull); - - /* When m_pipeline is destructed, the last reference to our pipeline will be gone, - * and with it all the elements, buses, etc will be destroyed too. As a result, - * there is no need to cleanup here. */ -} - -void Player::onBusSyncMessage(const QGst::MessagePtr & message) -{ - /* WARNING this slot gets called in a different thread */ - switch(message->type()) { - case QGst::MessageEos: //End of stream. We reached the end of the file. - case QGst::MessageError: //Some error occurred. - /* QCoreApplication::quit is safe to be called in another thread. - * It will schedule the main event loop to exit, when execution - * in the main thread has reached the event loop. */ - QCoreApplication::quit(); - break; - case QGst::MessageAsyncDone: - { - //File prerolled, queries the pipeline to get the file duration - QGst::DurationQueryPtr query = QGst::DurationQuery::create(QGst::FormatTime); - //This will create a temporary (cast to query). - m_pipeline->query(query); - - //qDebug() << QGst::Clock::timeFromClockTime(query->duration()); - - /*Set the pipeline to seek to 6 seconds in the stream and play until it reaches 15 secs - * Notice that using element->seek() is probably better in most cases - * - QGst::SeekEventPtr evt = QGst::SeekEvent::create(1.0, QGst::FormatTime, - QGst::SeekFlagNone, - QGst::SeekTypeSet, - QGst::Clock::clockTimeFromTime(QTime(0,0,6)), - QGst::SeekTypeSet, - QGst::Clock::clockTimeFromTime(QTime(0,0,15)) - ); - m_pipeline->sendEvent(evt);*/ - - /* this is the simple seek version - m_pipeline->seek(QGst::FormatTime, QGst::SeekFlagNone, - QGst::Clock::clockTimeFromTime(QTime(0,0,15)) );*/ - } - break; - default: - break; - } -} - -/* This method will be called every time a new "src" pad is available on the decodebin2 element. - * Here we have to check what kind of data this pad transfers (usually it is either "audio/x-raw-*" - * or "video/x-raw-*") and connect an appropriate sink that can handle this type of data. */ -void Player::onNewDecodedPad(QGst::PadPtr newPad) -{ - - QGst::CapsPtr caps = newPad->caps(); - QGst::StructurePtr structure = caps->internalStructure(0); - - /* The caps' first structure's name tells us what kind of data the pad transfers. - * Here we want to handle either audio/x-raw-int or audio/x-raw-float. Both types - * can be handled by the audioconvert element that is contained in the audioSinkBin, - * so there is no need to handle them separately */ - if (structure->name().contains("audio/x-raw")) { - QGst::BinPtr audioSinkBin = createAudioSinkBin(); - m_pipeline->add(audioSinkBin); - - /* The newly created bin must go to the playing state in order to function. - * Here we tell it to synchronise its state with its parent, the pipeline, - * which is scheduled to go to the playing state. */ - audioSinkBin->syncStateWithParent(); - - newPad->link(audioSinkBin->getStaticPad("sink")); - } -} - -QGst::BinPtr Player::createAudioSinkBin() -{ - QGst::BinPtr bin = QGst::Bin::create(); - - QGst::ElementPtr audioconvert = QGst::ElementFactory::make("audioconvert"); - QGst::ElementPtr audiosink = QGst::ElementFactory::make("autoaudiosink"); - - bin->add(audioconvert); - bin->add(audiosink); - audioconvert->link(audiosink); - - /* Add a sink pad to the bin that proxies the sink pad of the audioconvert element */ - bin->addPad(QGst::GhostPad::create(audioconvert->getStaticPad("sink"), "sink")); - - return bin; -} - -static void sighandler(int code) -{ - Q_UNUSED(code); - QCoreApplication::quit(); -} - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); +int main(int argc, char *argv[]) { + QApplication app(argc, argv); QGst::init(&argc, &argv); + MediaApp media; + media.show(); - QString fileName; - if (argc > 1) { - fileName = QFile::decodeName(argv[1]); - } - - if (!QFile::exists(fileName)) { - std::cerr << "Usage: " << argv[0] << " fileToPlay" << std::endl; - return 1; + if(argc == 2){ + media.openFile(argv[1]); } - Player *p = new Player(fileName); - - signal(SIGINT, sighandler); - int result = app.exec(); - - delete p; // we must delete all gstreamer objects before calling QGst::cleanup() - QGst::cleanup(); - - return result; + return app.exec(); } + diff --git a/examples/player/mediaapp.cpp b/examples/player/mediaapp.cpp new file mode 100644 index 0000000..5809340 --- /dev/null +++ b/examples/player/mediaapp.cpp @@ -0,0 +1,183 @@ +/* + Copyright (C) 2010 Marco Ballesio <gibrovacco@gmail.com> + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <QtGui> +#include <QtCore/QTime> +#include "mediaapp.h" + +MediaApp::MediaApp(QWidget *parent) : QWidget(parent) { + player = new Player(this); + player->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + player->setAutoFillBackground(false); + connect(player, SIGNAL(positionChanged(QTime)), this, SLOT(posChanged())); + connect(player, SIGNAL(stateChanged(QGst::State)), this, SLOT(stateChanged())); + + baseDir = "."; + fsTimer.setSingleShot(true); + connect(&fsTimer, SIGNAL(timeout()), this, SLOT(hideControls())); + + QVBoxLayout *appLayout = new QVBoxLayout; + appLayout->setContentsMargins(0,0,0,0); + createUI(appLayout); + setLayout(appLayout); + + stateChanged(); + setWindowTitle(tr("QtGstreamer example player")); + resize(400, 400); +} + +MediaApp::~MediaApp() { + delete player; +} + +void MediaApp::open() { + player->stop(); + QString fileName = QFileDialog::getOpenFileName( + this, tr("Open a Movie"), baseDir); + + if (!fileName.isEmpty()) + openFile(fileName); +} + +void MediaApp::mouseMoveEvent(QMouseEvent* event) { + if(isFullScreen()){ + if(!openButton->isVisible()) + showControls(true); + + fsTimer.start(3000); + } +} + + +void MediaApp::showControls(bool show) { + openButton->setVisible(show); + fullScreenButton->setVisible(show); + playButton->setVisible(show); + pauseButton->setVisible(show); + stopButton->setVisible(show); + posSlider->setVisible(show); + posLabel->setVisible(show); +} + +void MediaApp::toggleFullScreen() { + if(isFullScreen()){ + setMouseTracking(false); + fsTimer.stop(); + showNormal(); + } else { + showFullScreen(); + setMouseTracking(true); + showControls(false); + } +} + +void MediaApp::openFile(const QString &fileName) { + baseDir = QFileInfo(fileName).path(); + + player->setUri(fileName); + player->play(); +} + +void MediaApp::posChanged() { + QTime length = player->length(); + QTime curpos = player->position(); + posLabel->setText(curpos.toString() + "/" + length.toString()); + + if(length != QTime(0,0,0,0)){ + posSlider->setValue(curpos.msecsTo(QTime(0,0,0,0)) * 100 / + length.msecsTo(QTime(0,0,0,0))); + } + + if(curpos != QTime(0,0,0,0)){ + posLabel->setEnabled(true); + posSlider->setEnabled(true); + } +} + +void MediaApp::stateChanged() { + playButton->setEnabled(player->state() != QGst::StatePlaying); + pauseButton->setEnabled(player->state() == QGst::StatePlaying); + stopButton->setEnabled(player->state() != QGst::StateReady); + if(player->state() == QGst::StateReady){ + posLabel->setText("00:00:00/00:00:00"); + posSlider->setValue(0); + } +} + +void MediaApp::setPos(int value) { + quint64 length = -player->length().msecsTo(QTime(0,0,0,0)); + if(length != 0 && value > 0){ + QTime pos(0,0,0,0); + pos = pos.addMSecs( length*value/100); + player->setPosition(pos); + } +} + +inline QToolButton* MediaApp::initButton( + QStyle::StandardPixmap icon, + const char *tip, + QObject *dstobj, const char* slot_method, + QLayout *layout) +{ + QToolButton *button = new QToolButton; + button->setIcon(style()->standardIcon(icon)); + button->setIconSize(QSize(36,36)); + button->setToolTip(tr(tip)); + connect(button, SIGNAL(clicked()), dstobj, slot_method); + layout->addWidget(button); + + return button; +} + +void MediaApp::createUI(QBoxLayout *appLayout) { + appLayout->addWidget(player); + + posLabel = new QLabel(); + + posSlider = new QSlider(Qt::Horizontal); + posSlider->setTickPosition(QSlider::TicksBelow); + posSlider->setTickInterval(10); + posSlider->setMaximum(100); + + connect(posSlider, SIGNAL(sliderMoved(int)), this, SLOT(setPos(int))); + + QGridLayout *posLayout = new QGridLayout; + posLayout->addWidget(posLabel, 1, 0); + posLayout->addWidget(posSlider, 1, 1, 1, 2); + appLayout->addLayout(posLayout); + + QHBoxLayout *btnLayout = new QHBoxLayout; + btnLayout->addStretch(); + + openButton = initButton( + QStyle::SP_DialogOpenButton, "Open File", this, SLOT(open()), btnLayout); + + playButton = initButton( + QStyle::SP_MediaPlay, "Play", player, SLOT(play()), btnLayout); + + pauseButton = initButton( + QStyle::SP_MediaPause, "Pause", player, SLOT(pause()), btnLayout); + + stopButton = initButton( + QStyle::SP_MediaStop, "Stop", player, SLOT(stop()), btnLayout); + + fullScreenButton = initButton( + QStyle::SP_TitleBarMaxButton, "Fullscreen", this, SLOT(toggleFullScreen()), btnLayout); + + btnLayout->addStretch(); + appLayout->addLayout(btnLayout); +} diff --git a/examples/player/mediaapp.h b/examples/player/mediaapp.h new file mode 100644 index 0000000..1ab236b --- /dev/null +++ b/examples/player/mediaapp.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2010 Marco Ballesio <gibrovacco@gmail.com> + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MEDIAAPP_H +#define MEDIAAPP_H + +#include <QtGui/QWidget> +#include <QStyle> +#include "player.h" + +QT_BEGIN_NAMESPACE +class QBoxLayout; +class QLabel; +class QSlider; +class QToolButton; +class QTimer; +QT_END_NAMESPACE + +class MediaApp : public QWidget { + Q_OBJECT + + public: + MediaApp(QWidget *parent = 0); + ~MediaApp(); + void openFile(const QString &fileName); + + private Q_SLOTS: + void open(); + void toggleFullScreen(); + void stateChanged(); + void posChanged(); + void setPos(int); + void hideControls(){ showControls(false); } + + private: + QToolButton *initButton( + QStyle::StandardPixmap, const char* , QObject* , const char*, QLayout*); + void createUI(QBoxLayout *); + void showControls(bool); + void mouseMoveEvent(QMouseEvent*); + + QString baseDir; + Player *player; + QToolButton *openButton; + QToolButton *fullScreenButton; + QToolButton *playButton; + QToolButton *pauseButton; + QToolButton *stopButton; + QSlider *posSlider; + QLabel *posLabel; + QTimer fsTimer; +}; + +#endif diff --git a/examples/player/player.cpp b/examples/player/player.cpp new file mode 100644 index 0000000..dd89314 --- /dev/null +++ b/examples/player/player.cpp @@ -0,0 +1,195 @@ +/* + Copyright (C) 2010 Marco Ballesio <gibrovacco@gmail.com> + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "player.h" +#include <iostream> +#include <QtCore/QTime> +#include <QtCore/QDir> +#include <QtGui/QApplication> +#include <QGlib/Signal> +#include <QGst/Global> +#include <QGst/Pipeline> +#include <QGst/ElementFactory> +#include <QGst/XOverlay> +#include <QGst/Bus> +#include <QGst/Message> +#include <QGst/Query> +#include <QGst/Clock> +#include <QGst/Event> + +/* This is a simple example of a command-line player. It accepts the URI of + * a media file as the first command line argument and then constructs a pipeline + * that uses playbin2 to decode the stream. */ + +Player::Player(QWidget *parent) + : QGst::Ui::VideoWidget(parent) { + connect(&m_positionTimer, SIGNAL(timeout()), this, SLOT(updatePosition())); + setMouseTracking(true); + } + +void Player::setUri(const QString & uri) { + QString realUri = uri; + + if(uri.indexOf("://") < 0){ + if(realUri[0] != '/'){ + realUri = QDir::current().path() + "/" + realUri; + } + realUri = "file://" + realUri; + } + + if(!m_pipeline){ + QGst::ElementPtr playbin = QGst::ElementFactory::make("playbin2"); + if(playbin) { + m_pipeline = playbin.dynamicCast<QGst::Pipeline>(); + QGst::BusPtr bus = m_pipeline->bus(); + QGlib::Signal::connect(bus, "message", this, &Player::busMessage); + bus->addSignalWatch(); + } + } + + if(m_pipeline){ + m_pipeline->setProperty("uri", realUri); + } +} + +Player::~Player() { + if(m_pipeline) + m_pipeline->setState(QGst::StateNull); +} + +void Player::updatePosition() { + Q_EMIT positionChanged(position()); +} + +void Player::play() { + if(m_pipeline){ + m_pipeline->setState(QGst::StatePlaying); + } +} + +void Player::pause( ){ + if(m_pipeline){ + m_pipeline->setState(QGst::StatePaused); + } +} + +void Player::stop() { + if(m_pipeline){ + m_pipeline->setState(QGst::StateReady); + } +} + +void Player::setPosition(QTime pos) { + QGst::SeekEventPtr evt = QGst::SeekEvent::create( + 1.0, QGst::FormatTime, QGst::SeekFlagFlush, + QGst::SeekTypeSet, QGst::Clock::clockTimeFromTime(pos), + QGst::SeekTypeNone, -1); + + m_pipeline.dynamicCast<QGst::Element>()->sendEvent(evt); +} + +QTime Player::position() { + if(m_pipeline){ + QGst::PositionQueryPtr query = QGst::PositionQuery::create(QGst::FormatTime); + m_pipeline.dynamicCast<QGst::Element>()->query(query); + return QGst::Clock::timeFromClockTime(query->position()); + } + return QTime(0, 0, 0, 0); +} + +QTime Player::length() { + if(m_pipeline){ + QGst::DurationQueryPtr query = QGst::DurationQuery::create(QGst::FormatTime); + m_pipeline->query(query); + return QGst::Clock::timeFromClockTime(query->duration()); + } + return QTime(0, 0, 0, 0); +} + +QGst::State Player::state() { + QGst::State state; + if(!m_pipeline || + m_pipeline.dynamicCast<QGst::Element>()->getState(&state, NULL, 1e9) != + QGst::StateChangeSuccess) + { + state = QGst::StateNull; + } + return state; +} + +void Player::handleStateChange(QGst::StateChangedMessagePtr scm) { + switch(scm->newState()){ + case QGst::StatePlaying: + Q_EMIT positionChanged(position()); + m_positionTimer.start(500); + break; + case QGst::StatePaused: + if(scm->oldState() == QGst::StateReady){ + QGst::ElementPtr sink = + m_pipeline->property("video-sink").get<QGst::ElementPtr>(); + if(sink){ + setVideoSink(sink); + QGst::ChildProxyPtr proxy = sink.dynamicCast<QGst::ChildProxy>(); + proxy->childByIndex(0)->setProperty("force-aspect-ratio", true); + } + } else + m_positionTimer.stop(); + break; + case QGst::StateReady: + if(scm->oldState() == QGst::StatePaused) + /* Remove the sink now to avoid inter-thread issues with Qt + for the next time the pipeline goes to StatePlaying */ + setVideoSink(QGst::ElementPtr()); + break; + default: + break; + } +} + +void Player::busMessage(const QGst::MessagePtr & message) { + switch(message->type()) { + case QGst::MessageEos: //End of stream. We reached the end of the file. + qDebug() << "got eos"; + m_pipeline->setState(QGst::StateReady); + break; + case QGst::MessageError: //Some error occurred. + /*TODO: send a message to UI */ + break; + case QGst::MessageAsyncDone: + { + //File prerolled, queries the pipeline to get the file duration + QGst::DurationQueryPtr query = QGst::DurationQuery::create(QGst::FormatTime); + //This will create a temporary (cast to query). + m_pipeline->query(query); + } + break; + case QGst::MessageStateChanged: + if(QGlib::Type::fromInstance(message->source()). + isA(QGlib::GetType<QGst::Pipeline>())) + { + QGst::StateChangedMessagePtr scm = + message.dynamicCast<QGst::StateChangedMessage>(); + handleStateChange(scm); + Q_EMIT stateChanged(scm->newState()); + } + + break; + default: + break; + } +} + diff --git a/examples/player/player.h b/examples/player/player.h new file mode 100644 index 0000000..ac442b0 --- /dev/null +++ b/examples/player/player.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> + Copyright (C) 2010 Marco Ballesio <gibrovacco@gmail.com> + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PLAYER_H__ +#define __PLAYER_H__ + +#include <QtCore/QEvent> +#include <QtCore/QTimer> +#include <QtCore/QString> +#include <QtCore/QTime> +#include <QGst/Global> +#include <QGst/Pipeline> +#include <QGst/Ui/VideoWidget> + +/* This is a simple example of a command-line player. It accepts the URI of + * an media file as the first command line argument and then constructs a pipeline + * that uses playbin2 to decode the stream. + * In the future this example will perhaps gain a simple GUI. */ + +class Player : public QGst::Ui::VideoWidget +{ + Q_OBJECT; + public: + Player(QWidget *parent = 0); + ~Player(); + + void setUri(const QString &uri); + QTime position(); + QTime length(); + QGst::State state(); + + /* Everything is compiled with QT_NO_KEYWORDS because otherwise Signals::emit wouldn't compile + * so use Q_SLOTS instead of "slots" */ + public Q_SLOTS: + void stop(); + void play(); + void pause(); + void setPosition(QTime pos); + void updatePosition(); + +Q_SIGNALS: + void positionChanged(QTime); + void stateChanged(QGst::State state); + + private: + void busMessage(const QGst::MessagePtr & message); + void elementAdded(const QGst::ElementPtr & element); + void handleStateChange(QGst::StateChangedMessagePtr); + QGst::XOverlayPtr binVideoSink(QGst::BinPtr & bin); + + /* This smart pointer is needed to keep a reference to the underlying GstPipeline object. + * Even if we are not going to use it, we must keep a reference to the pipeline, + * so that it remains in memory, together with all its child elements. If this + * reference is gone, the pipeline and all the elements will be destroyed. + * Note that we don't need to keep references to the individual elements, because + * when they are added in the pipeline, the pipeline keeps a reference on them. */ + QGst::PipelinePtr m_pipeline; + QTimer m_positionTimer; +}; + +#endif diff --git a/examples/player/player.pro b/examples/player/player.pro index b75e5d1..1d56905 100644 --- a/examples/player/player.pro +++ b/examples/player/player.pro @@ -21,4 +21,5 @@ DEFINES += QT_NO_KEYWORDS QT -= gui # Input -SOURCES += main.cpp +HEADERS += movieplayer.h player.h +SOURCES += main.cpp movieplayer.cpp player.cpp |