diff --git a/doc/index.docbook b/doc/index.docbook
index 1e25f45..233c130 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -1,1397 +1,1397 @@
Kaffeine">
]>
The &kaffeine; Handbook
Jürgen
Kofler
kaffeine@gmx.net
Christophe
Thommeret
hftom@free.fr
Mauro
Carvalho
Chehab
mchehab+kde@kernel.org
2004
2016
2017
The &kaffeine; Authors
&FDLNotice;
2017-11-26
&kaffeine; 2.0.14
Kaffeine is a Media Player by &kde;.
kaffeine
vlc
video
audio
mp3
dvd
atsc
dvb-t
dvb-c
dvb-s
dvb-t2
dvb-s2
isdb-t
tv
&kaffeine; Player
The Start Window
Like many other media players, &kaffeine; supports a wide range of video and audio formats
as well as playing audio and video from DVD and &CD;. Additionally, it supports live
Digital TV playback if your machine has a Digital Video Broadcast (DVB)
device plugged into it.
Once &kaffeine; starts, it presents a screen with the main functions in the middle,
and it’s possible to switch to other functions via either the menu bar or the left sidebar:
Start Window
Start Window
Play a File
Playing a video or audio file is as simple as clicking on the Play File
button. It will ask you to select the file to be played, and will begin playing it. Since &kaffeine;
uses LibVLC for the backend, it supports all the same file formats as VLC.
It also supports opening a list of files to create and manage playlists.
Play a File
Play a File
The Playlist Window
&kaffeine; supports multiple playlists. Choose the active one with the Playlist selector in
the left sidebar. You can easily drag some files or folders from the file browser and drop it on the playlist to enqueue
or drop it on the player window to create a new playlist. To change a playlist name edit it and confirm with Return.
Playlist Window
Playlist Window
You can find all playlist related functions in the Playlist item from the menu bar
and the context-menu (right-click on playlist).
Digital TV Player
Digital TV configuration
While the basic functionality is useful enough for someone who wants a simple, yet powerful
media player, the best feature in &kaffeine; is to use it as a &GUI; frontend to watch and record digital TV.
Since &kaffeine; version 2.0, the digital TV support uses libdvbv5 and
was extended to support new standards like DVB-T2 and ISDB-T. Extending its
support for newer digital TV standards is now simpler.
Also, since it uses the &Linux; DVB version 5 API, it supports frontends
capable of implementing multiple digital TV standards.
Setting the TV configuration on &kaffeine; is as simple as open the
Television item from the menu bar and select the
Configure Television... option. A pop up window
will open, allowing setting the parameters to be used:
TV Configuration - General Options
TV Configuration - General Options
General digital TV settings
The General Options menu allows setting the
device-independent settings.
The Recording folder sets the location where all TV
program records will be stored.
The Time shift folder is used in conjunction with the
pause button
() of the media player screen. When the button
is pressed, a time shift file will be stored at the location pointed by this
menu option.
The Begin margin and End margin
options are used to setup a sort of security margin
in order
to avoid losing the beginning and the end of a program, as the time stamps at
the program guide may not be precise. So, it actually starts recording a few
minutes before the Start time defined in the
Program Guide. The exact amount of time before is
defined via Begin margin. &kaffeine; extends the
record by the amount of time defined by End margin
after the end of the program.
The Naming style for recordings option is used to setup
how &kaffeine; will name a program. Several macros can be used to dynamically
change the name of the record:
%title - Title of the program, as seen at the
Program Guide and Recording Schedule
menus;
%day, %month, %year, %hour, %min, %sec - Fields from the
time stamp with represents the time when &kaffeine; starts recording a program;
%channel - Name of the channel that streamed the program.
The Action after recording finishes option is used to
setup an optional command to be executed when &kaffeine; stops recording a
program.
Clicking at the Update Scan Data over Internet option
makes &kaffeine; to check if a new channel scanning definition file is
present at
KDE's site.
&kaffeine; uses a file called scanfile.dvb to store a list of known
digital TV channels per Country and City. This file is kept in sync with
the contents of the
dtv-scan-tables tree, maintained
by LinuxTV community. For more details,
please see the
dtv-scan-tables wiki page.
When the button is clicked, &kaffeine; will download the latest version of the
channel definitions and store on a user-specific local data file, overriding
any contents of a previous one.
Please notice that, in order to use the newest definitions, it is
required to close the TV configuration dialog and reopen.
The Edit scanfile option allows
editing the file, which can be useful to add a new set of channels, while
the upstream file is not updated. If you need to use it, please consider
sending an update to
dtv-scan-tables
for others to also benefit from the new channel definitions.
The Use ISO 8859-1 charset instead of ISO 6937
option allows selecting the default to be used on MPEG-TS messages
that don't explicitly set a charset. If not set, it defaults to using
ISO-6937 encoding. If set, the default changes to ISO 8859-1.
The Create info files to accompany EPG recordings
option enables the creation of ancillary files for scheduled records
with the contents of the program guide for records made via the
Program guide.
Configuring digital TV sources
TV Device Configuration
TV Configuration
The Device tabs have the per-device setup. Usually
selecting the country and the city in the Source
combo box (or using one of the Autoscan sources) is enough for non-satellite
configurations.
The same happens for devices that support multiple TV standards. On those
devices, you need to setup the Source for each
TV standard:
Channel Configuration
Channel Configuration
The Tuner timeout specifies the amount of time the
channel scan will wait to get a signal lock. Usually, the default is
enough for most devices, but if the device is too slow to lock, such
value can be increased.
The Name specifies the name associated with source
that will appear selecting Television item from the menubar
and Channels option, for settings panel.
Satellite devices
The configuration for satellite devices (DVB-S, DVB-S2) are more complex,
as there are different satellite system arrangements that are possible.
Also, on satellite systems, it is usually up to the device to power up an
amplifier located at the satellite dish - called LNBf - via a DC voltage.
Also, as satellite systems use a wide bandwidth and accept signals using
different polarities, it is common to use a protocol - called DiSEqC - in
order to select a range of channels to be received.
The first step is to teach &kaffeine; about the satellite configuration
via the Configuration combo box:
Satellite device definitions
Satellite device definitions
The following values are possible:
DiSEqC Switch - The antenna cable is connected to
a DiSEqC switch or the LNBf requires DiSEqC commands to select a range
of channels. This is the most common setting. It allows having up to 4
satellites connected at the same time, each with its own dish. For each
satellite, you need to set the configuration for the LNBf at the dish
pointing to it.
USALS Rotor - The antenna cable is connected to
a single dish with a USALS Rotor, controlled via DiSEqC. Multiple satellites
can be configured, as the rotor will change the dish position when a different
satellite is chosen. You need to specify the position of the dish
(latitude, longitude).
Positions Rotor - The antenna cable is connected to
a single dish with a Rotor with a set of fixed positions, controlled via
DiSEqC. Multiple satellites can be configured, as the rotor will change the
dish position when a different satellite is chosen.
Disable DiSEqC - The antenna cable is connected
to a dish without any elements supporting DiSEqC. This setup is typically
used with multipoint bandstacked LNBf, where all channels are present at
the same time at the antenna cabling.
On a typical satellite system, the LNBf uses the power up voltage to select
between a lower voltage (13V) for vertical or circular right polarization and
a higher voltage (18V) for horizontal or circular left polarization.
However, due to cabling loss, sometimes the LNBf doesn't understand the
high voltage and several channels won't tune or will tune wrong. So, a few
devices offer an option to increase the voltage to a higher setting
(14V or 19V). This is enabled via the tri-state
Use Higher LNBf voltage option. Three values
are possible:
tri-state - Don't send a command to the device to
adjust the voltage level. That's the default.
unselected - Use normal values (13V/18V) for the
DC voltage. Only select it if the device supports adjusting the level.
selected - Use higher values (14V/19V) for the
DC voltage. Only select it if the device supports adjusting the level.
Configurations without a rotor
When either DiSEqC Switch or Disable DiSEqC
options are used, the first step is to set the satellite that
will be used as a signal source, via a combo box on the right. With a
DiSEqC switch, it is possible to select up to 4 sources.
Each with its own LNBf. After setting the source(s), for each source, click at
the corresponding LNBf Settings button to open a popup
window to select the LNBf type inside the dish that corresponds to the source:
LNBf definitions
LNBf definitions
Rotor configurations
When a rotor is used, there is just one LNBf which is shared with multiple
satellites. So, the next step is to select the LNBf type via the
LNB Settings dialog.
For USALS rotor, the positioning is done via satellite position (latitude,
longitude). So, just select the satellites that will be used via a combo box
and click at the Add Satellite button.
For positions rotor, the positioning is done via a preconfigured position
number. So, just select the satellite position at the number dialog on the
left and the satellite via a combo box on the right and click at the
Add Satellite button.
If a satellite was added by mistake, you can select the satellite and
click at the Remove Satellite button to remove it.
Digital TV channel setup
After clicking on the Ok button, the next step is to
scan for the digital channels, using the Television item
from the menubar and select Channels option, for
settings panel:
Scanning Channels
Scanning Channels
If more then one standard is supported, the Source
combo box will allow you to select the one that will be used to scan. Don't
forget to connect the device's antenna cable to match the standard that
will be used.
When &kaffeine; identifies a channel, it reads a MPEG-TS
table called Network Information Table (NIT), which contains
information about channels using different tuning parameters transmitted by
the same broadcaster. On certain networks, it is possible that some tuning
parameters to be stored on several NIT tables
(called other NITs
). This is more common on some cable and
satellite systems. By selecting Search transponders for other
Networks, &kaffeine; is instructed to wait and parse all other
NITs, which may make it to find more channels, at the cost
of taking a lot more time to complete the channel scan operation.
The channel scan operation is started by clicking on
Start Scan.
Once finished, the discovered channels will appear on the right. These channels can be copied
to the left side by clicking Add Filtered. It is possible to check the tuning parameters
for the channel in the left side by clicking on the Edit button.
Some parameters are adjustable in the window that pops up.
Edit Channel Settings
Edit Channel Settings
Once the channels are saved, watching TV is as simple as clicking on the Digital TV button in the main window:
Watching TV
Watching TV
Watching TV
&kaffeine; also allows you to click on the
button to pause it.
With this action, &kaffeine; will record the program and once the
button is pressed it will start the program from
the point it was paused, this is known as time shifting. There is also a
button
that allows you to quick record and save the program to disk.
Program Guide
Digital TV channels usually transmit a list of the current and future
attractions. This is called Electronic Program Guide - EPG.
The EPG data is captured when a channel's content is played.
To see the EPG, open the Television item
from the menubar and select the Program Guide option:
Program Guide
Program Guide
On some Countries, the EPG may be available in multiple languages. By
default, &kaffeine; shows any languages on EPG. If multiple languages
are available for a given EPG entry, and no explicit language content is
select, it will prefix the title, subtitle and description data with a 3
letter language code, as defined by ISO 639-2 specification.
The EPG Language option allows filtering just one
language. If enabled, the filter will also be applied to the On
Screen Display - OSD and to any new scheduled
recordings. It won't affect pre-existing scheduled recordings.
Besides clicking on the record button
when the live view is opened, &kaffeine; also allows recording a program
via the program guide, by clicking on the
Record Show at the
Program Guide window.
Recording Schedule
To see the programs that are scheduled to be recorded, open the
Television item from the menubar and select the
Recording Schedule option:
Recording Schedule
Recording Schedule
By clicking one the New button, it is possible
to directly define a time and duration for a program to be recorded.
In this case, it won't use the EPG definitions.
By selecting an existing program and clicking on the
Edit button, you may change the start time
and the record duration. You may also program it to be recorded
weekly or daily.
By selecting an existing program and clicking on the
Remove button, it will remove the program from
the recording schedule.
Copyright and License
Program copyright 2007-2017, The &kaffeine; Authors
Documentation copyright 2003-2005, Jürgen Kofler kaffeine@gmx.net,
Christophe Thommeret hftom@free.fr, Mauro Carvalho Chehab mchehab+kde@kernel.org
&underFDL;
&underGPL;
&documentation.index;
diff --git a/src/abstractmediawidget.h b/src/abstractmediawidget.h
index cb4cd54..4b803e7 100644
--- a/src/abstractmediawidget.h
+++ b/src/abstractmediawidget.h
@@ -1,177 +1,177 @@
/*
* abstractmediawidget.h
*
* Copyright (C) 2010-2012 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef ABSTRACTMEDIAWIDGET_H
#define ABSTRACTMEDIAWIDGET_H
#include
#include "mediawidget.h"
class AbstractMediaWidget : public QWidget
{
public:
explicit AbstractMediaWidget(QWidget *parent);
virtual ~AbstractMediaWidget() {};
void connectToMediaWidget(MediaWidget *mediaWidget_);
// zero-based numbering is used everywhere (e.g. first audio channel = 0)
MediaWidget::PlaybackStatus getPlaybackStatus() const { return playbackStatus; }
int getCurrentTime() const { return currentTime; } // milliseconds
int getTotalTime() const { return totalTime; } // milliseconds
bool isSeekable() const { return seekable; }
QMap getMetadata() const { return metadata; }
QStringList getAudioStreams() const { return audioStreams; }
int getCurrentAudioStream() const { return currentAudioStream; }
QStringList getSubtitles() const { return subtitles; }
int getCurrentSubtitle() const { return currentSubtitle; }
int getTitleCount() const { return titleCount; }
int getCurrentTitle() const { return currentTitle; }
int getChapterCount() const { return chapterCount; }
int getCurrentChapter() const { return currentChapter; }
int getAngleCount() const { return angleCount; }
int getCurrentAngle() const { return currentAngle; }
bool hasDvdMenu() const { return dvdMenu; }
QSize getVideoSize() const { return videoSize; }
virtual QStringList getAudioDevices() = 0;
virtual void setAudioDevice(QString device) = 0;
virtual void setMuted(bool muted) = 0;
virtual void setVolume(int volume) = 0; // [0 - 200]
virtual void setAspectRatio(MediaWidget::AspectRatio aspectRatio) = 0;
virtual void resizeToVideo(float scale) = 0;
- virtual void setDeinterlacing(bool deinterlacing) = 0;
+ virtual void setDeinterlacing(MediaWidget::DeinterlaceMode) = 0;
virtual void play(const MediaSource &source) = 0;
virtual void stop() = 0;
virtual void setPaused(bool paused) = 0;
virtual void seek(int time) = 0; // milliseconds
virtual void setCurrentAudioStream(int currentAudioStream) = 0;
virtual void setCurrentSubtitle(int currentSubtitle) = 0;
virtual void setExternalSubtitle(const QUrl &subtitleUrl) = 0;
virtual void setCurrentTitle(int currentTitle) = 0;
virtual void setCurrentChapter(int currentChapter) = 0;
virtual void setCurrentAngle(int currentAngle) = 0;
virtual bool jumpToPreviousChapter() = 0;
virtual bool jumpToNextChapter() = 0;
virtual void showDvdMenu() = 0;
enum PendingUpdate
{
PlaybackFinished = (1 << 0),
PlaybackStatus = (1 << 1),
CurrentTotalTime = (1 << 2),
Seekable = (1 << 3),
Metadata = (1 << 4),
AudioStreams = (1 << 5),
Subtitles = (1 << 6),
Titles = (1 << 7),
Chapters = (1 << 8),
Angles = (1 << 9),
DvdMenu = (1 << 10),
VideoSize = (1 << 11)
};
Q_DECLARE_FLAGS(PendingUpdates, PendingUpdate)
protected:
void addPendingUpdates(PendingUpdates pendingUpdatesToBeAdded); // thread-safe
virtual int updatePlaybackStatus() = 0;
virtual void updateCurrentTotalTime() = 0;
virtual void updateSeekable() = 0;
virtual void updateMetadata() = 0;
virtual void updateAudioStreams() = 0;
virtual void updateSubtitles() = 0;
virtual void updateTitles() = 0;
virtual void updateChapters() = 0;
virtual void updateAngles() = 0;
virtual void updateDvdMenu() = 0;
virtual void updateVideoSize() = 0;
MediaWidget::PlaybackStatus playbackStatus;
int currentTime;
int totalTime;
bool seekable;
QMap metadata;
QStringList audioStreams;
int currentAudioStream;
QStringList subtitles;
int currentSubtitle;
int titleCount;
int currentTitle;
int chapterCount;
int currentChapter;
int angleCount;
int currentAngle;
bool dvdMenu;
QSize videoSize;
private:
void customEvent(QEvent *event);
MediaWidget *mediaWidget;
QAtomicInt pendingUpdates;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMediaWidget::PendingUpdates)
class DummyMediaWidget : public AbstractMediaWidget
{
public:
explicit DummyMediaWidget(QWidget *parent): AbstractMediaWidget(parent) {};
~DummyMediaWidget() {};
QStringList getAudioDevices() { QStringList empty; return empty; };
void setAudioDevice(QString) {};
void setMuted(bool) {};
void setVolume(int) {}; // [0 - 200]
void setAspectRatio(MediaWidget::AspectRatio) {};
void resizeToVideo(float) {};
- void setDeinterlacing(bool) {};
+ void setDeinterlacing(MediaWidget::DeinterlaceMode) {};
void play(const MediaSource &) {};
void stop() {};
void setPaused(bool) {};
void seek(int) {}; // milliseconds
void setCurrentAudioStream(int) {};
void setCurrentSubtitle(int) {};
void setExternalSubtitle(const QUrl &) {};
void setCurrentTitle(int) {};
void setCurrentChapter(int) {};
void setCurrentAngle(int) {};
bool jumpToPreviousChapter() { return false; };
bool jumpToNextChapter() { return false; }
void showDvdMenu() {};
int updatePlaybackStatus() { return true; };
void updateCurrentTotalTime() {};
void updateSeekable() {};
void updateMetadata() {};
void updateAudioDevices() {};
void updateAudioStreams() {};
void updateSubtitles() {};
void updateTitles() {};
void updateChapters() {};
void updateAngles() {};
void updateDvdMenu() {};
void updateVideoSize() {};
};
#endif /* ABSTRACTMEDIAWIDGET_H */
diff --git a/src/backend-mplayer/mplayermediawidget.cpp b/src/backend-mplayer/mplayermediawidget.cpp
index b4af9d2..3c26780 100644
--- a/src/backend-mplayer/mplayermediawidget.cpp
+++ b/src/backend-mplayer/mplayermediawidget.cpp
@@ -1,629 +1,626 @@
/*
* mplayermediawidget.cpp
*
* Copyright (C) 2010-2011 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include
#include
#include "mplayermediawidget.h"
#include "mplayervideowidget.h"
MPlayerMediaWidget::MPlayerMediaWidget(QWidget *parent) : AbstractMediaWidget(parent),
muted(false), volume(0), aspectRatio(MediaWidget::AspectRatioAuto), deinterlacing(false),
timerId(0), videoWidth(0), videoHeight(0), videoAspectRatio(1)
{
videoWidget = new MPlayerVideoWidget(this);
standardError.open(stderr, QIODevice::WriteOnly);
connect(&process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(error(QProcess::ProcessError)));
connect(&process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
connect(&process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));
process.start(QString("mplayer -idle -osdlevel 0 -quiet -slave -softvol -vf yadif "
"-volume 0 -wid %1").arg(videoWidget->winId()));
}
MPlayerMediaWidget::~MPlayerMediaWidget()
{
sendCommand(Quit);
process.waitForFinished(10000);
}
AbstractMediaWidget *MPlayerMediaWidget::createMPlayerMediaWidget(QWidget *parent)
{
return new MPlayerMediaWidget(parent);
}
void MPlayerMediaWidget::setMuted(bool muted_)
{
muted = muted_;
sendCommand(SetVolume);
}
void MPlayerMediaWidget::setVolume(int volume_)
{
volume = volume_;
sendCommand(SetVolume);
}
void MPlayerMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio_)
{
aspectRatio = aspectRatio_;
updateVideoWidgetGeometry();
}
-void MPlayerMediaWidget::setDeinterlacing(bool deinterlacing_)
+void MPlayerMediaWidget::setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing);
+
{
deinterlacing = deinterlacing_;
sendCommand(SetDeinterlacing);
}
void MPlayerMediaWidget::play(const MediaSource &source)
{
resetState();
QByteArray url = source.getUrl().toEncoded();
switch (source.getType()) {
case MediaSource::Url:
if (url.endsWith(".iso")) {
// FIXME use dvd://, dvdnav:// ?
updateDvdMenu(true);
}
if (source.getUrl().isLocalFile()) {
// mplayer can't deal with urls like "file:///tmp/te%20st.m2t"
url = QFile::encodeName(source.getUrl().toLocalFile());
url.replace(' ', "\\ ");
}
break;
case MediaSource::AudioCd:
if (url.size() >= 7) {
// e.g. cdda:////dev/sr0
url.replace(0, 5, "cdda:/");
} else {
url = "cdda://";
}
break;
case MediaSource::VideoCd:
if (url.size() >= 7) {
// e.g. vcd:////dev/sr0
url.replace(0, 5, "vcd:/");
} else {
url = "vcd://";
}
break;
case MediaSource::Dvd:
if (url.size() >= 7) {
// e.g. dvdnav:////dev/sr0
url.replace(0, 5, "dvdnav:/");
} else {
url = "dvdnav://";
}
updateDvdMenu(true);
break;
case MediaSource::Dvb:
if (source.getUrl().isLocalFile()) {
// mplayer can't deal with urls like "file:///tmp/te%20st.m2t"
url = QFile::encodeName(source.getUrl().toLocalFile());
url.replace(' ', "\\ ");
}
break;
}
updatePlaybackStatus(MediaWidget::Playing);
updateSeekable(true);
process.write("loadfile " + url + '\n');
process.write("pausing_keep_force get_property path\n");
sendCommand(SetDeinterlacing);
sendCommand(SetVolume);
timerId = startTimer(500);
}
void MPlayerMediaWidget::stop()
{
resetState();
sendCommand(Stop);
}
void MPlayerMediaWidget::setPaused(bool paused)
{
switch (getPlaybackStatus()) {
case MediaWidget::Idle:
break;
case MediaWidget::Playing:
if (paused) {
updatePlaybackStatus(MediaWidget::Paused);
sendCommand(TogglePause);
}
break;
case MediaWidget::Paused:
if (!paused) {
updatePlaybackStatus(MediaWidget::Playing);
sendCommand(TogglePause);
}
break;
}
}
void MPlayerMediaWidget::seek(int time)
{
process.write("pausing_keep_force set_property time_pos " +
QByteArray::number(float(time) / 1000) + '\n');
}
void MPlayerMediaWidget::setCurrentAudioStream(int currentAudioStream)
{
if ((currentAudioStream >= 0) && (currentAudioStream < audioIds.size())) {
process.write("pausing_keep_force set_property switch_audio " +
QByteArray::number(audioIds.at(currentAudioStream)) +
"\npausing_keep_force get_property switch_audio\n");
}
}
void MPlayerMediaWidget::setCurrentSubtitle(int currentSubtitle)
{
process.write("pausing_keep_force set_property sub " +
QByteArray::number(currentSubtitle) +
"\npausing_keep_force get_property sub\n");
}
void MPlayerMediaWidget::setExternalSubtitle(const QUrl &subtitleUrl)
{
// FIXME
Q_UNUSED(subtitleUrl)
}
void MPlayerMediaWidget::setCurrentTitle(int currentTitle)
{
process.write("pausing_keep_force set_property switch_title " +
QByteArray::number(currentTitle) +
"\npausing_keep_force get_property switch_title\n"
"pausing_keep_force get_property chapter\n");
}
void MPlayerMediaWidget::setCurrentChapter(int currentChapter)
{
process.write("pausing_keep_force set_property chapter " +
QByteArray::number(currentChapter) +
"\npausing_keep_force get_property switch_title\n"
"pausing_keep_force get_property chapter\n");
}
void MPlayerMediaWidget::setCurrentAngle(int currentAngle)
{
process.write("pausing_keep_force set_property switch_angle " +
QByteArray::number(currentAngle) + '\n');
}
bool MPlayerMediaWidget::jumpToPreviousChapter()
{
if ((getCurrentChapter() - 1) >= 0) {
setCurrentChapter(getCurrentChapter() - 1);
return true;
}
if ((getCurrentTitle() - 1) >= 0) {
setCurrentTitle(getCurrentTitle() - 1);
return true;
}
return false;
}
bool MPlayerMediaWidget::jumpToNextChapter()
{
if ((getCurrentChapter() + 1) < getChapterCount()) {
setCurrentChapter(getCurrentChapter() + 1);
return true;
}
if ((getCurrentTitle() + 1) < getTitleCount()) {
setCurrentTitle(getCurrentTitle() + 1);
return true;
}
return false;
}
void MPlayerMediaWidget::showDvdMenu()
{
sendCommand(ShowDvdMenu);
}
void MPlayerMediaWidget::error(QProcess::ProcessError error)
{
Q_UNUSED(error)
KMessageBox::queuedMessageBox(this, KMessageBox::Error,
i18n("Cannot start mplayer process."));
}
void MPlayerMediaWidget::readStandardOutput()
{
QByteArray data = process.readAllStandardOutput();
standardError.write(data); // forward
standardError.flush();
if ((data == "\n") || (data.indexOf("\n\n") >= 0)) {
process.write("pausing_keep_force get_property path\n");
}
bool videoPropertiesChanged = false;
QStringList audioStreams = getAudioStreams();
bool audioStreamsChanged = false;
QStringList subtitles = getSubtitles();
bool subtitlesChanged = false;
foreach (const QByteArray &line, data.split('\n')) {
if (line.startsWith("VO: ")) {
videoPropertiesChanged = true;
continue;
}
if (line.startsWith("audio stream: ")) {
int begin = 14;
int end = line.indexOf(' ', begin);
if (end < 0) {
end = line.size();
}
int audioStreamIndex = line.mid(begin, end - begin).toInt();
while (audioStreams.size() < audioStreamIndex) {
audioStreams.append(QString::number(audioStreams.size() + 1));
}
while (audioIds.size() < audioStreamIndex) {
audioIds.append(-1);
}
audioStreams.erase(audioStreams.begin() + audioStreamIndex,
audioStreams.end());
audioIds.erase(audioIds.begin() + audioStreamIndex, audioIds.end());
QString audioStream;
begin = line.indexOf("language: ");
if (begin >= 0) {
begin += 10;
end = line.indexOf(' ', begin);
if (end < 0) {
end = line.size();
}
audioStream = line.mid(begin, end - begin);
}
if (audioStream.isEmpty()) {
audioStream = QString::number(audioStreams.size() + 1);
}
int audioId = -1;
begin = line.indexOf("aid: ");
if (begin >= 0) {
begin += 5;
end = line.indexOf('.', begin);
if (end < 0) {
end = line.size();
}
audioId = line.mid(begin, end - begin).toInt();
}
audioStreams.append(audioStream);
audioIds.append(audioId);
audioStreamsChanged = true;
continue;
}
if (line.startsWith("subtitle ")) {
int begin = line.indexOf("( sid ): ");
if (begin < 0) {
continue;
}
begin += 9;
int end = line.indexOf(' ', begin);
if (end < 0) {
end = line.size();
}
int subtitleIndex = line.mid(begin, end - begin).toInt();
while (subtitles.size() < subtitleIndex) {
subtitles.append(QString::number(subtitles.size() + 1));
}
subtitles.erase(subtitles.begin() + subtitleIndex, subtitles.end());
QString subtitle;
begin = line.indexOf("language: ");
if (begin >= 0) {
begin += 10;
end = line.indexOf(' ', begin);
if (end < 0) {
end = line.size();
}
subtitle = line.mid(begin, end - begin);
}
if (subtitle.isEmpty()) {
subtitle = QString::number(subtitles.size() + 1);
}
subtitles.append(subtitle);
subtitlesChanged = true;
continue;
}
if (line == "ANS_path=(null)") {
switch (getPlaybackStatus()) {
case MediaWidget::Idle:
break;
case MediaWidget::Playing:
case MediaWidget::Paused:
playbackFinished();
break;
}
resetState();
continue;
}
if (line.startsWith("ANS_length=")) {
int totalTime = (line.mid(11).toFloat() * 1000 + 0.5);
updateCurrentTotalTime(getCurrentTime(), totalTime);
continue;
}
if (line.startsWith("ANS_time_pos=")) {
int currentTime = (line.mid(13).toFloat() * 1000 + 0.5);
updateCurrentTotalTime(currentTime, getTotalTime());
continue;
}
if (line.startsWith("ANS_width=")) {
videoWidth = line.mid(10).toInt();
if (videoWidth < 0) {
videoWidth = 0;
}
continue;
}
if (line.startsWith("ANS_height=")) {
videoHeight = line.mid(11).toInt();
if (videoHeight < 0) {
videoHeight = 0;
}
continue;
}
if (line.startsWith("ANS_aspect=")) {
videoAspectRatio = line.mid(11).toFloat();
if ((videoAspectRatio > 0.01) && (videoAspectRatio < 100)) {
// ok
} else {
videoAspectRatio = (videoWidth / float(videoHeight));
if ((videoAspectRatio > 0.01) && (videoAspectRatio < 100)) {
// ok
} else {
videoAspectRatio = 1;
}
}
updateVideoWidgetGeometry();
continue;
}
if (line.startsWith("ANS_switch_audio=")) {
int audioId = line.mid(17).toInt();
updateCurrentAudioStream(audioIds.indexOf(audioId));
continue;
}
if (line.startsWith("ANS_sub=")) {
int currentSubtitle = line.mid(8).toInt();
updateCurrentSubtitle(currentSubtitle);
continue;
}
}
if (videoPropertiesChanged) {
process.write("pausing_keep_force get_property width\n"
"pausing_keep_force get_property height\n"
"pausing_keep_force get_property aspect\n");
}
if (audioStreamsChanged) {
updateAudioStreams(audioStreams);
process.write("pausing_keep_force get_property switch_audio\n");
}
if (subtitlesChanged) {
updateSubtitles(subtitles);
process.write("pausing_keep_force get_property sub\n");
}
}
void MPlayerMediaWidget::readStandardError()
{
QByteArray data = process.readAllStandardError();
standardError.write(data); // forward
standardError.flush();
}
void MPlayerMediaWidget::mouseMoved(int x, int y)
{
process.write("set_mouse_pos " + QByteArray::number(x) + ' ' + QByteArray::number(y) +
'\n');
}
void MPlayerMediaWidget::mouseClicked()
{
process.write("dvdnav mouse\n");
}
void MPlayerMediaWidget::resetState()
{
resetBaseState();
if (timerId != 0) {
killTimer(timerId);
timerId = 0;
}
audioIds.clear();
videoWidth = 0;
videoHeight = 0;
videoAspectRatio = 1;
updateVideoWidgetGeometry();
}
void MPlayerMediaWidget::resizeEvent(QResizeEvent *event)
{
updateVideoWidgetGeometry();
AbstractMediaWidget::resizeEvent(event);
}
void MPlayerMediaWidget::sendCommand(Command command)
{
switch (command) {
case SetDeinterlacing:
if (getPlaybackStatus() == MediaWidget::Idle) {
// only works if media is loaded
break;
}
- if (deinterlacing) {
- process.write("pausing_keep_force set_property deinterlace 1\n");
- } else {
- process.write("pausing_keep_force set_property deinterlace 0\n");
- }
+ process.write("pausing_keep_force set_property deinterlace %1\n", deinterlacing);
break;
case SetVolume: {
if (getPlaybackStatus() == MediaWidget::Idle) {
// only works if media is loaded
break;
}
int realVolume = volume;
if (muted) {
realVolume = 0;
}
process.write("pausing_keep_force set_property volume " +
QByteArray::number(realVolume) + '\n');
break;
}
case ShowDvdMenu:
process.write("dvdnav menu\n");
break;
case Stop:
process.write("stop\n");
break;
case TogglePause:
process.write("pause\n");
break;
case Quit:
process.write("quit\n");
break;
}
}
void MPlayerMediaWidget::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event)
process.write("pausing_keep_force get_property length\n"
"pausing_keep_force get_property time_pos\n");
}
void MPlayerMediaWidget::updateVideoWidgetGeometry()
{
float effectiveAspectRatio = videoAspectRatio;
switch (aspectRatio) {
case MediaWidget::AspectRatioAuto:
break;
case MediaWidget::AspectRatio1_1:
effectiveAspectRatio = 1;
break;
case MediaWidget::AspectRatio4_3:
effectiveAspectRatio = (4.0 / 3.0);
break;
case MediaWidget::AspectRatio5_4:
effectiveAspectRatio = (5.0 / 4.0);
break;
case MediaWidget::AspectRatio16_9:
effectiveAspectRatio = (16.0 / 9.0);
break;
case MediaWidget::AspectRatio16_10:
effectiveAspectRatio = (16.0 / 10.0);
break;
case MediaWidget::AspectRatio221_100:
effectiveAspectRatio = (221.0 / 100.0);
break;
case MediaWidget::AspectRatio235_100:
effectiveAspectRatio = (235.0 / 100.0);
break;
case MediaWidget::AspectRatio239_100:
effectiveAspectRatio = (239.0 / 100.0);
break;
}
QRect geometry(QPoint(0, 0), size());
if (getPlaybackStatus() == MediaWidget::Idle) {
geometry.setSize(QSize(0, 0));
} else if (effectiveAspectRatio > 0) {
int newWidth = (geometry.height() * effectiveAspectRatio + 0.5);
if (newWidth <= geometry.width()) {
geometry.setX((geometry.width() - newWidth) / 2);
geometry.setWidth(newWidth);
} else {
int newHeight = (geometry.width() / effectiveAspectRatio + 0.5);
geometry.setY((geometry.height() - newHeight) / 2);
geometry.setHeight(newHeight);
}
}
if (videoWidget->geometry() != geometry) {
videoWidget->setGeometry(geometry);
}
}
diff --git a/src/backend-mplayer/mplayermediawidget.h b/src/backend-mplayer/mplayermediawidget.h
index fc27c8a..f397b81 100644
--- a/src/backend-mplayer/mplayermediawidget.h
+++ b/src/backend-mplayer/mplayermediawidget.h
@@ -1,97 +1,97 @@
/*
* mplayermediawidget.h
*
* Copyright (C) 2010-2011 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYERMEDIAWIDGET_H
#define MPLAYERMEDIAWIDGET_H
#include
#include
#include "../abstractmediawidget.h"
class MPlayerMediaWidget : public AbstractMediaWidget
{
Q_OBJECT
private:
explicit MPlayerMediaWidget(QWidget *parent);
public:
~MPlayerMediaWidget();
// returns NULL if init fails
static AbstractMediaWidget *createMPlayerMediaWidget(QWidget *parent);
void setMuted(bool muted);
void setVolume(int volume); // [0 - 200]
void setAspectRatio(MediaWidget::AspectRatio aspectRatio);
- void setDeinterlacing(bool deinterlacing);
+ void setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing);
void play(const MediaSource &source);
void stop();
void setPaused(bool paused);
void seek(int time); // milliseconds
void setCurrentAudioStream(int currentAudioStream);
void setCurrentSubtitle(int currentSubtitle);
void setExternalSubtitle(const QUrl &subtitleUrl);
void setCurrentTitle(int currentTitle);
void setCurrentChapter(int currentChapter);
void setCurrentAngle(int currentAngle);
bool jumpToPreviousChapter();
bool jumpToNextChapter();
void showDvdMenu();
void mouseMoved(int x, int y);
void mouseClicked();
private slots:
void error(QProcess::ProcessError error);
void readStandardOutput();
void readStandardError();
private:
enum Command
{
SetDeinterlacing,
SetVolume,
ShowDvdMenu,
Stop,
TogglePause,
Quit
};
void resetState();
void resizeEvent(QResizeEvent *event);
void sendCommand(Command command);
void timerEvent(QTimerEvent *event);
void updateVideoWidgetGeometry();
QWidget *videoWidget;
QFile standardError;
QProcess process;
bool muted;
int volume;
MediaWidget::AspectRatio aspectRatio;
- bool deinterlacing;
+ MediaWidget::DeinterlaceMode deinterlacing;
int timerId;
QList audioIds;
int videoWidth;
int videoHeight;
float videoAspectRatio;
};
#endif /* MPLAYERMEDIAWIDGET_H */
diff --git a/src/backend-vlc/vlcmediawidget.cpp b/src/backend-vlc/vlcmediawidget.cpp
index 12dcebe..ee04e8a 100644
--- a/src/backend-vlc/vlcmediawidget.cpp
+++ b/src/backend-vlc/vlcmediawidget.cpp
@@ -1,709 +1,740 @@
/*
* vlcmediawidget.cpp
*
* Copyright (C) 2010-2012 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../log.h"
#include
#include
#include
#include
#include
#include
#include
#include "../configuration.h"
#include "vlcmediawidget.h"
VlcMediaWidget::VlcMediaWidget(QWidget *parent) : AbstractMediaWidget(parent), vlcInstance(NULL),
vlcMediaPlayer(NULL), playingDvd(false)
{
}
bool VlcMediaWidget::init()
{
QString args = Configuration::instance()->getLibVlcArguments();
QStringList argList;
int argc = 0, size;
argList = args.split(' ', QString::SkipEmptyParts);
size = argList.size();
const char **argv = new const char *[size];
QVector str(size);
for (int i = 0; i < size; i++) {
str[i] = argList.at(i).toUtf8();
argv[argc++] = str[i];
}
vlcInstance = libvlc_new(argc, argv);
if (!vlcInstance) {
qCWarning(logMediaWidget, "libVLC: failed to use extra args: %s", qPrintable(args));
argc = 0;
vlcInstance = libvlc_new(0, NULL);
if (vlcInstance)
qCInfo(logMediaWidget, "Using libVLC without arguments");
}
if (vlcInstance == NULL) {
qFatal("Cannot create vlc instance %s", qPrintable(libvlc_errmsg()));
delete argv;
return false;
}
if (argc) {
QString log = "Using libVLC with args:";
for (int i = 0; i < argc; i++)
log += " " + QLatin1String(argv[i]);
qCDebug(logVlc, "%s", qPrintable(log));
}
delete argv;
vlcMediaPlayer = libvlc_media_player_new(vlcInstance);
if (vlcMediaPlayer == NULL) {
qFatal("Cannot create vlc media player %s", qPrintable(libvlc_errmsg()));
return false;
}
libvlc_event_manager_t *eventManager = libvlc_media_player_event_manager(vlcMediaPlayer);
libvlc_event_e eventTypes[] = { libvlc_MediaPlayerEncounteredError,
libvlc_MediaPlayerEndReached, libvlc_MediaPlayerLengthChanged,
libvlc_MediaPlayerSeekableChanged, libvlc_MediaPlayerStopped,
#if LIBVLC_VERSION_MAJOR > 2
libvlc_MediaPlayerESAdded, libvlc_MediaPlayerESDeleted,
#endif
libvlc_MediaPlayerTimeChanged };
for (uint i = 0; i < (sizeof(eventTypes) / sizeof(eventTypes[0])); ++i) {
if (libvlc_event_attach(eventManager, eventTypes[i], vlcEventHandler, this) != 0) {
qCCritical(logMediaWidget, "Cannot attach event handler %s", qPrintable(eventTypes[i]));
return false;
}
}
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(hideMouse()));
libvlc_media_player_set_xwindow(vlcMediaPlayer, quint32(winId()));
setAttribute(Qt::WA_NativeWindow);
libvlc_audio_set_mute(vlcMediaPlayer, false);
// This is broken on qt5: the kernel/qwidget.cpp tries to repaint
// on a wrong place, causing this warning:
// QWidget::paintEngine: Should no longer be called
// setAttribute(Qt::WA_PaintOnScreen);
return true;
}
VlcMediaWidget::~VlcMediaWidget()
{
if (vlcMediaPlayer != NULL) {
libvlc_media_player_release(vlcMediaPlayer);
}
if (vlcInstance != NULL) {
libvlc_release(vlcInstance);
}
}
VlcMediaWidget *VlcMediaWidget::createVlcMediaWidget(QWidget *parent)
{
QScopedPointer vlcMediaWidget(new VlcMediaWidget(parent));
if (!vlcMediaWidget->init()) {
return NULL;
}
return vlcMediaWidget.take();
}
QStringList VlcMediaWidget::getAudioDevices()
{
libvlc_audio_output_device_t *vlcAudioOutput, *i;
QStringList audioDevices;
// Get audio device list
vlcAudioOutput = libvlc_audio_output_device_enum(vlcMediaPlayer);
if (!vlcAudioOutput)
return audioDevices;
for (i = vlcAudioOutput; i != NULL; i = i->p_next) {
QString device = QString::fromUtf8(i->psz_description);
audioDevices.append(device);
}
libvlc_audio_output_device_list_release(vlcAudioOutput);
return audioDevices;
}
void VlcMediaWidget::setAudioDevice(QString device)
{
libvlc_audio_output_device_t *vlcAudioOutput, *i;
vlcAudioOutput = libvlc_audio_output_device_enum(vlcMediaPlayer);
if (!vlcAudioOutput)
return;
for (i = vlcAudioOutput; i != NULL; i = i->p_next) {
if (device.compare(QString::fromUtf8(i->psz_description)))
continue;
qCDebug(logVlc, "Setting audio output to: %s", qPrintable(i->psz_device));
libvlc_audio_output_device_set(vlcMediaPlayer, NULL, i->psz_device);
}
libvlc_audio_output_device_list_release(vlcAudioOutput);
}
void VlcMediaWidget::setMuted(bool muted)
{
libvlc_audio_set_mute(vlcMediaPlayer, muted);
}
void VlcMediaWidget::setVolume(int volume)
{
// 0 <= volume <= 200
if (libvlc_audio_set_volume(vlcMediaPlayer, volume) != 0) {
qCWarning(logMediaWidget, "cannot set volume %i", volume);
}
}
void VlcMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
{
const char *vlcAspectRatio = "";
switch (aspectRatio) {
case MediaWidget::AspectRatioAuto:
break;
case MediaWidget::AspectRatio1_1:
vlcAspectRatio = "1:1";
break;
case MediaWidget::AspectRatio4_3:
vlcAspectRatio = "4:3";
break;
case MediaWidget::AspectRatio5_4:
vlcAspectRatio = "5:4";
break;
case MediaWidget::AspectRatio16_9:
vlcAspectRatio = "16:9";
break;
case MediaWidget::AspectRatio16_10:
vlcAspectRatio = "16:10";
break;
case MediaWidget::AspectRatio221_100:
vlcAspectRatio = "221:100";
break;
case MediaWidget::AspectRatio235_100:
vlcAspectRatio = "235:100";
break;
case MediaWidget::AspectRatio239_100:
vlcAspectRatio = "239:100";
break;
}
libvlc_video_set_aspect_ratio(vlcMediaPlayer, vlcAspectRatio);
}
void VlcMediaWidget::resizeToVideo(float resizeFactor)
{
qCDebug(logMediaWidget, "video resized to %.1f", resizeFactor);
libvlc_video_set_scale(vlcMediaPlayer, resizeFactor);
}
-void VlcMediaWidget::setDeinterlacing(bool deinterlacing)
+void VlcMediaWidget::setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing)
{
- // "", "blend", "bob", "discard", "ivtc", "linear",
- // "mean", "phosphor", "x", "yadif", "yadif2x"
- const char *vlcDeinterlaceMode = "";
+ const char *vlcDeinterlaceMode;
- if (deinterlacing) {
+ switch (deinterlacing) {
+ case MediaWidget::DeinterlaceDiscard:
+ vlcDeinterlaceMode = "discard";
+ break;
+ case MediaWidget::DeinterlaceBob:
+ vlcDeinterlaceMode = "bob";
+ break;
+ case MediaWidget::DeinterlaceLinear:
+ vlcDeinterlaceMode = "linear";
+ break;
+ case MediaWidget::DeinterlaceYadif:
vlcDeinterlaceMode = "yadif";
+ break;
+ case MediaWidget::DeinterlaceYadif2x:
+ vlcDeinterlaceMode = "yadif2x";
+ break;
+ case MediaWidget::DeinterlacePhosphor:
+ vlcDeinterlaceMode = "phosphor";
+ break;
+ case MediaWidget::DeinterlaceX:
+ vlcDeinterlaceMode = "x";
+ break;
+ case MediaWidget::DeinterlaceMean:
+ vlcDeinterlaceMode = "mean";
+ break;
+ case MediaWidget::DeinterlaceBlend:
+ vlcDeinterlaceMode = "blend";
+ break;
+ case MediaWidget::DeinterlaceIvtc:
+ vlcDeinterlaceMode = "ivtc";
+ break;
+ case MediaWidget::DeinterlaceDisabled:
+ default:
+ vlcDeinterlaceMode = NULL;
}
+
libvlc_video_set_deinterlace(vlcMediaPlayer, vlcDeinterlaceMode);
}
void VlcMediaWidget::play(const MediaSource &source)
{
addPendingUpdates(PlaybackStatus | DvdMenu);
QByteArray url = source.getUrl().toEncoded();
playingDvd = false;
switch (source.getType()) {
case MediaSource::Url:
if (url.endsWith(".iso")) {
playingDvd = true;
}
break;
case MediaSource::AudioCd:
if (url.size() >= 7) {
url.replace(0, 4, "cdda");
} else {
url = "cdda://";
}
break;
case MediaSource::VideoCd:
if (url.size() >= 7) {
url.replace(0, 4, "vcd");
} else {
url = "vcd://";
}
break;
case MediaSource::Dvd:
if (url.size() >= 7) {
url.replace(0, 4, "dvd");
} else {
url = "dvd://";
}
playingDvd = true;
break;
case MediaSource::Dvb:
break;
}
libvlc_media_t *vlcMedia = libvlc_media_new_location(vlcInstance, url.constData());
if (vlcMedia == NULL) {
libvlc_media_player_stop(vlcMediaPlayer);
qCWarning(logMediaWidget, "Cannot create media %s", qPrintable(source.getUrl().toDisplayString()));
return;
}
libvlc_event_manager_t *eventManager = libvlc_media_event_manager(vlcMedia);
libvlc_event_e eventTypes[] = { libvlc_MediaMetaChanged };
for (uint i = 0; i < (sizeof(eventTypes) / sizeof(eventTypes[0])); ++i) {
if (libvlc_event_attach(eventManager, eventTypes[i], vlcEventHandler, this) != 0) {
qCWarning(logMediaWidget, "Cannot attach event handler %s", qPrintable(eventTypes[i]));
}
}
libvlc_media_player_set_media(vlcMediaPlayer, vlcMedia);
libvlc_media_release(vlcMedia);
// FIXME! subtitleUrl is only available for MediaSourceUrl private class
// if (source.subtitleUrl.isValid())
// setExternalSubtitle(source.subtitleUrl);
if (libvlc_media_player_play(vlcMediaPlayer) != 0) {
qCWarning(logMediaWidget, "Cannot play media %s", qPrintable(source.getUrl().toDisplayString()));
}
setCursor(Qt::BlankCursor);
setCursor(Qt::ArrowCursor);
timer->start(1000);
setMouseTracking(true);
}
void VlcMediaWidget::stop()
{
libvlc_media_player_stop(vlcMediaPlayer);
timer->stop();
setCursor(Qt::BlankCursor);
setCursor(Qt::ArrowCursor);
addPendingUpdates(PlaybackStatus);
}
void VlcMediaWidget::setPaused(bool paused)
{
isPaused = paused;
libvlc_media_player_set_pause(vlcMediaPlayer, paused);
// we don't monitor playing / buffering / paused state changes
addPendingUpdates(PlaybackStatus);
}
void VlcMediaWidget::seek(int time)
{
if (!seekable)
return;
libvlc_media_player_set_time(vlcMediaPlayer, time);
}
void VlcMediaWidget::setCurrentAudioStream(int currentAudioStream)
{
// skip the 'deactivate' audio channel
libvlc_audio_set_track(vlcMediaPlayer, currentAudioStream + 1);
}
void VlcMediaWidget::setCurrentSubtitle(int currentSubtitle)
{
int requestedSubtitle = -1;
QMap::const_iterator i = subtitleId.constBegin();
while (i != subtitleId.constEnd()) {
qCDebug(logVlc, "Subtitle #%d, key: %d", i.value(), i.key());
if (i.value() == currentSubtitle) {
requestedSubtitle = i.key();
break;
}
i++;
}
qCDebug(logVlc, "Try to set subtitle #%d, id %d", currentSubtitle, requestedSubtitle);
libvlc_video_set_spu(vlcMediaPlayer, requestedSubtitle);
/* Print what it was actually selected */
libvlc_track_description_t *track = libvlc_video_get_spu_description(vlcMediaPlayer);
while (track != NULL) {
QString subtitle = QString::fromUtf8(track->psz_name);
if (subtitle.isEmpty()) {
subtitle = i18n("Subtitle %1", track->i_id);
}
if (track->i_id == requestedSubtitle)
qCDebug(logVlc, "Subtitle set to id %d: %s", track->i_id, qPrintable(subtitle));
track = track->p_next;
}
libvlc_track_description_list_release(track);
}
void VlcMediaWidget::setExternalSubtitle(const QUrl &url)
{
QString fname = url.toLocalFile();
#if LIBVLC_VERSION_MAJOR > 2
if (libvlc_media_player_add_slave(vlcMediaPlayer,
libvlc_media_slave_type_subtitle,
url.toEncoded().constData(),
true) == 0)
qCWarning(logMediaWidget, "Cannot set subtitle file %s", qPrintable(fname));
#else
if (libvlc_video_set_subtitle_file(vlcMediaPlayer,
qPrintable(fname)) == 0)
qCWarning(logMediaWidget, "Cannot set subtitle file %s", qPrintable(fname));
#endif
}
void VlcMediaWidget::setCurrentTitle(int currentTitle)
{
libvlc_media_player_set_title(vlcMediaPlayer, currentTitle);
}
void VlcMediaWidget::setCurrentChapter(int currentChapter)
{
libvlc_media_player_set_chapter(vlcMediaPlayer, currentChapter);
}
void VlcMediaWidget::setCurrentAngle(int currentAngle)
{
Q_UNUSED(currentAngle)
// FIXME
}
bool VlcMediaWidget::jumpToPreviousChapter()
{
int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
libvlc_media_player_previous_chapter(vlcMediaPlayer);
if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) ||
(libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) {
return true;
}
return false;
}
bool VlcMediaWidget::jumpToNextChapter()
{
int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
libvlc_media_player_next_chapter(vlcMediaPlayer);
if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) ||
(libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) {
return true;
}
return false;
}
void VlcMediaWidget::showDvdMenu()
{
if (playingDvd) {
libvlc_media_player_set_title(vlcMediaPlayer, 0);
}
}
int VlcMediaWidget::updatePlaybackStatus()
{
MediaWidget::PlaybackStatus oldPlaybackStatus = playbackStatus;
switch (libvlc_media_player_get_state(vlcMediaPlayer)) {
case libvlc_NothingSpecial:
case libvlc_Stopped:
playbackStatus = MediaWidget::Idle;
break;
case libvlc_Opening:
case libvlc_Buffering:
playbackStatus = MediaWidget::Playing;
break;
case libvlc_Playing:
// The first time libVLC is set to pause, it reports status as playing
if (isPaused)
playbackStatus = MediaWidget::Paused;
else
playbackStatus = MediaWidget::Playing;
break;
case libvlc_Paused:
playbackStatus = MediaWidget::Paused;
break;
case libvlc_Ended:
case libvlc_Error:
playbackStatus = MediaWidget::Idle;
// don't keep last picture shown
libvlc_media_player_stop(vlcMediaPlayer);
break;
}
if (playbackStatus == MediaWidget::Idle) {
addPendingUpdates(DvdMenu);
playingDvd = false;
}
// Report if the status has changed
return (oldPlaybackStatus != playbackStatus);
}
void VlcMediaWidget::updateCurrentTotalTime()
{
if (playbackStatus == MediaWidget::Idle)
return;
currentTime = int(libvlc_media_player_get_time(vlcMediaPlayer));
totalTime = int(libvlc_media_player_get_length(vlcMediaPlayer));
if (currentTime < 0) {
currentTime = 0;
}
if (totalTime < 0) {
totalTime = 0;
}
if (totalTime && currentTime > totalTime) {
currentTime = totalTime;
}
}
void VlcMediaWidget::updateSeekable()
{
seekable = libvlc_media_player_is_seekable(vlcMediaPlayer);
}
void VlcMediaWidget::updateMetadata()
{
metadata.clear();
libvlc_media_t *media = libvlc_media_player_get_media(vlcMediaPlayer);
if (media != NULL) {
metadata.insert(MediaWidget::Title,
QString::fromUtf8(libvlc_media_get_meta(media, libvlc_meta_Title)));
metadata.insert(MediaWidget::Artist,
QString::fromUtf8(libvlc_media_get_meta(media, libvlc_meta_Artist)));
metadata.insert(MediaWidget::Album,
QString::fromUtf8(libvlc_media_get_meta(media, libvlc_meta_Album)));
metadata.insert(MediaWidget::TrackNumber,
QString::fromUtf8(libvlc_media_get_meta(media, libvlc_meta_TrackNumber)));
}
}
void VlcMediaWidget::updateAudioStreams()
{
audioStreams.clear();
libvlc_track_description_t *track = libvlc_audio_get_track_description(vlcMediaPlayer);
if (track != NULL) {
// skip the 'deactivate' audio channel
track = track->p_next;
}
while (track != NULL) {
QString audioStream = QString::fromUtf8(track->psz_name);
int cutBegin = (audioStream.indexOf(QLatin1Char('[')) + 1);
if (cutBegin > 0) {
int cutEnd = audioStream.lastIndexOf(QLatin1Char(']'));
if (cutEnd >= 0) {
// remove unnecessary text
audioStream = audioStream.mid(cutBegin, cutEnd - cutBegin);
}
}
if (audioStream.isEmpty()) {
audioStream = QString::number(audioStreams.size() + 1);
}
audioStreams.append(audioStream);
track = track->p_next;
}
// skip the 'deactivate' audio channel
currentAudioStream = (libvlc_audio_get_track(vlcMediaPlayer) - 1);
}
void VlcMediaWidget::updateSubtitles()
{
subtitles.clear();
libvlc_track_description_t *track = libvlc_video_get_spu_description(vlcMediaPlayer);
int i = 0;
subtitleId.clear();
if (track != NULL) {
// skip the 'deactivate' subtitle
track = track->p_next;
}
while (track != NULL) {
QString subtitle = QString::fromUtf8(track->psz_name);
if (subtitle.isEmpty()) {
subtitle = i18n("Subtitle %1", track->i_id);
}
// 0 is reserved for "disabled" at mediawidget. So, we should
// Start counting from 1, to match the range expected for
// currentSubtitle
subtitleId[track->i_id] = ++i;
subtitles.append(subtitle);
qCDebug(logVlc, "Got subtitle id#%d: %s", track->i_id, qPrintable(subtitle));
track = track->p_next;
}
libvlc_track_description_list_release(track);
// skip the 'deactivate' subtitle
currentSubtitle = subtitleId.value(libvlc_video_get_spu(vlcMediaPlayer), -1);
}
void VlcMediaWidget::updateTitles()
{
titleCount = libvlc_media_player_get_title_count(vlcMediaPlayer);
currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
}
void VlcMediaWidget::updateChapters()
{
chapterCount = libvlc_media_player_get_chapter_count(vlcMediaPlayer);
currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
}
void VlcMediaWidget::updateAngles()
{
// FIXME
}
void VlcMediaWidget::updateDvdMenu()
{
dvdMenu = playingDvd;
}
void VlcMediaWidget::updateVideoSize()
{
// FIXME
}
void VlcMediaWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
libvlc_media_player_navigate(vlcMediaPlayer, libvlc_navigate_activate);
}
AbstractMediaWidget::mousePressEvent(event);
}
void VlcMediaWidget::hideMouse()
{
timer->stop();
setCursor(Qt::ArrowCursor);
setCursor(Qt::BlankCursor);
}
void VlcMediaWidget::mouseMoveEvent(QMouseEvent *event)
{
mouseVisible = this->rect().contains(event->pos());
if (!timer->isActive()) {
setCursor(Qt::BlankCursor);
setCursor(Qt::ArrowCursor);
}
if (mouseVisible)
timer->start(1000);
else
timer->stop();
AbstractMediaWidget::mouseMoveEvent(event);
}
void VlcMediaWidget::vlcEvent(const libvlc_event_t *event)
{
PendingUpdates pendingUpdatesToBeAdded = 0;
switch (event->type) {
#if LIBVLC_VERSION_MAJOR > 2
case libvlc_MediaPlayerESAdded:
case libvlc_MediaPlayerESDeleted:
#endif
case libvlc_MediaMetaChanged:
pendingUpdatesToBeAdded = Metadata | Subtitles;
break;
case libvlc_MediaPlayerEncounteredError:
pendingUpdatesToBeAdded = PlaybackStatus;
break;
case libvlc_MediaPlayerEndReached:
pendingUpdatesToBeAdded = (PlaybackFinished | PlaybackStatus);
break;
case libvlc_MediaPlayerLengthChanged:
pendingUpdatesToBeAdded = CurrentTotalTime;
break;
case libvlc_MediaPlayerSeekableChanged:
pendingUpdatesToBeAdded = Seekable | Subtitles;
break;
case libvlc_MediaPlayerStopped:
pendingUpdatesToBeAdded = PlaybackStatus;
setMouseTracking(false);
break;
case libvlc_MediaPlayerTimeChanged:
pendingUpdatesToBeAdded = CurrentTotalTime;
break;
}
if (pendingUpdatesToBeAdded != 0) {
addPendingUpdates(pendingUpdatesToBeAdded);
} else {
qCWarning(logMediaWidget, "Unknown libVLC event type %d", event->type);
}
}
void VlcMediaWidget::vlcEventHandler(const libvlc_event_t *event, void *instance)
{
reinterpret_cast(instance)->vlcEvent(event);
}
diff --git a/src/backend-vlc/vlcmediawidget.h b/src/backend-vlc/vlcmediawidget.h
index 243df93..03c4e03 100644
--- a/src/backend-vlc/vlcmediawidget.h
+++ b/src/backend-vlc/vlcmediawidget.h
@@ -1,98 +1,98 @@
/*
* vlcmediawidget.h
*
* Copyright (C) 2010-2012 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef VLCMEDIAWIDGET_H
#define VLCMEDIAWIDGET_H
#include "../abstractmediawidget.h"
class libvlc_event_t;
class libvlc_instance_t;
class libvlc_media_player_t;
class QTimer;
class VlcMediaWidget : public AbstractMediaWidget
{
Q_OBJECT
private:
explicit VlcMediaWidget(QWidget *parent);
bool init();
QTimer *timer;
bool isPaused;
private slots:
void hideMouse();
public:
~VlcMediaWidget();
static VlcMediaWidget *createVlcMediaWidget(QWidget *parent); // returns NULL if init fails
// zero-based numbering is used everywhere (e.g. first audio channel = 0)
QStringList getAudioDevices();
void setAudioDevice(QString device);
void setMuted(bool muted);
void setVolume(int volume); // [0 - 200]
void setAspectRatio(MediaWidget::AspectRatio aspectRatio);
void resizeToVideo(float resizeFactor);
- void setDeinterlacing(bool deinterlacing);
+ void setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing);
void play(const MediaSource &source);
void stop();
void setPaused(bool paused);
void seek(int time); // milliseconds
void setCurrentAudioStream(int currentAudioStream);
void setCurrentSubtitle(int currentSubtitle);
void setExternalSubtitle(const QUrl &subtitleUrl);
void setCurrentTitle(int currentTitle);
void setCurrentChapter(int currentChapter);
void setCurrentAngle(int currentAngle);
bool jumpToPreviousChapter();
bool jumpToNextChapter();
void showDvdMenu();
int updatePlaybackStatus();
void updateCurrentTotalTime();
void updateSeekable();
void updateMetadata();
void updateAudioStreams();
void updateSubtitles();
void updateTitles();
void updateChapters();
void updateAngles();
void updateDvdMenu();
void updateVideoSize();
private:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void vlcEvent(const libvlc_event_t *event);
static void vlcEventHandler(const libvlc_event_t *event, void *instance);
libvlc_instance_t *vlcInstance;
libvlc_media_player_t *vlcMediaPlayer;
bool playingDvd;
bool mouseVisible;
QMap subtitleId;
};
#endif /* VLCMEDIAWIDGET_H */
diff --git a/src/mediawidget.cpp b/src/mediawidget.cpp
index f963a9e..9819857 100644
--- a/src/mediawidget.cpp
+++ b/src/mediawidget.cpp
@@ -1,1456 +1,1563 @@
/*
* mediawidget.cpp
*
* Copyright (C) 2007-2011 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "log.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "backend-vlc/vlcmediawidget.h"
#include "configuration.h"
#include "mediawidget.h"
#include "mediawidget_p.h"
#include "osdwidget.h"
MediaWidget::MediaWidget(QMenu *menu_, QToolBar *toolBar, KActionCollection *collection,
QWidget *parent) : QWidget(parent), menu(menu_), displayMode(NormalMode),
autoResizeFactor(0), blockBackendUpdates(false), muted(false),
screenSaverSuspended(false), showElapsedTime(true)
{
dummySource.reset(new MediaSource());
source = dummySource.data();
QBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
QPalette palette = QWidget::palette();
palette.setColor(backgroundRole(), Qt::black);
setPalette(palette);
setAutoFillBackground(true);
setAcceptDrops(true);
setFocusPolicy(Qt::StrongFocus);
backend = VlcMediaWidget::createVlcMediaWidget(this);
if (backend == NULL) {
backend = new DummyMediaWidget(this);
}
backend->connectToMediaWidget(this);
layout->addWidget(backend);
osdWidget = new OsdWidget(this);
actionPrevious = new QWidgetAction(this);
actionPrevious->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
actionPrevious->setText(i18n("Previous"));
actionPrevious->setShortcut(Qt::Key_PageUp);
connect(actionPrevious, SIGNAL(triggered()), this, SLOT(previous()));
toolBar->addAction(collection->addAction(QLatin1String("controls_previous"), actionPrevious));
menu->addAction(actionPrevious);
actionPlayPause = new QWidgetAction(this);
actionPlayPause->setShortcut(Qt::Key_Space);
textPlay = i18n("Play");
textPause = i18n("Pause");
iconPlay = QIcon::fromTheme(QLatin1String("media-playback-start"), QIcon(":media-playback-start"));
iconPause = QIcon::fromTheme(QLatin1String("media-playback-pause"), QIcon(":media-playback-pause"));
connect(actionPlayPause, SIGNAL(triggered(bool)), this, SLOT(pausedChanged(bool)));
toolBar->addAction(collection->addAction(QLatin1String("controls_play_pause"), actionPlayPause));
menu->addAction(actionPlayPause);
actionStop = new QWidgetAction(this);
actionStop->setIcon(QIcon::fromTheme(QLatin1String("media-playback-stop"), QIcon(":media-playback-stop")));
actionStop->setText(i18n("Stop"));
actionStop->setShortcut(Qt::Key_Backspace);
connect(actionStop, SIGNAL(triggered()), this, SLOT(stop()));
toolBar->addAction(collection->addAction(QLatin1String("controls_stop"), actionStop));
menu->addAction(actionStop);
actionNext = new QWidgetAction(this);
actionNext->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
actionNext->setText(i18n("Next"));
actionNext->setShortcut(Qt::Key_PageDown);
connect(actionNext, SIGNAL(triggered()), this, SLOT(next()));
toolBar->addAction(collection->addAction(QLatin1String("controls_next"), actionNext));
menu->addAction(actionNext);
menu->addSeparator();
fullScreenAction = new QWidgetAction(this);
fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
fullScreenAction->setText(i18nc("'Playback' menu", "Full Screen Mode"));
fullScreenAction->setShortcut(Qt::Key_F);
connect(fullScreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
menu->addAction(collection->addAction(QLatin1String("view_fullscreen"), fullScreenAction));
minimalModeAction = new QWidgetAction(this);
minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
minimalModeAction->setText(i18nc("'Playback' menu", "Minimal Mode"));
minimalModeAction->setShortcut(Qt::Key_Period);
connect(minimalModeAction, SIGNAL(triggered()), this, SLOT(toggleMinimalMode()));
menu->addAction(collection->addAction(QLatin1String("view_minimal_mode"), minimalModeAction));
audioStreamBox = new QComboBox(toolBar);
connect(audioStreamBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(currentAudioStreamChanged(int)));
toolBar->addWidget(audioStreamBox);
audioStreamModel = new QStringListModel(toolBar);
audioStreamBox->setModel(audioStreamModel);
QMenu *subtitleMenu = new QMenu(i18nc("'Subtitle' menu", "Subtitle"), this);
subtitleBox = new QComboBox(this);
QWidgetAction *action = new QWidgetAction(this);
action->setDefaultWidget(subtitleBox);
textSubtitlesOff = i18nc("subtitle selection entry", "off");
connect(subtitleBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(currentSubtitleChanged(int)));
subtitleModel = new QStringListModel(toolBar);
subtitleBox->setModel(subtitleModel);
subtitleMenu->addAction(action);
menu->addMenu(subtitleMenu);
action = new QWidgetAction(this);
action->setText(i18nc("'Subtitle' menu", "Add subtitle file"));
action->setIcon(QIcon::fromTheme(QLatin1String("application-x-subrip"), QIcon(":application-x-subrip")));
connect(action, &QWidgetAction::triggered, this, &MediaWidget::openSubtitle);
subtitleMenu->addAction(action);
menu->addMenu(subtitleMenu);
QMenu *audioMenu = new QMenu(i18nc("'Playback' menu", "Audio"), this);
action = new QWidgetAction(this);
action->setIcon(QIcon::fromTheme(QLatin1String("audio-card"), QIcon(":audio-card")));
action->setText(i18nc("'Audio' menu", "Audio Device"));
audioDevMenu = new QMenu(i18nc("'Playback' menu", "Audio Device"), audioMenu);
action = new QWidgetAction(this);
connect(audioDevMenu, &QMenu::aboutToShow, this, &MediaWidget::getAudioDevices);
audioMenu->addMenu(audioDevMenu);
action = new QWidgetAction(this);
action->setIcon(QIcon::fromTheme(QLatin1String("audio-volume-high"), QIcon(":audio-volume-high")));
action->setText(i18nc("'Audio' menu", "Increase Volume"));
action->setShortcut(Qt::Key_Plus);
connect(action, SIGNAL(triggered()), this, SLOT(increaseVolume()));
audioMenu->addAction(collection->addAction(QLatin1String("controls_increase_volume"), action));
action = new QWidgetAction(this);
action->setIcon(QIcon::fromTheme(QLatin1String("audio-volume-low"), QIcon(":audio-volume-low")));
action->setText(i18nc("'Audio' menu", "Decrease Volume"));
action->setShortcut(Qt::Key_Minus);
connect(action, SIGNAL(triggered()), this, SLOT(decreaseVolume()));
audioMenu->addAction(collection->addAction(QLatin1String("controls_decrease_volume"), action));
muteAction = new QWidgetAction(this);
muteAction->setText(i18nc("'Audio' menu", "Mute Volume"));
mutedIcon = QIcon::fromTheme(QLatin1String("audio-volume-muted"), QIcon(":audio-volume-muted"));
unmutedIcon = QIcon::fromTheme(QLatin1String("audio-volume-medium"), QIcon(":audio-volume-medium"));
muteAction->setIcon(unmutedIcon);
muteAction->setShortcut(Qt::Key_M);
connect(muteAction, SIGNAL(triggered()), this, SLOT(mutedChanged()));
toolBar->addAction(collection->addAction(QLatin1String("controls_mute_volume"), muteAction));
audioMenu->addAction(muteAction);
menu->addMenu(audioMenu);
QMenu *videoMenu = new QMenu(i18nc("'Playback' menu", "Video"), this);
menu->addMenu(videoMenu);
menu->addSeparator();
- deinterlaceAction = new QWidgetAction(this);
- deinterlaceAction->setIcon(QIcon::fromTheme(QLatin1String("format-justify-center"), QIcon(":format-justify-center")));
- deinterlaceAction->setText(i18nc("'Video' menu", "Deinterlace"));
- deinterlaceAction->setCheckable(true);
- deinterlaceAction->setChecked(
- KSharedConfig::openConfig()->group("MediaObject").readEntry("Deinterlace", true));
- deinterlaceAction->setShortcut(Qt::Key_I);
- connect(deinterlaceAction, SIGNAL(toggled(bool)), this, SLOT(deinterlacingChanged(bool)));
- backend->setDeinterlacing(deinterlaceAction->isChecked());
- videoMenu->addAction(collection->addAction(QLatin1String("controls_deinterlace"), deinterlaceAction));
+ QMenu *deinterlaceMenu = new QMenu(i18nc("'Video' menu", "Deinterlace"), this);
+ deinterlaceMenu->setIcon(QIcon::fromTheme(QLatin1String("format-justify-center"), QIcon(":format-justify-center")));
+ QActionGroup *deinterlaceGroup = new QActionGroup(this);
+ connect(deinterlaceMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(deinterlacingChanged(QAction*)));
+ videoMenu->addMenu(deinterlaceMenu);
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "disabled"));
+ action->setCheckable(true);
+ action->setShortcut(Qt::Key_D);
+ action->setData(DeinterlaceDisabled);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_disabled"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "discard"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceDiscard);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_discard"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "bob"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceBob);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_bob"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "linear"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceLinear);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_linear"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "yadif"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceYadif);
+ action->setShortcut(Qt::Key_I);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_yadif"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "yadif2x"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceYadif2x);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_yadif2x"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "phosphor"));
+ action->setCheckable(true);
+ action->setData(DeinterlacePhosphor);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_phosphor"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "x"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceX);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_x"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "mean"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceMean);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_mean"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "blend"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceBlend);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_blend"), action));
+
+ action = new QWidgetAction(deinterlaceGroup);
+ action->setText(i18nc("'Deinterlace' menu", "Inverse telecine"));
+ action->setCheckable(true);
+ action->setData(DeinterlaceIvtc);
+ deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_ivtc"), action));
+
+ deinterlaceMode =
+ KSharedConfig::openConfig()->group("MediaObject").readEntry("Deinterlace", 0);
+
+ if (deinterlaceMode <= DeinterlaceIvtc) {
+ for (int i = 0; i < deinterlaceGroup->actions().size(); i++) {
+ if (deinterlaceGroup->actions().at(i)->data().toInt() == deinterlaceMode) {
+ deinterlaceGroup->actions().at(i)->setChecked(true);
+ break;
+ }
+ }
+ } else {
+ deinterlaceGroup->actions().at(0)->setChecked(true);
+ }
+ backend->setDeinterlacing(static_cast(deinterlaceMode));
QMenu *aspectMenu = new QMenu(i18nc("'Video' menu", "Aspect Ratio"), this);
QActionGroup *aspectGroup = new QActionGroup(this);
connect(aspectGroup, SIGNAL(triggered(QAction*)),
this, SLOT(aspectRatioChanged(QAction*)));
+ videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "Automatic"));
action->setCheckable(true);
- action->setChecked(true);
action->setData(AspectRatioAuto);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_auto"), action));
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "1:1"));
action->setCheckable(true);
action->setData(AspectRatio1_1);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_1_1"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "4:3"));
action->setCheckable(true);
action->setData(AspectRatio4_3);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_4_3"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "5:4"));
action->setCheckable(true);
action->setData(AspectRatio5_4);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_5_4"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "16:9"));
action->setCheckable(true);
action->setData(AspectRatio16_9);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_16_9"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "16:10"));
action->setCheckable(true);
action->setData(AspectRatio16_10);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_16_10"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "2.21:1"));
action->setCheckable(true);
action->setData(AspectRatio221_100);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_221_100"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "2.35:1"));
action->setCheckable(true);
action->setData(AspectRatio235_100);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_235_100"), action));
- videoMenu->addMenu(aspectMenu);
action = new QWidgetAction(aspectGroup);
action->setText(i18nc("'Aspect Ratio' menu", "2.39:1"));
action->setCheckable(true);
action->setData(AspectRatio239_100);
aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_239_100"), action));
- videoMenu->addMenu(aspectMenu);
QMenu *autoResizeMenu = new QMenu(i18n("Video size"), this);
QActionGroup *autoResizeGroup = new QActionGroup(this);
// we need an event even if you select the currently selected item
autoResizeGroup->setExclusive(false);
connect(autoResizeGroup, SIGNAL(triggered(QAction*)),
this, SLOT(autoResizeTriggered(QAction*)));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "Automatic"));
action->setCheckable(true);
action->setData(0);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_off"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "25%"));
action->setCheckable(true);
action->setData(25);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "50%"));
action->setCheckable(true);
action->setData(50);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "75%"));
action->setCheckable(true);
action->setData(75);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "Original Size"));
action->setCheckable(true);
action->setData(100);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_original"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "150%"));
action->setCheckable(true);
action->setData(150);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "200%"));
action->setCheckable(true);
action->setData(200);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "250%"));
action->setCheckable(true);
action->setData(250);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
action = new QWidgetAction(autoResizeGroup);
action->setText(i18nc("Video size", "300%"));
action->setCheckable(true);
action->setData(300);
autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
autoResizeFactor =
KSharedConfig::openConfig()->group("MediaObject").readEntry("AutoResizeFactor", 0);
if (autoResizeFactor <= 300) {
for (int i = 0; i < autoResizeGroup->actions().size(); i++) {
if (autoResizeGroup->actions().at(i)->data().toInt() == autoResizeFactor) {
autoResizeGroup->actions().at(i)->setChecked(true);
break;
}
}
} else {
autoResizeGroup->actions().at(0)->setChecked(true);
}
setVideoSize();
videoMenu->addMenu(autoResizeMenu);
action = new QWidgetAction(this);
action->setText(i18n("Volume Slider"));
volumeSlider = new QSlider(toolBar);
volumeSlider->setFocusPolicy(Qt::NoFocus);
volumeSlider->setOrientation(Qt::Horizontal);
volumeSlider->setRange(0, 100);
volumeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
volumeSlider->setToolTip(action->text());
volumeSlider->setValue(KSharedConfig::openConfig()->group("MediaObject").readEntry("Volume", 100));
connect(volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
backend->setVolume(volumeSlider->value());
action->setDefaultWidget(volumeSlider);
toolBar->addAction(collection->addAction(QLatin1String("controls_volume_slider"), action));
jumpToPositionAction = new QWidgetAction(this);
jumpToPositionAction->setIcon(QIcon::fromTheme(QLatin1String("go-jump"), QIcon(":go-jump")));
jumpToPositionAction->setText(i18nc("@action:inmenu", "Jump to Position..."));
jumpToPositionAction->setShortcut(Qt::CTRL + Qt::Key_J);
connect(jumpToPositionAction, SIGNAL(triggered()), this, SLOT(jumpToPosition()));
menu->addAction(collection->addAction(QLatin1String("controls_jump_to_position"), jumpToPositionAction));
navigationMenu = new QMenu(i18nc("playback menu", "Skip"), this);
menu->addMenu(navigationMenu);
menu->addSeparator();
int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
int longSkipDuration = Configuration::instance()->getLongSkipDuration();
connect(Configuration::instance(), SIGNAL(shortSkipDurationChanged(int)),
this, SLOT(shortSkipDurationChanged(int)));
connect(Configuration::instance(), SIGNAL(longSkipDurationChanged(int)),
this, SLOT(longSkipDurationChanged(int)));
longSkipBackwardAction = new QWidgetAction(this);
longSkipBackwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
// xgettext:no-c-format
longSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward", longSkipDuration));
longSkipBackwardAction->setShortcut(Qt::SHIFT + Qt::Key_Left);
connect(longSkipBackwardAction, SIGNAL(triggered()), this, SLOT(longSkipBackward()));
navigationMenu->addAction(
collection->addAction(QLatin1String("controls_long_skip_backward"), longSkipBackwardAction));
shortSkipBackwardAction = new QWidgetAction(this);
shortSkipBackwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
// xgettext:no-c-format
shortSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward", shortSkipDuration));
shortSkipBackwardAction->setShortcut(Qt::Key_Left);
connect(shortSkipBackwardAction, SIGNAL(triggered()), this, SLOT(shortSkipBackward()));
navigationMenu->addAction(
collection->addAction(QLatin1String("controls_skip_backward"), shortSkipBackwardAction));
shortSkipForwardAction = new QWidgetAction(this);
shortSkipForwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
// xgettext:no-c-format
shortSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward", shortSkipDuration));
shortSkipForwardAction->setShortcut(Qt::Key_Right);
connect(shortSkipForwardAction, SIGNAL(triggered()), this, SLOT(shortSkipForward()));
navigationMenu->addAction(
collection->addAction(QLatin1String("controls_skip_forward"), shortSkipForwardAction));
longSkipForwardAction = new QWidgetAction(this);
longSkipForwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
// xgettext:no-c-format
longSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward", longSkipDuration));
longSkipForwardAction->setShortcut(Qt::SHIFT + Qt::Key_Right);
connect(longSkipForwardAction, SIGNAL(triggered()), this, SLOT(longSkipForward()));
navigationMenu->addAction(
collection->addAction(QLatin1String("controls_long_skip_forward"), longSkipForwardAction));
toolBar->addAction(QIcon::fromTheme(QLatin1String("player-time"), QIcon(":player-time")), i18n("Seek Slider"))->setEnabled(false);
action = new QWidgetAction(this);
action->setText(i18n("Seek Slider"));
seekSlider = new SeekSlider(toolBar);
seekSlider->setFocusPolicy(Qt::NoFocus);
seekSlider->setOrientation(Qt::Horizontal);
seekSlider->setToolTip(action->text());
connect(seekSlider, SIGNAL(valueChanged(int)), this, SLOT(seek(int)));
action->setDefaultWidget(seekSlider);
toolBar->addAction(collection->addAction(QLatin1String("controls_position_slider"), action));
menuAction = new QWidgetAction(this);
menuAction->setIcon(QIcon::fromTheme(QLatin1String("media-optical-video"), QIcon(":media-optical-video")));
menuAction->setText(i18nc("dvd navigation", "DVD Menu"));
connect(menuAction, SIGNAL(triggered()), this, SLOT(toggleMenu()));
menu->addAction(collection->addAction(QLatin1String("controls_toggle_menu"), menuAction));
titleMenu = new QMenu(i18nc("dvd navigation", "Title"), this);
titleGroup = new QActionGroup(this);
connect(titleGroup, SIGNAL(triggered(QAction*)),
this, SLOT(currentTitleChanged(QAction*)));
menu->addMenu(titleMenu);
chapterMenu = new QMenu(i18nc("dvd navigation", "Chapter"), this);
chapterGroup = new QActionGroup(this);
connect(chapterGroup, SIGNAL(triggered(QAction*)),
this, SLOT(currentChapterChanged(QAction*)));
menu->addMenu(chapterMenu);
angleMenu = new QMenu(i18nc("dvd navigation", "Angle"), this);
angleGroup = new QActionGroup(this);
connect(angleGroup, SIGNAL(triggered(QAction*)), this,
SLOT(currentAngleChanged(QAction*)));
menu->addMenu(angleMenu);
action = new QWidgetAction(this);
action->setText(i18n("Switch between elapsed and remaining time display"));
timeButton = new QPushButton(toolBar);
timeButton->setFocusPolicy(Qt::NoFocus);
timeButton->setToolTip(action->text());
connect(timeButton, SIGNAL(clicked(bool)), this, SLOT(timeButtonClicked()));
action->setDefaultWidget(timeButton);
toolBar->addAction(collection->addAction(QLatin1String("controls_time_button"), action));
QTimer *timer = new QTimer(this);
timer->start(50000);
connect(timer, SIGNAL(timeout()), this, SLOT(checkScreenSaver()));
// Set the play/pause icons accordingly
playbackStatusChanged();
}
MediaWidget::~MediaWidget()
{
KSharedConfig::openConfig()->group("MediaObject").writeEntry("Volume", volumeSlider->value());
- KSharedConfig::openConfig()->group("MediaObject").writeEntry("Deinterlace",
- deinterlaceAction->isChecked());
+ KSharedConfig::openConfig()->group("MediaObject").writeEntry("Deinterlace", deinterlaceMode);
KSharedConfig::openConfig()->group("MediaObject").writeEntry("AutoResizeFactor", autoResizeFactor);
}
QString MediaWidget::extensionFilter()
{
return i18n(
"Supported Media Files ("
// generated from kaffeine.desktop's mime types
"*.3ga *.3gp *.3gpp *.669 *.ac3 *.aif *.aiff *.anim1 *.anim2 *.anim3 *.anim4 "
"*.anim5 *.anim6 *.anim7 *.anim8 *.anim9 *.animj *.asf *.asx *.au *.avf *.avi "
"*.bdm *.bdmv *.clpi *.cpi *.divx *.dv *.f4a *.f4b *.f4v *.flac *.flc *.fli *.flv "
"*.it *.lrv *.m15 *.m2t *.m2ts *.m3u *.m3u8 *.m4a *.m4b *.m4v *.med *.mka *.mkv "
"*.mng *.mod *.moov *.mov *.mp+ *.mp2 *.mp3 *.mp4 *.mpc *.mpe *.mpeg *.mpg *.mpga "
"*.mpl *.mpls *.mpp *.mtm *.mts *.nsv *.oga *.ogg *.ogm *.ogv *.ogx *.opus *.pls "
"*.qt *.qtl *.qtvr *.ra *.ram *.rax *.rm *.rmj *.rmm *.rms *.rmvb *.rmx *.rp *.rv "
"*.rvx *.s3m *.shn *.snd *.spl *.stm *.swf *.ts *.tta *.ult *.uni *.vdr *.vlc "
"*.vob *.voc *.wav *.wax *.webm *.wma *.wmv *.wmx *.wv *.wvp *.wvx *.xm *.xspf "
// manual entries
"*.kaffeine *.iso);;"
"All Files (*)");
}
MediaWidget::DisplayMode MediaWidget::getDisplayMode() const
{
return displayMode;
}
void MediaWidget::setDisplayMode(DisplayMode displayMode_)
{
if (displayMode != displayMode_) {
displayMode = displayMode_;
switch (displayMode) {
case NormalMode:
case MinimalMode:
fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
fullScreenAction->setText(i18nc("'Playback' menu", "Full Screen Mode"));
break;
case FullScreenMode:
case FullScreenReturnToMinimalMode:
fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-restore"), QIcon(":view-restore")));
fullScreenAction->setText(i18nc("'Playback' menu",
"Exit Full Screen Mode"));
break;
}
switch (displayMode) {
case NormalMode:
case FullScreenMode:
case FullScreenReturnToMinimalMode:
minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-restore"), QIcon(":view-restore")));
minimalModeAction->setText(i18nc("'Playback' menu", "Minimal Mode"));
break;
case MinimalMode:
minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
minimalModeAction->setText(i18nc("'Playback' menu", "Exit Minimal Mode"));
break;
}
emit displayModeChanged();
}
}
void MediaWidget::play(MediaSource *source_)
{
if (source != source_) {
source->playbackStatusChanged(Idle);
source = source_;
if (source == NULL) {
source = dummySource.data();
}
}
source->setMediaWidget(this);
backend->play(*source);
}
void MediaWidget::mediaSourceDestroyed(MediaSource *mediaSource)
{
if (source == mediaSource) {
source = dummySource.data();
}
}
void MediaWidget::openSubtitle()
{
QString fname = QFileDialog::getOpenFileName(this,
i18nc("@title:window", "Open subtitle"),".",
i18n("Subtitles (*.cdg *.idx *.srt " \
"*.sub *.utf *.ass " \
"*.ssa *.aqt " \
"*.jss *.psb " \
"*.rt *.smi *.txt " \
"*.smil *.stl *.usf " \
"*.dks *.pjs *.mpl2 *.mks " \
"*.vtt *.ttml *.dfxp"));
setSubtitle(QUrl::fromLocalFile(fname));
}
void MediaWidget::setSubtitle(QUrl url)
{
if (!url.isValid()) {
return;
}
backend->setExternalSubtitle(url);
}
void MediaWidget::play(const QUrl &url, const QUrl &subtitleUrl)
{
// FIXME mem-leak
play(new MediaSourceUrl(url, subtitleUrl));
}
void MediaWidget::playAudioCd(const QString &device)
{
QUrl devicePath;
if (!device.isEmpty()) {
devicePath = QUrl::fromLocalFile(device);
} else {
QList devices =
Solid::Device::listFromQuery(QLatin1String("OpticalDisc.availableContent & 'Audio'"));
if (!devices.isEmpty()) {
Solid::Block *block = devices.first().as();
if (block != NULL) {
devicePath = QUrl::fromLocalFile(block->device());
}
}
}
// FIXME mem-leak
play(new MediaSourceAudioCd(devicePath));
}
void MediaWidget::playVideoCd(const QString &device)
{
QUrl devicePath;
if (!device.isEmpty()) {
devicePath = QUrl::fromLocalFile(device);
} else {
QList devices = Solid::Device::listFromQuery(
QLatin1String("OpticalDisc.availableContent & 'VideoCd|SuperVideoCd'"));
if (!devices.isEmpty()) {
Solid::Block *block = devices.first().as();
if (block != NULL) {
devicePath = QUrl::fromLocalFile(block->device());
}
}
}
// FIXME mem-leak
play(new MediaSourceVideoCd(devicePath));
}
void MediaWidget::playDvd(const QString &device)
{
QUrl devicePath;
if (!device.isEmpty()) {
devicePath = QUrl::fromLocalFile(device);
} else {
QList devices =
Solid::Device::listFromQuery(QLatin1String("OpticalDisc.availableContent & 'VideoDvd'"));
if (!devices.isEmpty()) {
Solid::Block *block = devices.first().as();
if (block != NULL) {
devicePath = QUrl::fromLocalFile(block->device());
}
}
}
// FIXME mem-leak
play(new MediaSourceDvd(devicePath));
}
OsdWidget *MediaWidget::getOsdWidget()
{
return osdWidget;
}
MediaWidget::PlaybackStatus MediaWidget::getPlaybackStatus() const
{
return backend->getPlaybackStatus();
}
int MediaWidget::getVolume() const
{
return volumeSlider->value();
}
int MediaWidget::getPosition() const
{
return backend->getCurrentTime();
}
void MediaWidget::play()
{
source->replay();
}
void MediaWidget::togglePause()
{
actionPlayPause->trigger();
}
void MediaWidget::setPosition(int position)
{
backend->seek(position);
}
void MediaWidget::setVolume(int volume)
{
// QSlider ensures that the value is within the range
volumeSlider->setValue(volume);
}
void MediaWidget::toggleMuted()
{
muteAction->trigger();
}
void MediaWidget::previous()
{
if (source->getType() == MediaSource::Url)
emit playlistPrevious();
source->previous();
}
void MediaWidget::next()
{
if (source->getType() == MediaSource::Url)
emit playlistNext();
source->next();
}
void MediaWidget::stop()
{
switch (backend->getPlaybackStatus()) {
case Idle:
break;
case Playing:
case Paused:
osdWidget->showText(i18nc("osd", "Stopped"), 1500);
break;
}
backend->stop();
source->playbackStatusChanged(Idle);
}
void MediaWidget::setAudioCard()
{
QAction *action = qobject_cast(sender());
backend->setAudioDevice(action->data().toString());
}
void MediaWidget::increaseVolume()
{
// QSlider ensures that the value is within the range
volumeSlider->setValue(volumeSlider->value() + 5);
}
void MediaWidget::decreaseVolume()
{
// QSlider ensures that the value is within the range
volumeSlider->setValue(volumeSlider->value() - 5);
}
void MediaWidget::checkScreenSaver()
{
bool suspendScreenSaver = false;
switch (backend->getPlaybackStatus()) {
case Idle:
case Paused:
break;
case Playing:
suspendScreenSaver = isVisible();
break;
}
if (suspendScreenSaver) {
// KDE - Inhibit doesn't inhibit "lock screen after inactivity"
QDBusInterface(QLatin1String("org.freedesktop.ScreenSaver"), QLatin1String("/ScreenSaver"),
QLatin1String("org.freedesktop.ScreenSaver")).call(QDBus::NoBlock,
QLatin1String("SimulateUserActivity"));
// GNOME - Inhibit doesn't inhibit power management functions
QDBusInterface(QLatin1String("org.gnome.ScreenSaver"), QLatin1String("/"),
QLatin1String("org.gnome.ScreenSaver")).
call(QDBus::NoBlock, QLatin1String("SimulateUserActivity"));
}
if (screenSaverSuspended != suspendScreenSaver) {
// X11 - needed if none of the above applications is running
screenSaverSuspended = suspendScreenSaver;
XScreenSaverSuspend(QX11Info::display(), suspendScreenSaver);
}
}
void MediaWidget::mutedChanged()
{
muted = !muted;
backend->setMuted(muted);
if (muted) {
muteAction->setIcon(mutedIcon);
osdWidget->showText(i18nc("osd", "Mute On"), 1500);
} else {
muteAction->setIcon(unmutedIcon);
osdWidget->showText(i18nc("osd", "Mute Off"), 1500);
}
}
void MediaWidget::volumeChanged(int volume)
{
backend->setVolume(volume);
osdWidget->showText(i18nc("osd", "Volume: %1%", volume), 1500);
}
void MediaWidget::toggleFullScreen()
{
switch (displayMode) {
case NormalMode:
setDisplayMode(FullScreenMode);
break;
case FullScreenMode:
setDisplayMode(NormalMode);
break;
case FullScreenReturnToMinimalMode:
setDisplayMode(MinimalMode);
break;
case MinimalMode:
setDisplayMode(FullScreenReturnToMinimalMode);
break;
}
}
void MediaWidget::toggleMinimalMode()
{
switch (displayMode) {
case NormalMode:
case FullScreenMode:
case FullScreenReturnToMinimalMode:
setDisplayMode(MinimalMode);
break;
case MinimalMode:
setDisplayMode(NormalMode);
break;
}
}
void MediaWidget::seek(int position)
{
if (blockBackendUpdates) {
return;
}
backend->seek(position);
}
-void MediaWidget::deinterlacingChanged(bool deinterlacing)
+void MediaWidget::deinterlacingChanged(QAction *action)
{
- backend->setDeinterlacing(deinterlacing);
+ bool ok;
+ const char *mode;
- if (deinterlacing) {
- osdWidget->showText(i18nc("osd message", "Deinterlacing On"), 1500);
- } else {
- osdWidget->showText(i18nc("osd message", "Deinterlacing Off"), 1500);
+ deinterlaceMode = action->data().toInt(&ok);
+
+ switch (deinterlaceMode) {
+ case DeinterlaceDiscard:
+ mode = "discard";
+ break;
+ case DeinterlaceBob:
+ mode = "bob";
+ break;
+ case DeinterlaceLinear:
+ mode = "linear";
+ break;
+ case DeinterlaceYadif:
+ mode = "yadif";
+ break;
+ case DeinterlaceYadif2x:
+ mode = "yadif2x";
+ break;
+ case DeinterlacePhosphor:
+ mode = "phosphor";
+ break;
+ case DeinterlaceX:
+ mode = "x";
+ break;
+ case DeinterlaceMean:
+ mode = "mean";
+ break;
+ case DeinterlaceBlend:
+ mode = "blend";
+ break;
+ case DeinterlaceIvtc:
+ mode = "ivtc";
+ break;
+ case DeinterlaceDisabled:
+ default:
+ mode = "disabled";
}
+
+ backend->setDeinterlacing(static_cast(deinterlaceMode));
+
+ osdWidget->showText(i18nc("osd message", "Deinterlace %1", mode), 1500);
}
void MediaWidget::aspectRatioChanged(QAction *action)
{
bool ok;
unsigned int aspectRatio_ = action->data().toInt(&ok);
- if (ok && aspectRatio_ <= AspectRatio239_100) {
+ if (aspectRatio_ <= AspectRatio239_100) {
backend->setAspectRatio(static_cast(aspectRatio_));
setVideoSize();
return;
}
qCWarning(logMediaWidget, "internal error");
}
void MediaWidget::setVideoSize()
{
float scale = autoResizeFactor / 100.0;
if (scale > 3.4 || scale < 0)
scale = 0;
backend->resizeToVideo(scale);
}
void MediaWidget::autoResizeTriggered(QAction *action)
{
foreach (QAction *autoResizeAction, action->actionGroup()->actions()) {
autoResizeAction->setChecked(autoResizeAction == action);
}
bool ok = false;
autoResizeFactor = action->data().toInt(&ok);
if (ok)
setVideoSize();
else
qCWarning(logMediaWidget, "internal error");
}
void MediaWidget::pausedChanged(bool paused)
{
switch (backend->getPlaybackStatus()) {
case Idle:
source->replay();
break;
case Playing:
case Paused:
backend->setPaused(paused);
break;
}
}
void MediaWidget::timeButtonClicked()
{
showElapsedTime = !showElapsedTime;
currentTotalTimeChanged();
}
void MediaWidget::longSkipBackward()
{
int longSkipDuration = Configuration::instance()->getLongSkipDuration();
int currentTime = (backend->getCurrentTime() - 1000 * longSkipDuration);
if (currentTime < 0) {
currentTime = 0;
}
backend->seek(currentTime);
}
void MediaWidget::shortSkipBackward()
{
int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
int currentTime = (backend->getCurrentTime() - 1000 * shortSkipDuration);
if (currentTime < 0) {
currentTime = 0;
}
backend->seek(currentTime);
}
void MediaWidget::shortSkipForward()
{
int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
backend->seek(backend->getCurrentTime() + 1000 * shortSkipDuration);
}
void MediaWidget::longSkipForward()
{
int longSkipDuration = Configuration::instance()->getLongSkipDuration();
backend->seek(backend->getCurrentTime() + 1000 * longSkipDuration);
}
void MediaWidget::jumpToPosition()
{
QDialog *dialog = new JumpToPositionDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
dialog->setModal(true);
dialog->show();
}
void MediaWidget::currentAudioStreamChanged(int currentAudioStream)
{
if (!blockBackendUpdates) {
if (source->overrideAudioStreams()) {
source->setCurrentAudioStream(currentAudioStream);
return;
}
source->setCurrentAudioStream(currentAudioStream -
backend->getAudioStreams().size());
if (currentAudioStream >= backend->getAudioStreams().size()) {
currentAudioStream = -1;
}
if (backend->getCurrentAudioStream() != currentAudioStream) {
backend->setCurrentAudioStream(currentAudioStream);
}
}
}
void MediaWidget::currentSubtitleChanged(int currentSubtitle)
{
if (blockBackendUpdates)
return;
if (source->overrideSubtitles()) {
source->setCurrentSubtitle(currentSubtitle - 1);
return;
}
source->setCurrentSubtitle(currentSubtitle - 1 - backend->getSubtitles().size());
backend->setCurrentSubtitle(currentSubtitle);
}
void MediaWidget::toggleMenu()
{
backend->showDvdMenu();
}
void MediaWidget::currentTitleChanged(QAction *action)
{
backend->setCurrentTitle(titleGroup->actions().indexOf(action) + 1);
}
void MediaWidget::currentChapterChanged(QAction *action)
{
backend->setCurrentChapter(chapterGroup->actions().indexOf(action) + 1);
}
void MediaWidget::currentAngleChanged(QAction *action)
{
backend->setCurrentAngle(angleGroup->actions().indexOf(action) + 1);
}
void MediaWidget::shortSkipDurationChanged(int shortSkipDuration)
{
// xgettext:no-c-format
shortSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward",
shortSkipDuration));
// xgettext:no-c-format
shortSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward",
shortSkipDuration));
}
void MediaWidget::longSkipDurationChanged(int longSkipDuration)
{
// xgettext:no-c-format
longSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward",
longSkipDuration));
// xgettext:no-c-format
longSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward",
longSkipDuration));
}
void MediaWidget::getAudioDevices()
{
foreach(QAction *action, audioDevMenu->actions()) {
audioDevMenu->removeAction(action);
}
foreach(const QString &device, backend->getAudioDevices()) {
QAction *action = new QWidgetAction(this);
action->setText(device);
action->setData(device);
connect(action, SIGNAL(triggered()), this, SLOT(setAudioCard()));
audioDevMenu->addAction(action);
}
}
void MediaWidget::audioStreamsChanged()
{
QStringList items;
int currentIndex;
if (source->overrideAudioStreams()) {
items = source->getAudioStreams();
currentIndex = source->getCurrentAudioStream();
} else {
items = backend->getAudioStreams();
currentIndex = backend->getCurrentAudioStream();
}
blockBackendUpdates = true;
if (audioStreamModel->stringList() != items) {
audioStreamModel->setStringList(items);
}
audioStreamBox->setCurrentIndex(currentIndex);
audioStreamBox->setEnabled(items.size() > 1);
blockBackendUpdates = false;
}
void MediaWidget::subtitlesChanged()
{
QStringList items(textSubtitlesOff);
int currentIndex = 0;
if (source->overrideSubtitles()) {
items += source->getSubtitles();
currentIndex = (source->getCurrentSubtitle() + 1);
// automatically choose appropriate subtitle
int selectedSubtitle = -1;
if (currentIndex > 0) {
selectedSubtitle = (backend->getSubtitles().size() - 1);
}
if (backend->getCurrentSubtitle() != selectedSubtitle) {
backend->setCurrentSubtitle(selectedSubtitle);
}
} else {
items += backend->getSubtitles();
items += source->getSubtitles();
currentIndex = (backend->getCurrentSubtitle());
int currentSourceIndex = source->getCurrentSubtitle();
if (currentSourceIndex >= 0) {
currentIndex = (currentSourceIndex + backend->getSubtitles().size() + 1);
}
}
blockBackendUpdates = true;
if (subtitleModel->stringList() != items) {
subtitleModel->setStringList(items);
}
if (currentIndex < 0)
currentIndex = 0;
subtitleBox->setCurrentIndex(currentIndex);
subtitleBox->setEnabled(items.size() > 1);
blockBackendUpdates = false;
}
void MediaWidget::currentTotalTimeChanged()
{
int currentTime = backend->getCurrentTime();
int totalTime = backend->getTotalTime();
source->trackLengthChanged(totalTime);
if (source->getType() == MediaSource::Url)
emit playlistTrackLengthChanged(totalTime);
// If the player backend doesn't implement currentTime and/or
// totalTime, the source can implement such logic
source->validateCurrentTotalTime(currentTime, totalTime);
blockBackendUpdates = true;
seekSlider->setRange(0, totalTime);
seekSlider->setValue(currentTime);
if (showElapsedTime) {
timeButton->setText(QLatin1Char(' ') + QTime(0, 0).addMSecs(currentTime).toString());
} else {
int remainingTime = (totalTime - currentTime);
timeButton->setText(QLatin1Char('-') + QTime(0, 0).addMSecs(remainingTime).toString());
}
blockBackendUpdates = false;
}
void MediaWidget::seekableChanged()
{
bool seekable = (backend->isSeekable() && !source->hideCurrentTotalTime());
seekSlider->setEnabled(seekable);
navigationMenu->setEnabled(seekable);
jumpToPositionAction->setEnabled(seekable);
timeButton->setEnabled(seekable);
}
void MediaWidget::contextMenuEvent(QContextMenuEvent *event)
{
menu->popup(event->globalPos());
}
void MediaWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_UNUSED(event)
emit toggleFullScreen();
}
void MediaWidget::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void MediaWidget::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData();
if (mimeData->hasUrls()) {
emit playlistUrlsDropped(mimeData->urls());
event->acceptProposedAction();
}
}
void MediaWidget::keyPressEvent(QKeyEvent *event)
{
int key = event->key();
if ((key >= Qt::Key_0) && (key <= Qt::Key_9)) {
emit osdKeyPressed(key);
} else {
QWidget::keyPressEvent(event);
}
}
void MediaWidget::resizeEvent(QResizeEvent *event)
{
osdWidget->resize(event->size());
QWidget::resizeEvent(event);
}
void MediaWidget::wheelEvent(QWheelEvent *event)
{
int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
int currentTime =
(backend->getCurrentTime() - ((25 * shortSkipDuration * event->delta()) / 3));
if (currentTime < 0) {
currentTime = 0;
}
backend->seek(currentTime);
}
void MediaWidget::playbackFinished()
{
if (source->getType() == MediaSource::Url)
emit playlistNext();
source->playbackFinished();
}
void MediaWidget::playbackStatusChanged()
{
source->playbackStatusChanged(backend->getPlaybackStatus());
bool playing = true;
switch (backend->getPlaybackStatus()) {
case Idle:
actionPlayPause->setIcon(iconPlay);
actionPlayPause->setText(textPlay);
playing = false;
break;
case Playing:
actionPlayPause->setIcon(iconPause);
actionPlayPause->setText(textPause);
osdWidget->showText(i18nc("osd", "Playing"), 1500);
break;
case Paused:
actionPlayPause->setIcon(iconPlay);
actionPlayPause->setText(textPlay);
osdWidget->showText(i18nc("osd", "Paused"), 1500);
break;
}
actionPlayPause->setCheckable(playing);
actionPrevious->setEnabled(playing);
actionStop->setEnabled(playing);
actionNext->setEnabled(playing);
timeButton->setEnabled(playing);
}
void MediaWidget::metadataChanged()
{
QMap metadata = backend->getMetadata();
source->metadataChanged(metadata);
if (source->getType() == MediaSource::Url)
emit playlistTrackMetadataChanged(metadata);
if (source->overrideCaption()) {
emit changeCaption(source->getDefaultCaption());
return;
}
QString caption = metadata.value(Title);
QString artist = metadata.value(Artist);
if (!caption.isEmpty() && !artist.isEmpty()) {
caption += QLatin1Char(' ');
}
if (!artist.isEmpty()) {
caption += QLatin1Char('(');
caption += artist;
caption += QLatin1Char(')');
}
if (caption.isEmpty()) {
caption = source->getDefaultCaption();
}
if (!caption.isEmpty()) {
osdWidget->showText(caption, 2500);
}
emit changeCaption(caption);
}
void MediaWidget::dvdMenuChanged()
{
menuAction->setEnabled(backend->hasDvdMenu());
}
void MediaWidget::titlesChanged()
{
int titleCount = backend->getTitleCount();
int currentTitle = backend->getCurrentTitle();
if (titleCount > 1) {
QList actions = titleGroup->actions();
if (actions.count() < titleCount) {
int i = actions.count();
actions.clear();
for (; i < titleCount; ++i) {
QAction *action = titleGroup->addAction(QString::number(i + 1));
action->setCheckable(true);
titleMenu->addAction(action);
}
actions = titleGroup->actions();
}
for (int i = 0; i < actions.size(); ++i) {
actions.at(i)->setVisible(i < titleCount);
}
if ((currentTitle >= 1) && (currentTitle <= titleGroup->actions().count())) {
titleGroup->actions().at(currentTitle - 1)->setChecked(true);
} else if (titleGroup->checkedAction() != NULL) {
titleGroup->checkedAction()->setChecked(false);
}
titleMenu->setEnabled(true);
} else {
titleMenu->setEnabled(false);
}
}
void MediaWidget::chaptersChanged()
{
int chapterCount = backend->getChapterCount();
int currentChapter = backend->getCurrentChapter();
if (chapterCount > 1) {
QList actions = chapterGroup->actions();
if (actions.count() < chapterCount) {
int i = actions.count();
actions.clear();
for (; i < chapterCount; ++i) {
QAction *action = chapterGroup->addAction(QString::number(i + 1));
action->setCheckable(true);
chapterMenu->addAction(action);
}
actions = chapterGroup->actions();
}
for (int i = 0; i < actions.size(); ++i) {
actions.at(i)->setVisible(i < chapterCount);
}
if ((currentChapter >= 1) && (currentChapter <= chapterGroup->actions().count())) {
chapterGroup->actions().at(currentChapter - 1)->setChecked(true);
} else if (chapterGroup->checkedAction() != NULL) {
chapterGroup->checkedAction()->setChecked(false);
}
chapterMenu->setEnabled(true);
} else {
chapterMenu->setEnabled(false);
}
}
void MediaWidget::anglesChanged()
{
int angleCount = backend->getAngleCount();
int currentAngle = backend->getCurrentAngle();
if (angleCount > 1) {
QList actions = angleGroup->actions();
if (actions.count() < angleCount) {
int i = actions.count();
actions.clear();
for (; i < angleCount; ++i) {
QAction *action = angleGroup->addAction(QString::number(i + 1));
action->setCheckable(true);
angleMenu->addAction(action);
}
actions = angleGroup->actions();
}
for (int i = 0; i < actions.size(); ++i) {
actions.at(i)->setVisible(i < angleCount);
}
if ((currentAngle >= 1) && (currentAngle <= angleGroup->actions().count())) {
angleGroup->actions().at(currentAngle - 1)->setChecked(true);
} else if (angleGroup->checkedAction() != NULL) {
angleGroup->checkedAction()->setChecked(false);
}
angleMenu->setEnabled(true);
} else {
angleMenu->setEnabled(false);
}
}
void MediaWidget::videoSizeChanged()
{
setVideoSize();
}
JumpToPositionDialog::JumpToPositionDialog(MediaWidget *mediaWidget_) : QDialog(mediaWidget_),
mediaWidget(mediaWidget_)
{
setWindowTitle(i18nc("@title:window", "Jump to Position"));
QWidget *widget = new QWidget(this);
QBoxLayout *layout = new QVBoxLayout(widget);
layout->addWidget(new QLabel(i18n("Enter a position:")));
timeEdit = new QTimeEdit(this);
timeEdit->setDisplayFormat(QLatin1String("hh:mm:ss"));
timeEdit->setTime(QTime().addMSecs(mediaWidget->getPosition()));
layout->addWidget(timeEdit);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
timeEdit->setFocus();
QVBoxLayout *mainLayout = new QVBoxLayout;
setLayout(mainLayout);
mainLayout->addWidget(widget);
mainLayout->addWidget(buttonBox);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
}
JumpToPositionDialog::~JumpToPositionDialog()
{
}
void JumpToPositionDialog::accept()
{
mediaWidget->setPosition(QTime(0, 0, 0).msecsTo(timeEdit->time()));
QDialog::accept();
}
void SeekSlider::mousePressEvent(QMouseEvent *event)
{
int buttons = style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons);
Qt::MouseButton button = static_cast(buttons & (~(buttons - 1)));
QMouseEvent modifiedEvent(event->type(), event->pos(), event->globalPos(), button,
event->buttons() ^ event->button() ^ button, event->modifiers());
QSlider::mousePressEvent(&modifiedEvent);
}
diff --git a/src/mediawidget.h b/src/mediawidget.h
index 09002c5..a646ea7 100644
--- a/src/mediawidget.h
+++ b/src/mediawidget.h
@@ -1,300 +1,315 @@
/*
* mediawidget.h
*
* Copyright (C) 2007-2011 Christoph Pfister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MEDIAWIDGET_H
#define MEDIAWIDGET_H
#include
#include
#include
#include
#include
#include
class KActionCollection;
class KToolBar;
class QActionGroup;
class QComboBox;
class QMenu;
class QPushButton;
class QSlider;
class QStringListModel;
class QWidgetAction;
class AbstractMediaWidget;
class MediaSource;
class OsdWidget;
class SeekSlider;
class MediaWidget : public QWidget
{
Q_OBJECT
public:
MediaWidget(QMenu *menu_, QToolBar *toolBar, KActionCollection *collection,
QWidget *parent);
~MediaWidget();
static QString extensionFilter(); // usable for KFileDialog::setFilter()
enum AspectRatio
{
AspectRatioAuto,
AspectRatio1_1,
AspectRatio4_3,
AspectRatio5_4,
AspectRatio16_9,
AspectRatio16_10,
AspectRatio221_100,
AspectRatio235_100,
AspectRatio239_100,
};
+ enum DeinterlaceMode
+ {
+ DeinterlaceDisabled,
+ DeinterlaceDiscard,
+ DeinterlaceBob,
+ DeinterlaceLinear,
+ DeinterlaceYadif,
+ DeinterlaceYadif2x,
+ DeinterlacePhosphor,
+ DeinterlaceX,
+ DeinterlaceMean,
+ DeinterlaceBlend,
+ DeinterlaceIvtc,
+ };
+
enum DisplayMode
{
NormalMode,
FullScreenMode,
FullScreenReturnToMinimalMode,
MinimalMode
};
enum MetadataType
{
Title,
Artist,
Album,
TrackNumber
};
enum PlaybackStatus
{
Idle,
Playing,
Paused
};
DisplayMode getDisplayMode() const;
void setDisplayMode(DisplayMode displayMode_);
/*
* loads the media and starts playback
*/
void play(MediaSource *source_);
void play(const QUrl &url, const QUrl &subtitleUrl = QUrl());
void playAudioCd(const QString &device);
void playVideoCd(const QString &device);
void playDvd(const QString &device);
OsdWidget *getOsdWidget();
PlaybackStatus getPlaybackStatus() const;
int getPosition() const; // milliseconds
int getVolume() const; // 0 - 100
void play(); // (re-)starts the current media
void togglePause();
void setPosition(int position); // milliseconds
void setVolume(int volume); // 0 - 100
void toggleMuted();
void mediaSourceDestroyed(MediaSource *mediaSource);
public slots:
void previous();
void next();
void stop();
void increaseVolume();
void decreaseVolume();
void toggleFullScreen();
void toggleMinimalMode();
void shortSkipBackward();
void shortSkipForward();
void longSkipBackward();
void longSkipForward();
void getAudioDevices();
void openSubtitle();
void setSubtitle(QUrl text);
public:
void playbackFinished();
void playbackStatusChanged();
void currentTotalTimeChanged();
void metadataChanged();
void seekableChanged();
void audioStreamsChanged();
void subtitlesChanged();
void titlesChanged();
void chaptersChanged();
void anglesChanged();
void dvdMenuChanged();
void videoSizeChanged();
signals:
void displayModeChanged();
void changeCaption(const QString &caption);
void resizeToVideo(float resizeFactor);
void playlistPrevious();
void playlistNext();
void playlistUrlsDropped(const QList &urls);
void playlistTrackLengthChanged(int length);
void playlistTrackMetadataChanged(const QMap &metadata);
void osdKeyPressed(int key);
private slots:
void checkScreenSaver();
void setAudioCard();
void mutedChanged();
void volumeChanged(int volume);
void seek(int position);
- void deinterlacingChanged(bool deinterlacing);
+ void deinterlacingChanged(QAction *action);
void aspectRatioChanged(QAction *action);
void setVideoSize();
void autoResizeTriggered(QAction *action);
void pausedChanged(bool paused);
void timeButtonClicked();
void jumpToPosition();
void currentAudioStreamChanged(int currentAudioStream);
void currentSubtitleChanged(int currentSubtitle);
void toggleMenu();
void currentTitleChanged(QAction *action);
void currentChapterChanged(QAction *action);
void currentAngleChanged(QAction *action);
void shortSkipDurationChanged(int shortSkipDuration);
void longSkipDurationChanged(int longSkipDuration);
private:
void contextMenuEvent(QContextMenuEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void keyPressEvent(QKeyEvent *event);
void resizeEvent(QResizeEvent *event);
void wheelEvent(QWheelEvent *event);
QMenu *menu;
AbstractMediaWidget *backend;
OsdWidget *osdWidget;
QWidgetAction *actionPrevious;
QWidgetAction *actionPlayPause;
QString textPlay;
QString textPause;
QIcon iconPlay;
QIcon iconPause;
QWidgetAction *actionStop;
QWidgetAction *actionNext;
QWidgetAction *fullScreenAction;
QWidgetAction *minimalModeAction;
QComboBox *audioStreamBox;
QComboBox *subtitleBox;
QStringListModel *audioStreamModel;
QStringListModel *subtitleModel;
QString textSubtitlesOff;
QWidgetAction *muteAction;
QIcon mutedIcon;
QIcon unmutedIcon;
QSlider *volumeSlider;
SeekSlider *seekSlider;
QWidgetAction *longSkipBackwardAction;
QWidgetAction *shortSkipBackwardAction;
QWidgetAction *shortSkipForwardAction;
QWidgetAction *longSkipForwardAction;
- QWidgetAction *deinterlaceAction;
QWidgetAction *menuAction;
QMenu *audioDevMenu;
QMenu *titleMenu;
QMenu *chapterMenu;
QMenu *angleMenu;
QActionGroup *titleGroup;
QActionGroup *chapterGroup;
QActionGroup *angleGroup;
QMenu *navigationMenu;
QWidgetAction *jumpToPositionAction;
QPushButton *timeButton;
DisplayMode displayMode;
int autoResizeFactor;
+ int deinterlaceMode;
QScopedPointer dummySource;
MediaSource *source;
bool blockBackendUpdates;
bool muted;
bool screenSaverSuspended;
bool showElapsedTime;
};
class MediaSource
{
public:
MediaSource() { }
virtual ~MediaSource()
{
setMediaWidget(NULL);
}
enum Type
{
Url,
AudioCd,
VideoCd,
Dvd,
Dvb
};
virtual Type getType() const { return Url; }
virtual QUrl getUrl() const { return QUrl(); }
virtual void validateCurrentTotalTime(int &, int &) const { }
virtual bool hideCurrentTotalTime() const { return false; }
virtual bool overrideAudioStreams() const { return false; }
virtual bool overrideSubtitles() const { return false; }
virtual QStringList getAudioStreams() const { return QStringList(); }
virtual QStringList getSubtitles() const { return QStringList(); }
virtual int getCurrentAudioStream() const { return -1; }
virtual int getCurrentSubtitle() const { return -1; }
virtual bool overrideCaption() const { return false; }
virtual QString getDefaultCaption() const { return QString(); }
virtual void setCurrentAudioStream(int ) { }
virtual void setCurrentSubtitle(int ) { }
virtual void trackLengthChanged(int ) { }
virtual void metadataChanged(const QMap &) { }
virtual void playbackFinished() { }
virtual void playbackStatusChanged(MediaWidget::PlaybackStatus ) { }
virtual void replay() { }
virtual void previous() { }
virtual void next() { }
void setMediaWidget(const MediaWidget *mediaWidget)
{
MediaWidget *oldMediaWidget = weakMediaWidget.data();
if (mediaWidget != oldMediaWidget) {
if (oldMediaWidget != NULL) {
oldMediaWidget->mediaSourceDestroyed(this);
}
// FIXME:
// weakMediaWidget = mediaWidget;
}
}
private:
QWeakPointer weakMediaWidget;
};
#endif /* MEDIAWIDGET_H */