/**************************************************************************** ** ** Copyright (C) 2013 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 #include #include #include #include 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(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(); 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