diff options
Diffstat (limited to 'examples/multimediawidgets/player')
-rw-r--r-- | examples/multimediawidgets/player/doc/src/player.qdoc | 96 | ||||
-rw-r--r-- | examples/multimediawidgets/player/histogramwidget.cpp | 154 | ||||
-rw-r--r-- | examples/multimediawidgets/player/histogramwidget.h | 83 | ||||
-rw-r--r-- | examples/multimediawidgets/player/main.cpp | 62 | ||||
-rw-r--r-- | examples/multimediawidgets/player/player.cpp | 428 | ||||
-rw-r--r-- | examples/multimediawidgets/player/player.h | 127 | ||||
-rw-r--r-- | examples/multimediawidgets/player/player.pro | 28 | ||||
-rw-r--r-- | examples/multimediawidgets/player/playercontrols.cpp | 205 | ||||
-rw-r--r-- | examples/multimediawidgets/player/playercontrols.h | 98 | ||||
-rw-r--r-- | examples/multimediawidgets/player/playlistmodel.cpp | 156 | ||||
-rw-r--r-- | examples/multimediawidgets/player/playlistmodel.h | 88 | ||||
-rw-r--r-- | examples/multimediawidgets/player/videowidget.cpp | 81 | ||||
-rw-r--r-- | examples/multimediawidgets/player/videowidget.h | 59 |
13 files changed, 1665 insertions, 0 deletions
diff --git a/examples/multimediawidgets/player/doc/src/player.qdoc b/examples/multimediawidgets/player/doc/src/player.qdoc new file mode 100644 index 000000000..5e98b912c --- /dev/null +++ b/examples/multimediawidgets/player/doc/src/player.qdoc @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example player + \title Media Player Example + \ingroup video_examples + + + This example creates a simple multimedia player. We can play audio and + or video files using various codecs. + + The example uses a QMediaPlayer object passed into a QVideoWidget to + control the video output. To give the application playlist capability + we also use a QPlayList object. + + To activate the various functions such as play and stop on the dialog + we connect clicked() signals to slots that emit the play() and stop() + signals and in turn which we connect to the play() and stop() slots in + QMediaPlayer. + + \code + connect(controls, SIGNAL(play()), player, SLOT(play())); + connect(controls, SIGNAL(pause()), player, SLOT(pause())); + connect(controls, SIGNAL(stop()), player, SLOT(stop())); + \endcode + + We can get the volume (and set our user interface representation) + + \code + controls->setVolume(player->volume()); + \endcode + + and we can make widget 'volume' changes change the volume + + \code + connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int))); + \endcode + + The example also allows us to change various video properties by means + of the QVideoWidget object. We can go to Full Screen mode with a single + button click, and back again. Or if we press the "Color Options" dialog + button we can have access to more subtle influences. The dialog has a + set of sliders so that we can change the brightness, contrast, hue and + saturation of the video being watched. The connect() statements are in + pairs so that changes to either the user interface widget (the relevant + slider) or the QVideoWidget object will update the other object. + + \code + connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget, + SLOT(setBrightness(int))); + connect(videoWidget, SIGNAL(brightnessChanged(int)), + brightnessSlider, SLOT(setValue(int))); + + connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget, + SLOT(setContrast(int))); + connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider, + SLOT(setValue(int))); + + connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget, + SLOT(setHue(int))); + connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider, + SLOT(setValue(int))); + + connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget, + SLOT(setSaturation(int))); + connect(videoWidget, SIGNAL(saturationChanged(int)), + saturationSlider, SLOT(setValue(int))); + \endcode + +*/ + diff --git a/examples/multimediawidgets/player/histogramwidget.cpp b/examples/multimediawidgets/player/histogramwidget.cpp new file mode 100644 index 000000000..7d4e63a58 --- /dev/null +++ b/examples/multimediawidgets/player/histogramwidget.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "histogramwidget.h" +#include <QPainter> + +HistogramWidget::HistogramWidget(QWidget *parent) + : QWidget(parent) + , m_levels(128) + , m_isBusy(false) +{ + m_processor.moveToThread(&m_processorThread); + qRegisterMetaType<QVector<qreal> >("QVector<qreal>"); + connect(&m_processor, SIGNAL(histogramReady(QVector<qreal>)), SLOT(setHistogram(QVector<qreal>))); + m_processorThread.start(QThread::LowestPriority); +} + +HistogramWidget::~HistogramWidget() +{ + m_processorThread.quit(); + m_processorThread.wait(10000); +} + +void HistogramWidget::processFrame(QVideoFrame frame) +{ + if (m_isBusy) + return; //drop frame + + m_isBusy = true; + QMetaObject::invokeMethod(&m_processor, "processFrame", + Qt::QueuedConnection, Q_ARG(QVideoFrame, frame), Q_ARG(int, m_levels)); +} + +void HistogramWidget::setHistogram(QVector<qreal> histogram) +{ + m_isBusy = false; + m_histogram = histogram; + update(); +} + +void HistogramWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + QPainter painter(this); + + if (m_histogram.isEmpty()) { + painter.fillRect(0, 0, width(), height(), QColor::fromRgb(0, 0, 0)); + return; + } + + qreal barWidth = width() / (qreal)m_histogram.size(); + + for (int i = 0; i < m_histogram.size(); i++) { + qreal h = m_histogram[i] * height(); + // draw level + painter.fillRect(barWidth * i, height() - h, barWidth * (i + 1), height(), Qt::red); + // clear the rest of the control + painter.fillRect(barWidth * i, 0, barWidth * (i + 1), height() - h, Qt::black); + } +} + +void FrameProcessor::processFrame(QVideoFrame frame, int levels) +{ + QVector<qreal> histogram(levels); + + do { + if (!levels) + break; + + if (!frame.map(QAbstractVideoBuffer::ReadOnly)) + break; + + if (frame.pixelFormat() == QVideoFrame::Format_YUV420P || + frame.pixelFormat() == QVideoFrame::Format_NV12) { + // Process YUV data + uchar *b = frame.bits(); + for (int y = 0; y < frame.height(); y++) { + uchar *lastPixel = b + frame.width(); + for (uchar *curPixel = b; curPixel < lastPixel; curPixel++) + histogram[(*curPixel * levels) >> 8] += 1.0; + b += frame.bytesPerLine(); + } + } else { + QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); + if (imageFormat != QImage::Format_Invalid) { + // Process RGB data + QImage image(frame.bits(), frame.width(), frame.height(), imageFormat); + image = image.convertToFormat(QImage::Format_RGB32); + + const QRgb* b = (const QRgb*)image.bits(); + for (int y = 0; y < image.height(); y++) { + const QRgb *lastPixel = b + frame.width(); + for (const QRgb *curPixel = b; curPixel < lastPixel; curPixel++) + histogram[(qGray(*curPixel) * levels) >> 8] += 1.0; + b = (const QRgb*)((uchar*)b + image.bytesPerLine()); + } + } + } + + // find maximum value + qreal maxValue = 0.0; + for (int i = 0; i < histogram.size(); i++) { + if (histogram[i] > maxValue) + maxValue = histogram[i]; + } + + if (maxValue > 0.0) { + for (int i = 0; i < histogram.size(); i++) + histogram[i] /= maxValue; + } + + frame.unmap(); + } while (false); + + emit histogramReady(histogram); +} diff --git a/examples/multimediawidgets/player/histogramwidget.h b/examples/multimediawidgets/player/histogramwidget.h new file mode 100644 index 000000000..6a8aa16fe --- /dev/null +++ b/examples/multimediawidgets/player/histogramwidget.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HISTOGRAMWIDGET_H +#define HISTOGRAMWIDGET_H + +#include <QThread> +#include <QVideoFrame> +#include <QWidget> + +class FrameProcessor: public QObject +{ + Q_OBJECT + +public slots: + void processFrame(QVideoFrame frame, int levels); + +signals: + void histogramReady(QVector<qreal> histogram); +}; + +class HistogramWidget : public QWidget +{ + Q_OBJECT + +public: + explicit HistogramWidget(QWidget *parent = 0); + ~HistogramWidget(); + void setLevels(int levels) { m_levels = levels; } + +public slots: + void processFrame(QVideoFrame frame); + void setHistogram(QVector<qreal> histogram); + +protected: + void paintEvent(QPaintEvent *event); + +private: + QVector<qreal> m_histogram; + int m_levels; + FrameProcessor m_processor; + QThread m_processorThread; + bool m_isBusy; +}; + +#endif // HISTOGRAMWIDGET_H diff --git a/examples/multimediawidgets/player/main.cpp b/examples/multimediawidgets/player/main.cpp new file mode 100644 index 000000000..4754a03e2 --- /dev/null +++ b/examples/multimediawidgets/player/main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "player.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ +#ifdef Q_WS_MAEMO_6 + //Meego graphics system conflicts with xvideo during fullscreen transition + QApplication::setGraphicsSystem("raster"); +#endif + QApplication app(argc, argv); + + Player player; + +#if defined(Q_WS_SIMULATOR) + player.setAttribute(Qt::WA_LockLandscapeOrientation); + player.showMaximized(); +#else + player.show(); +#endif + return app.exec(); +} diff --git a/examples/multimediawidgets/player/player.cpp b/examples/multimediawidgets/player/player.cpp new file mode 100644 index 000000000..fbc3e575e --- /dev/null +++ b/examples/multimediawidgets/player/player.cpp @@ -0,0 +1,428 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "player.h" + +#include "playercontrols.h" +#include "playlistmodel.h" +#include "histogramwidget.h" + +#include <QMediaService> +#include <QMediaPlaylist> +#include <QVideoProbe> +#include <QtWidgets> + + +Player::Player(QWidget *parent) + : QWidget(parent) + , videoWidget(0) + , coverLabel(0) + , slider(0) +#ifndef PLAYER_NO_COLOROPTIONS + , colorDialog(0) +#endif +{ +//! [create-objs] + player = new QMediaPlayer(this); + // owned by PlaylistModel + playlist = new QMediaPlaylist(); + player->setPlaylist(playlist); +//! [create-objs] + + connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64))); + connect(player, SIGNAL(positionChanged(qint64)), SLOT(positionChanged(qint64))); + connect(player, SIGNAL(metaDataChanged()), SLOT(metaDataChanged())); + connect(playlist, SIGNAL(currentIndexChanged(int)), SLOT(playlistPositionChanged(int))); + connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SLOT(statusChanged(QMediaPlayer::MediaStatus))); + connect(player, SIGNAL(bufferStatusChanged(int)), this, SLOT(bufferingProgress(int))); + connect(player, SIGNAL(videoAvailableChanged(bool)), this, SLOT(videoAvailableChanged(bool))); + connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(displayErrorMessage())); + +//! [2] + videoWidget = new VideoWidget(this); + player->setVideoOutput(videoWidget); + + playlistModel = new PlaylistModel(this); + playlistModel->setPlaylist(playlist); +//! [2] + + playlistView = new QListView(this); + playlistView->setModel(playlistModel); + playlistView->setCurrentIndex(playlistModel->index(playlist->currentIndex(), 0)); + + connect(playlistView, SIGNAL(activated(QModelIndex)), this, SLOT(jump(QModelIndex))); + + slider = new QSlider(Qt::Horizontal, this); + slider->setRange(0, player->duration() / 1000); + + labelDuration = new QLabel(this); + connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int))); + + labelHistogram = new QLabel(this); + labelHistogram->setText("Histogram:"); + histogram = new HistogramWidget(this); + QHBoxLayout *histogramLayout = new QHBoxLayout; + histogramLayout->addWidget(labelHistogram); + histogramLayout->addWidget(histogram, 1); + + probe = new QVideoProbe(this); + connect(probe, SIGNAL(videoFrameProbed(const QVideoFrame&)), histogram, SLOT(processFrame(QVideoFrame))); + probe->setSource(player); + + QPushButton *openButton = new QPushButton(tr("Open"), this); + + connect(openButton, SIGNAL(clicked()), this, SLOT(open())); + + PlayerControls *controls = new PlayerControls(this); + controls->setState(player->state()); + controls->setVolume(player->volume()); + controls->setMuted(controls->isMuted()); + + connect(controls, SIGNAL(play()), player, SLOT(play())); + connect(controls, SIGNAL(pause()), player, SLOT(pause())); + connect(controls, SIGNAL(stop()), player, SLOT(stop())); + connect(controls, SIGNAL(next()), playlist, SLOT(next())); + connect(controls, SIGNAL(previous()), this, SLOT(previousClicked())); + connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int))); + connect(controls, SIGNAL(changeMuting(bool)), player, SLOT(setMuted(bool))); + connect(controls, SIGNAL(changeRate(qreal)), player, SLOT(setPlaybackRate(qreal))); + + connect(controls, SIGNAL(stop()), videoWidget, SLOT(update())); + + connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), + controls, SLOT(setState(QMediaPlayer::State))); + connect(player, SIGNAL(volumeChanged(int)), controls, SLOT(setVolume(int))); + connect(player, SIGNAL(mutedChanged(bool)), controls, SLOT(setMuted(bool))); + + fullScreenButton = new QPushButton(tr("FullScreen"), this); + fullScreenButton->setCheckable(true); + +#ifndef PLAYER_NO_COLOROPTIONS + colorButton = new QPushButton(tr("Color Options..."), this); + colorButton->setEnabled(false); + connect(colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog())); +#endif + + QBoxLayout *displayLayout = new QHBoxLayout; + displayLayout->addWidget(videoWidget, 2); + displayLayout->addWidget(playlistView); + + QBoxLayout *controlLayout = new QHBoxLayout; + controlLayout->setMargin(0); + controlLayout->addWidget(openButton); + controlLayout->addStretch(1); + controlLayout->addWidget(controls); + controlLayout->addStretch(1); + controlLayout->addWidget(fullScreenButton); +#ifndef PLAYER_NO_COLOROPTIONS + controlLayout->addWidget(colorButton); +#endif + + QBoxLayout *layout = new QVBoxLayout; + layout->addLayout(displayLayout); + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(slider); + hLayout->addWidget(labelDuration); + layout->addLayout(hLayout); + layout->addLayout(controlLayout); + layout->addLayout(histogramLayout); + + setLayout(layout); + + if (!player->isAvailable()) { + QMessageBox::warning(this, tr("Service not available"), + tr("The QMediaPlayer object does not have a valid service.\n"\ + "Please check the media service plugins are installed.")); + + controls->setEnabled(false); + playlistView->setEnabled(false); + openButton->setEnabled(false); +#ifndef PLAYER_NO_COLOROPTIONS + colorButton->setEnabled(false); +#endif + fullScreenButton->setEnabled(false); + } + + metaDataChanged(); + + QStringList arguments = qApp->arguments(); + arguments.removeAt(0); + addToPlaylist(arguments); +} + +Player::~Player() +{ +} + +void Player::open() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Files")); + addToPlaylist(fileNames); +} + +void Player::addToPlaylist(const QStringList& fileNames) +{ + foreach (QString const &argument, fileNames) { + QFileInfo fileInfo(argument); + if (fileInfo.exists()) { + QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + if (fileInfo.suffix().toLower() == QLatin1String("m3u")) { + playlist->load(url); + } else + playlist->addMedia(url); + } else { + QUrl url(argument); + if (url.isValid()) { + playlist->addMedia(url); + } + } + } +} + +void Player::durationChanged(qint64 duration) +{ + this->duration = duration/1000; + slider->setMaximum(duration / 1000); +} + +void Player::positionChanged(qint64 progress) +{ + if (!slider->isSliderDown()) { + slider->setValue(progress / 1000); + } + updateDurationInfo(progress / 1000); +} + +void Player::metaDataChanged() +{ + if (player->isMetaDataAvailable()) { + setTrackInfo(QString("%1 - %2") + .arg(player->metaData(QMediaMetaData::AlbumArtist).toString()) + .arg(player->metaData(QMediaMetaData::Title).toString())); + + if (coverLabel) { + QUrl url = player->metaData(QMediaMetaData::CoverArtUrlLarge).value<QUrl>(); + + coverLabel->setPixmap(!url.isEmpty() + ? QPixmap(url.toString()) + : QPixmap()); + } + } +} + +void Player::previousClicked() +{ + // Go to previous track if we are within the first 5 seconds of playback + // Otherwise, seek to the beginning. + if(player->position() <= 5000) + playlist->previous(); + else + player->setPosition(0); +} + +void Player::jump(const QModelIndex &index) +{ + if (index.isValid()) { + playlist->setCurrentIndex(index.row()); + player->play(); + } +} + +void Player::playlistPositionChanged(int currentItem) +{ + playlistView->setCurrentIndex(playlistModel->index(currentItem, 0)); +} + +void Player::seek(int seconds) +{ + player->setPosition(seconds * 1000); +} + +void Player::statusChanged(QMediaPlayer::MediaStatus status) +{ + handleCursor(status); + + // handle status message + switch (status) { + case QMediaPlayer::UnknownMediaStatus: + case QMediaPlayer::NoMedia: + case QMediaPlayer::LoadedMedia: + case QMediaPlayer::BufferingMedia: + case QMediaPlayer::BufferedMedia: + setStatusInfo(QString()); + break; + case QMediaPlayer::LoadingMedia: + setStatusInfo(tr("Loading...")); + break; + case QMediaPlayer::StalledMedia: + setStatusInfo(tr("Media Stalled")); + break; + case QMediaPlayer::EndOfMedia: + QApplication::alert(this); + break; + case QMediaPlayer::InvalidMedia: + displayErrorMessage(); + break; + } +} + +void Player::handleCursor(QMediaPlayer::MediaStatus status) +{ +#ifndef QT_NO_CURSOR + if (status == QMediaPlayer::LoadingMedia || + status == QMediaPlayer::BufferingMedia || + status == QMediaPlayer::StalledMedia) + setCursor(QCursor(Qt::BusyCursor)); + else + unsetCursor(); +#endif +} + +void Player::bufferingProgress(int progress) +{ + setStatusInfo(tr("Buffering %4%").arg(progress)); +} + +void Player::videoAvailableChanged(bool available) +{ + if (!available) { + disconnect(fullScreenButton, SIGNAL(clicked(bool)), + videoWidget, SLOT(setFullScreen(bool))); + disconnect(videoWidget, SIGNAL(fullScreenChanged(bool)), + fullScreenButton, SLOT(setChecked(bool))); + videoWidget->setFullScreen(false); + } else { + connect(fullScreenButton, SIGNAL(clicked(bool)), + videoWidget, SLOT(setFullScreen(bool))); + connect(videoWidget, SIGNAL(fullScreenChanged(bool)), + fullScreenButton, SLOT(setChecked(bool))); + + if (fullScreenButton->isChecked()) + videoWidget->setFullScreen(true); + } +#ifndef PLAYER_NO_COLOROPTIONS + colorButton->setEnabled(available); +#endif +} + +void Player::setTrackInfo(const QString &info) +{ + trackInfo = info; + if (!statusInfo.isEmpty()) + setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo)); + else + setWindowTitle(trackInfo); +} + +void Player::setStatusInfo(const QString &info) +{ + statusInfo = info; + if (!statusInfo.isEmpty()) + setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo)); + else + setWindowTitle(trackInfo); +} + +void Player::displayErrorMessage() +{ + setStatusInfo(player->errorString()); +} + +void Player::updateDurationInfo(qint64 currentInfo) +{ + QString tStr; + if (currentInfo || duration) { + QTime currentTime((currentInfo/3600)%60, (currentInfo/60)%60, currentInfo%60, (currentInfo*1000)%1000); + QTime totalTime((duration/3600)%60, (duration/60)%60, duration%60, (duration*1000)%1000); + QString format = "mm:ss"; + if (duration > 3600) + format = "hh:mm:ss"; + tStr = currentTime.toString(format) + " / " + totalTime.toString(format); + } + labelDuration->setText(tStr); +} + +#ifndef PLAYER_NO_COLOROPTIONS +void Player::showColorDialog() +{ + if (!colorDialog) { + QSlider *brightnessSlider = new QSlider(Qt::Horizontal); + brightnessSlider->setRange(-100, 100); + brightnessSlider->setValue(videoWidget->brightness()); + connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setBrightness(int))); + connect(videoWidget, SIGNAL(brightnessChanged(int)), brightnessSlider, SLOT(setValue(int))); + + QSlider *contrastSlider = new QSlider(Qt::Horizontal); + contrastSlider->setRange(-100, 100); + contrastSlider->setValue(videoWidget->contrast()); + connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setContrast(int))); + connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider, SLOT(setValue(int))); + + QSlider *hueSlider = new QSlider(Qt::Horizontal); + hueSlider->setRange(-100, 100); + hueSlider->setValue(videoWidget->hue()); + connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setHue(int))); + connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider, SLOT(setValue(int))); + + QSlider *saturationSlider = new QSlider(Qt::Horizontal); + saturationSlider->setRange(-100, 100); + saturationSlider->setValue(videoWidget->saturation()); + connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setSaturation(int))); + connect(videoWidget, SIGNAL(saturationChanged(int)), saturationSlider, SLOT(setValue(int))); + + QFormLayout *layout = new QFormLayout; + layout->addRow(tr("Brightness"), brightnessSlider); + layout->addRow(tr("Contrast"), contrastSlider); + layout->addRow(tr("Hue"), hueSlider); + layout->addRow(tr("Saturation"), saturationSlider); + + QPushButton *button = new QPushButton(tr("Close")); + layout->addRow(button); + + colorDialog = new QDialog(this); + colorDialog->setWindowTitle(tr("Color Options")); + colorDialog->setLayout(layout); + + connect(button, SIGNAL(clicked()), colorDialog, SLOT(close())); + } + colorDialog->show(); +} +#endif diff --git a/examples/multimediawidgets/player/player.h b/examples/multimediawidgets/player/player.h new file mode 100644 index 000000000..66f1b1679 --- /dev/null +++ b/examples/multimediawidgets/player/player.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLAYER_H +#define PLAYER_H + +#include "videowidget.h" + +#include <QWidget> +#include <QMediaPlayer> +#include <QMediaPlaylist> + +QT_BEGIN_NAMESPACE +class QAbstractItemView; +class QLabel; +class QMediaPlayer; +class QModelIndex; +class QPushButton; +class QSlider; +class QVideoProbe; +class QVideoWidget; +QT_END_NAMESPACE + +class PlaylistModel; +class HistogramWidget; + +class Player : public QWidget +{ + Q_OBJECT + +public: + Player(QWidget *parent = 0); + ~Player(); + +signals: + void fullScreenChanged(bool fullScreen); + +private slots: + void open(); + void durationChanged(qint64 duration); + void positionChanged(qint64 progress); + void metaDataChanged(); + + void previousClicked(); + + void seek(int seconds); + void jump(const QModelIndex &index); + void playlistPositionChanged(int); + + void statusChanged(QMediaPlayer::MediaStatus status); + void bufferingProgress(int progress); + void videoAvailableChanged(bool available); + + void displayErrorMessage(); + +#ifndef PLAYER_NO_COLOROPTIONS + void showColorDialog(); +#endif + void addToPlaylist(const QStringList &fileNames); + +private: + void setTrackInfo(const QString &info); + void setStatusInfo(const QString &info); + void handleCursor(QMediaPlayer::MediaStatus status); + void updateDurationInfo(qint64 currentInfo); + + QMediaPlayer *player; + QMediaPlaylist *playlist; + VideoWidget *videoWidget; + QLabel *coverLabel; + QSlider *slider; + QLabel *labelDuration; + QPushButton *fullScreenButton; +#ifndef PLAYER_NO_COLOROPTIONS + QPushButton *colorButton; + QDialog *colorDialog; +#endif + + QLabel *labelHistogram; + HistogramWidget *histogram; + QVideoProbe *probe; + + PlaylistModel *playlistModel; + QAbstractItemView *playlistView; + QString trackInfo; + QString statusInfo; + qint64 duration; +}; + +#endif // PLAYER_H diff --git a/examples/multimediawidgets/player/player.pro b/examples/multimediawidgets/player/player.pro new file mode 100644 index 000000000..067b31b11 --- /dev/null +++ b/examples/multimediawidgets/player/player.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +TARGET = player + +QT += network \ + xml \ + multimedia \ + multimediawidgets \ + widgets + +HEADERS = \ + player.h \ + playercontrols.h \ + playlistmodel.h \ + videowidget.h \ + histogramwidget.h +SOURCES = main.cpp \ + player.cpp \ + playercontrols.cpp \ + playlistmodel.cpp \ + videowidget.cpp \ + histogramwidget.cpp + +maemo* { + DEFINES += PLAYER_NO_COLOROPTIONS +} + +target.path = $$[QT_INSTALL_EXAMPLES]/multimediawidgets/player +INSTALLS += target diff --git a/examples/multimediawidgets/player/playercontrols.cpp b/examples/multimediawidgets/player/playercontrols.cpp new file mode 100644 index 000000000..1f18fc0cd --- /dev/null +++ b/examples/multimediawidgets/player/playercontrols.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "playercontrols.h" + +#include <QBoxLayout> +#include <QSlider> +#include <QStyle> +#include <QToolButton> +#include <QComboBox> + +PlayerControls::PlayerControls(QWidget *parent) + : QWidget(parent) + , playerState(QMediaPlayer::StoppedState) + , playerMuted(false) + , playButton(0) + , stopButton(0) + , nextButton(0) + , previousButton(0) + , muteButton(0) + , volumeSlider(0) + , rateBox(0) +{ + playButton = new QToolButton(this); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + + connect(playButton, SIGNAL(clicked()), this, SLOT(playClicked())); + + stopButton = new QToolButton(this); + stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop)); + stopButton->setEnabled(false); + + connect(stopButton, SIGNAL(clicked()), this, SIGNAL(stop())); + + nextButton = new QToolButton(this); + nextButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); + + connect(nextButton, SIGNAL(clicked()), this, SIGNAL(next())); + + previousButton = new QToolButton(this); + previousButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); + + connect(previousButton, SIGNAL(clicked()), this, SIGNAL(previous())); + + muteButton = new QToolButton(this); + muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume)); + + connect(muteButton, SIGNAL(clicked()), this, SLOT(muteClicked())); + + volumeSlider = new QSlider(Qt::Horizontal, this); + volumeSlider->setRange(0, 100); + + connect(volumeSlider, SIGNAL(sliderMoved(int)), this, SIGNAL(changeVolume(int))); + + rateBox = new QComboBox(this); + rateBox->addItem("0.5x", QVariant(0.5)); + rateBox->addItem("1.0x", QVariant(1.0)); + rateBox->addItem("2.0x", QVariant(2.0)); + rateBox->setCurrentIndex(1); + + connect(rateBox, SIGNAL(activated(int)), SLOT(updateRate())); + + QBoxLayout *layout = new QHBoxLayout; + layout->setMargin(0); + layout->addWidget(stopButton); + layout->addWidget(previousButton); + layout->addWidget(playButton); + layout->addWidget(nextButton); + layout->addWidget(muteButton); + layout->addWidget(volumeSlider); + layout->addWidget(rateBox); + setLayout(layout); +} + +QMediaPlayer::State PlayerControls::state() const +{ + return playerState; +} + +void PlayerControls::setState(QMediaPlayer::State state) +{ + if (state != playerState) { + playerState = state; + + switch (state) { + case QMediaPlayer::StoppedState: + stopButton->setEnabled(false); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + case QMediaPlayer::PlayingState: + stopButton->setEnabled(true); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); + break; + case QMediaPlayer::PausedState: + stopButton->setEnabled(true); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + } + } +} + +int PlayerControls::volume() const +{ + return volumeSlider ? volumeSlider->value() : 0; +} + +void PlayerControls::setVolume(int volume) +{ + if (volumeSlider) + volumeSlider->setValue(volume); +} + +bool PlayerControls::isMuted() const +{ + return playerMuted; +} + +void PlayerControls::setMuted(bool muted) +{ + if (muted != playerMuted) { + playerMuted = muted; + + muteButton->setIcon(style()->standardIcon(muted + ? QStyle::SP_MediaVolumeMuted + : QStyle::SP_MediaVolume)); + } +} + +void PlayerControls::playClicked() +{ + switch (playerState) { + case QMediaPlayer::StoppedState: + case QMediaPlayer::PausedState: + emit play(); + break; + case QMediaPlayer::PlayingState: + emit pause(); + break; + } +} + +void PlayerControls::muteClicked() +{ + emit changeMuting(!playerMuted); +} + +qreal PlayerControls::playbackRate() const +{ + return rateBox->itemData(rateBox->currentIndex()).toDouble(); +} + +void PlayerControls::setPlaybackRate(float rate) +{ + for (int i = 0; i < rateBox->count(); ++i) { + if (qFuzzyCompare(rate, float(rateBox->itemData(i).toDouble()))) { + rateBox->setCurrentIndex(i); + return; + } + } + + rateBox->addItem(QString("%1x").arg(rate), QVariant(rate)); + rateBox->setCurrentIndex(rateBox->count() - 1); +} + +void PlayerControls::updateRate() +{ + emit changeRate(playbackRate()); +} diff --git a/examples/multimediawidgets/player/playercontrols.h b/examples/multimediawidgets/player/playercontrols.h new file mode 100644 index 000000000..35ae30252 --- /dev/null +++ b/examples/multimediawidgets/player/playercontrols.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLAYERCONTROLS_H +#define PLAYERCONTROLS_H + +#include <QMediaPlayer> +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QAbstractButton; +class QAbstractSlider; +class QComboBox; +QT_END_NAMESPACE + +class PlayerControls : public QWidget +{ + Q_OBJECT + +public: + PlayerControls(QWidget *parent = 0); + + QMediaPlayer::State state() const; + int volume() const; + bool isMuted() const; + qreal playbackRate() const; + +public slots: + void setState(QMediaPlayer::State state); + void setVolume(int volume); + void setMuted(bool muted); + void setPlaybackRate(float rate); + +signals: + void play(); + void pause(); + void stop(); + void next(); + void previous(); + void changeVolume(int volume); + void changeMuting(bool muting); + void changeRate(qreal rate); + +private slots: + void playClicked(); + void muteClicked(); + void updateRate(); + +private: + QMediaPlayer::State playerState; + bool playerMuted; + QAbstractButton *playButton; + QAbstractButton *stopButton; + QAbstractButton *nextButton; + QAbstractButton *previousButton; + QAbstractButton *muteButton; + QAbstractSlider *volumeSlider; + QComboBox *rateBox; +}; + +#endif // PLAYERCONTROLS_H diff --git a/examples/multimediawidgets/player/playlistmodel.cpp b/examples/multimediawidgets/player/playlistmodel.cpp new file mode 100644 index 000000000..bf10153e3 --- /dev/null +++ b/examples/multimediawidgets/player/playlistmodel.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "playlistmodel.h" + +#include <QFileInfo> +#include <QUrl> +#include <QMediaPlaylist> + +PlaylistModel::PlaylistModel(QObject *parent) + : QAbstractItemModel(parent) + , m_playlist(0) +{ +} + +int PlaylistModel::rowCount(const QModelIndex &parent) const +{ + return m_playlist && !parent.isValid() ? m_playlist->mediaCount() : 0; +} + +int PlaylistModel::columnCount(const QModelIndex &parent) const +{ + return !parent.isValid() ? ColumnCount : 0; +} + +QModelIndex PlaylistModel::index(int row, int column, const QModelIndex &parent) const +{ + return m_playlist && !parent.isValid() + && row >= 0 && row < m_playlist->mediaCount() + && column >= 0 && column < ColumnCount + ? createIndex(row, column) + : QModelIndex(); +} + +QModelIndex PlaylistModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child); + + return QModelIndex(); +} + +QVariant PlaylistModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && role == Qt::DisplayRole) { + QVariant value = m_data[index]; + if (!value.isValid() && index.column() == Title) { + QUrl location = m_playlist->media(index.row()).canonicalUrl(); + return QFileInfo(location.path()).fileName(); + } + + return value; + } + return QVariant(); +} + +QMediaPlaylist *PlaylistModel::playlist() const +{ + return m_playlist; +} + +void PlaylistModel::setPlaylist(QMediaPlaylist *playlist) +{ + if (m_playlist) { + disconnect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int))); + disconnect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems())); + disconnect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int))); + disconnect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems())); + disconnect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int))); + } + + beginResetModel(); + m_playlist = playlist; + + if (m_playlist) { + connect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int))); + connect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems())); + connect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int))); + connect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems())); + connect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int))); + } + + endResetModel(); +} + +bool PlaylistModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + Q_UNUSED(role); + m_data[index] = value; + emit dataChanged(index, index); + return true; +} + +void PlaylistModel::beginInsertItems(int start, int end) +{ + m_data.clear(); + beginInsertRows(QModelIndex(), start, end); +} + +void PlaylistModel::endInsertItems() +{ + endInsertRows(); +} + +void PlaylistModel::beginRemoveItems(int start, int end) +{ + m_data.clear(); + beginRemoveRows(QModelIndex(), start, end); +} + +void PlaylistModel::endRemoveItems() +{ + endInsertRows(); +} + +void PlaylistModel::changeItems(int start, int end) +{ + m_data.clear(); + emit dataChanged(index(start,0), index(end,ColumnCount)); +} diff --git a/examples/multimediawidgets/player/playlistmodel.h b/examples/multimediawidgets/player/playlistmodel.h new file mode 100644 index 000000000..59d202818 --- /dev/null +++ b/examples/multimediawidgets/player/playlistmodel.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLAYLISTMODEL_H +#define PLAYLISTMODEL_H + +#include <QAbstractItemModel> + +QT_BEGIN_NAMESPACE +class QMediaPlaylist; +QT_END_NAMESPACE + +class PlaylistModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + enum Column + { + Title = 0, + ColumnCount + }; + + PlaylistModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + QMediaPlaylist *playlist() const; + void setPlaylist(QMediaPlaylist *playlist); + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole); + +private slots: + void beginInsertItems(int start, int end); + void endInsertItems(); + void beginRemoveItems(int start, int end); + void endRemoveItems(); + void changeItems(int start, int end); + +private: + QMediaPlaylist *m_playlist; + QMap<QModelIndex, QVariant> m_data; +}; + +#endif // PLAYLISTMODEL_H diff --git a/examples/multimediawidgets/player/videowidget.cpp b/examples/multimediawidgets/player/videowidget.cpp new file mode 100644 index 000000000..5e07bd398 --- /dev/null +++ b/examples/multimediawidgets/player/videowidget.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videowidget.h" + +#include <QKeyEvent> +#include <QMouseEvent> + +VideoWidget::VideoWidget(QWidget *parent) + : QVideoWidget(parent) +{ + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + + QPalette p = palette(); + p.setColor(QPalette::Window, Qt::black); + setPalette(p); + + setAttribute(Qt::WA_OpaquePaintEvent); +} + +void VideoWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape && isFullScreen()) { + setFullScreen(false); + event->accept(); + } else if (event->key() == Qt::Key_Enter && event->modifiers() & Qt::Key_Alt) { + setFullScreen(!isFullScreen()); + event->accept(); + } else { + QVideoWidget::keyPressEvent(event); + } +} + +void VideoWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + setFullScreen(!isFullScreen()); + event->accept(); +} + +void VideoWidget::mousePressEvent(QMouseEvent *event) +{ + QVideoWidget::mousePressEvent(event); +} + diff --git a/examples/multimediawidgets/player/videowidget.h b/examples/multimediawidgets/player/videowidget.h new file mode 100644 index 000000000..9a520e7ee --- /dev/null +++ b/examples/multimediawidgets/player/videowidget.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#include <QVideoWidget> + +class VideoWidget : public QVideoWidget +{ + Q_OBJECT + +public: + VideoWidget(QWidget *parent = 0); + +protected: + void keyPressEvent(QKeyEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); +}; + +#endif // VIDEOWIDGET_H |