mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 19:24:08 +00:00
Add QMediaPlayer internal player back end (Qt5 only)
* add config and GUI support for internal player back end switching; * make FFmpeg player disabling option consistent with other similar qmake options by using CONFIG; * add a new qmake option that disables Qt Multimedia player. This is useful for GNU/Linux distributions where Qt WebKit and Qt Multimedia packages depend on different GStreamer versions and don't work correctly when combined in one application. The existing FFmpeg+libao internal player back end has a relatively low-level implementation, which is difficult to understand and improve. There are at least 3 open internal player issues: 1) many GNU/Linux users have to edit their libao configuration file to make Goldendict's internal player work (issue #412); 2) libao's pulseaudio plugin does not support 32-bit audio, which means that many MediaWiki pronunciations don't work with the most popular GNU/Linux audio driver (issue #949); 3) Ffmpeg::DecoderContext uses deprecated FFmpeg APIs, which causes compiler warnings and means that this internal player back end may not compile with a future FFmpeg library version (issue #978). The Qt Multimedia back end implementation uses the highest-level Qt audio API and is very simple. This new back end works flawlessly on my GNU/Linux machine. I'm not making it the default back end because I don't know how well it will work on other platforms with different configurations.
This commit is contained in:
parent
d5998cabb7
commit
9aa3c44d4e
15
README.md
15
README.md
|
@ -28,7 +28,7 @@ This code has been run and tested on Windows XP/Vista/7, Ubuntu Linux, Mac OS X.
|
||||||
qtdeclarative5-dev libqtwebkit-dev libxtst-dev liblzo2-dev libbz2-dev \
|
qtdeclarative5-dev libqtwebkit-dev libxtst-dev liblzo2-dev libbz2-dev \
|
||||||
libao-dev libavutil-dev libavformat-dev libtiff5-dev libeb16-dev \
|
libao-dev libavutil-dev libavformat-dev libtiff5-dev libeb16-dev \
|
||||||
libqt5webkit5-dev libqt5svg5-dev libqt5x11extras5-dev qttools5-dev \
|
libqt5webkit5-dev libqt5svg5-dev libqt5x11extras5-dev qttools5-dev \
|
||||||
qttools5-dev-tools
|
qttools5-dev-tools qtmultimedia5-dev libqt5multimedia5-plugins
|
||||||
|
|
||||||
## How to build
|
## How to build
|
||||||
|
|
||||||
|
@ -82,16 +82,21 @@ If you have problem building with libeb-dev package, you can pass
|
||||||
|
|
||||||
qmake "CONFIG+=no_epwing_support"
|
qmake "CONFIG+=no_epwing_support"
|
||||||
|
|
||||||
### Building without internal audio player
|
### Building without internal audio players
|
||||||
|
|
||||||
If you have problem building with FFmpeg/libao (for example, Ubuntu older than 12.04), you can pass
|
If you have problem building with FFmpeg/libao (for example, Ubuntu older than 12.04), you can pass
|
||||||
`"DISABLE_INTERNAL_PLAYER=1"` to `qmake` in order to disable internal audio player completely:
|
`"CONFIG+=no_ffmpeg_player"` to `qmake` in order to disable FFmpeg+libao internal audio player back end:
|
||||||
|
|
||||||
qmake "DISABLE_INTERNAL_PLAYER=1"
|
qmake "CONFIG+=no_ffmpeg_player"
|
||||||
|
|
||||||
|
If you have problem building with Qt5 Multimedia or experience GStreamer run-time errors (for example, Ubuntu 14.04), you can pass
|
||||||
|
`"CONFIG+=no_qtmultimedia_player"` to `qmake` in order to disable Qt Multimedia internal audio player back end:
|
||||||
|
|
||||||
|
qmake "CONFIG+=no_qtmultimedia_player"
|
||||||
|
|
||||||
<b>NB:</b> All additional settings for `qmake` that you need must be combined in one `qmake` launch, for example:
|
<b>NB:</b> All additional settings for `qmake` that you need must be combined in one `qmake` launch, for example:
|
||||||
|
|
||||||
qmake "CONFIG+=zim_support" "CONFIG+=no_extra_tiff_handler" "DISABLE_INTERNAL_PLAYER=1"
|
qmake "CONFIG+=zim_support" "CONFIG+=no_extra_tiff_handler" "CONFIG+=no_ffmpeg_player"
|
||||||
|
|
||||||
|
|
||||||
Then, invoke `make clean` before `make` because the setting change:
|
Then, invoke `make clean` before `make` because the setting change:
|
||||||
|
|
|
@ -5,11 +5,13 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "audioplayerfactory.hh"
|
#include "audioplayerfactory.hh"
|
||||||
#include "ffmpegaudioplayer.hh"
|
#include "ffmpegaudioplayer.hh"
|
||||||
|
#include "multimediaaudioplayer.hh"
|
||||||
#include "externalaudioplayer.hh"
|
#include "externalaudioplayer.hh"
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
|
|
||||||
AudioPlayerFactory::AudioPlayerFactory( Config::Preferences const & p ) :
|
AudioPlayerFactory::AudioPlayerFactory( Config::Preferences const & p ) :
|
||||||
useInternalPlayer( p.useInternalPlayer ),
|
useInternalPlayer( p.useInternalPlayer ),
|
||||||
|
internalPlayerBackend( p.internalPlayerBackend ),
|
||||||
audioPlaybackProgram( p.audioPlaybackProgram )
|
audioPlaybackProgram( p.audioPlaybackProgram )
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
@ -20,10 +22,17 @@ void AudioPlayerFactory::setPreferences( Config::Preferences const & p )
|
||||||
if( p.useInternalPlayer != useInternalPlayer )
|
if( p.useInternalPlayer != useInternalPlayer )
|
||||||
{
|
{
|
||||||
useInternalPlayer = p.useInternalPlayer;
|
useInternalPlayer = p.useInternalPlayer;
|
||||||
|
internalPlayerBackend = p.internalPlayerBackend;
|
||||||
audioPlaybackProgram = p.audioPlaybackProgram;
|
audioPlaybackProgram = p.audioPlaybackProgram;
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
if( useInternalPlayer && p.internalPlayerBackend != internalPlayerBackend )
|
||||||
|
{
|
||||||
|
internalPlayerBackend = p.internalPlayerBackend;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
if( !useInternalPlayer && p.audioPlaybackProgram != audioPlaybackProgram )
|
if( !useInternalPlayer && p.audioPlaybackProgram != audioPlaybackProgram )
|
||||||
{
|
{
|
||||||
audioPlaybackProgram = p.audioPlaybackProgram;
|
audioPlaybackProgram = p.audioPlaybackProgram;
|
||||||
|
@ -38,16 +47,35 @@ void AudioPlayerFactory::setPreferences( Config::Preferences const & p )
|
||||||
|
|
||||||
void AudioPlayerFactory::reset()
|
void AudioPlayerFactory::reset()
|
||||||
{
|
{
|
||||||
#ifndef DISABLE_INTERNAL_PLAYER
|
|
||||||
if( useInternalPlayer )
|
if( useInternalPlayer )
|
||||||
playerPtr.reset( new Ffmpeg::AudioPlayer );
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
QScopedPointer< ExternalAudioPlayer > externalPlayer( new ExternalAudioPlayer );
|
// qobject_cast checks below account for the case when an unsupported backend
|
||||||
setAudioPlaybackProgram( *externalPlayer );
|
// is stored in config. After this backend is replaced with the default one
|
||||||
playerPtr.reset( externalPlayer.take() );
|
// upon preferences saving, the code below does not reset playerPtr with
|
||||||
|
// another object of the same type.
|
||||||
|
|
||||||
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
Q_ASSERT( Config::InternalPlayerBackend::defaultBackend().isFfmpeg()
|
||||||
|
&& "Adjust the code below after changing the default backend." );
|
||||||
|
|
||||||
|
if( !internalPlayerBackend.isQtmultimedia() )
|
||||||
|
{
|
||||||
|
if( qobject_cast< Ffmpeg::AudioPlayer * >( playerPtr.data() ) == 0 )
|
||||||
|
playerPtr.reset( new Ffmpeg::AudioPlayer );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
if( qobject_cast< MultimediaAudioPlayer * >( playerPtr.data() ) == 0 )
|
||||||
|
playerPtr.reset( new MultimediaAudioPlayer );
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QScopedPointer< ExternalAudioPlayer > externalPlayer( new ExternalAudioPlayer );
|
||||||
|
setAudioPlaybackProgram( *externalPlayer );
|
||||||
|
playerPtr.reset( externalPlayer.take() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioPlayerFactory::setAudioPlaybackProgram( ExternalAudioPlayer & externalPlayer )
|
void AudioPlayerFactory::setAudioPlaybackProgram( ExternalAudioPlayer & externalPlayer )
|
||||||
|
|
|
@ -25,6 +25,7 @@ private:
|
||||||
void setAudioPlaybackProgram( ExternalAudioPlayer & externalPlayer );
|
void setAudioPlaybackProgram( ExternalAudioPlayer & externalPlayer );
|
||||||
|
|
||||||
bool useInternalPlayer;
|
bool useInternalPlayer;
|
||||||
|
Config::InternalPlayerBackend internalPlayerBackend;
|
||||||
QString audioPlaybackProgram;
|
QString audioPlaybackProgram;
|
||||||
AudioPlayerPtr playerPtr;
|
AudioPlayerPtr playerPtr;
|
||||||
};
|
};
|
||||||
|
|
77
config.cc
77
config.cc
|
@ -78,6 +78,56 @@ QKeySequence HotKey::toKeySequence() const
|
||||||
return QKeySequence( key1 | modifiers, v2 );
|
return QKeySequence( key1 | modifiers, v2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InternalPlayerBackend::anyAvailable()
|
||||||
|
{
|
||||||
|
#if defined( MAKE_FFMPEG_PLAYER ) || defined( MAKE_QTMULTIMEDIA_PLAYER )
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalPlayerBackend InternalPlayerBackend::defaultBackend()
|
||||||
|
{
|
||||||
|
#if defined( MAKE_FFMPEG_PLAYER )
|
||||||
|
return ffmpeg();
|
||||||
|
#elif defined( MAKE_QTMULTIMEDIA_PLAYER )
|
||||||
|
return qtmultimedia();
|
||||||
|
#else
|
||||||
|
return InternalPlayerBackend( QString() );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList InternalPlayerBackend::nameList()
|
||||||
|
{
|
||||||
|
QStringList result;
|
||||||
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
result.push_back( ffmpeg().uiName() );
|
||||||
|
#endif
|
||||||
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
result.push_back( qtmultimedia().uiName() );
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InternalPlayerBackend::isFfmpeg() const
|
||||||
|
{
|
||||||
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
return *this == ffmpeg();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InternalPlayerBackend::isQtmultimedia() const
|
||||||
|
{
|
||||||
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
return *this == qtmultimedia();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Preferences::Preferences():
|
Preferences::Preferences():
|
||||||
newTabsOpenAfterCurrentOne( false ),
|
newTabsOpenAfterCurrentOne( false ),
|
||||||
newTabsOpenInBackground( true ),
|
newTabsOpenInBackground( true ),
|
||||||
|
@ -114,11 +164,8 @@ Preferences::Preferences():
|
||||||
#endif
|
#endif
|
||||||
pronounceOnLoadMain( false ),
|
pronounceOnLoadMain( false ),
|
||||||
pronounceOnLoadPopup( false ),
|
pronounceOnLoadPopup( false ),
|
||||||
#ifndef DISABLE_INTERNAL_PLAYER
|
useInternalPlayer( InternalPlayerBackend::anyAvailable() ),
|
||||||
useInternalPlayer( true ),
|
internalPlayerBackend( InternalPlayerBackend::defaultBackend() ),
|
||||||
#else
|
|
||||||
useInternalPlayer( false ),
|
|
||||||
#endif
|
|
||||||
checkForNewReleases( true ),
|
checkForNewReleases( true ),
|
||||||
disallowContentFromOtherSites( false ),
|
disallowContentFromOtherSites( false ),
|
||||||
enableWebPlugins( false ),
|
enableWebPlugins( false ),
|
||||||
|
@ -769,12 +816,16 @@ Class load() throw( exError )
|
||||||
c.preferences.pronounceOnLoadMain = ( preferences.namedItem( "pronounceOnLoadMain" ).toElement().text() == "1" );
|
c.preferences.pronounceOnLoadMain = ( preferences.namedItem( "pronounceOnLoadMain" ).toElement().text() == "1" );
|
||||||
c.preferences.pronounceOnLoadPopup = ( preferences.namedItem( "pronounceOnLoadPopup" ).toElement().text() == "1" );
|
c.preferences.pronounceOnLoadPopup = ( preferences.namedItem( "pronounceOnLoadPopup" ).toElement().text() == "1" );
|
||||||
|
|
||||||
#ifndef DISABLE_INTERNAL_PLAYER
|
if ( InternalPlayerBackend::anyAvailable() )
|
||||||
if ( !preferences.namedItem( "useInternalPlayer" ).isNull() )
|
{
|
||||||
c.preferences.useInternalPlayer = ( preferences.namedItem( "useInternalPlayer" ).toElement().text() == "1" );
|
if ( !preferences.namedItem( "useInternalPlayer" ).isNull() )
|
||||||
#else
|
c.preferences.useInternalPlayer = ( preferences.namedItem( "useInternalPlayer" ).toElement().text() == "1" );
|
||||||
c.preferences.useInternalPlayer = false;
|
}
|
||||||
#endif
|
else
|
||||||
|
c.preferences.useInternalPlayer = false;
|
||||||
|
|
||||||
|
if ( !preferences.namedItem( "internalPlayerBackend" ).isNull() )
|
||||||
|
c.preferences.internalPlayerBackend.setUiName( preferences.namedItem( "internalPlayerBackend" ).toElement().text() );
|
||||||
|
|
||||||
if ( !preferences.namedItem( "audioPlaybackProgram" ).isNull() )
|
if ( !preferences.namedItem( "audioPlaybackProgram" ).isNull() )
|
||||||
c.preferences.audioPlaybackProgram = preferences.namedItem( "audioPlaybackProgram" ).toElement().text();
|
c.preferences.audioPlaybackProgram = preferences.namedItem( "audioPlaybackProgram" ).toElement().text();
|
||||||
|
@ -1660,6 +1711,10 @@ void save( Class const & c ) throw( exError )
|
||||||
opt.appendChild( dd.createTextNode( c.preferences.useInternalPlayer ? "1" : "0" ) );
|
opt.appendChild( dd.createTextNode( c.preferences.useInternalPlayer ? "1" : "0" ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
||||||
|
opt = dd.createElement( "internalPlayerBackend" );
|
||||||
|
opt.appendChild( dd.createTextNode( c.preferences.internalPlayerBackend.uiName() ) );
|
||||||
|
preferences.appendChild( opt );
|
||||||
|
|
||||||
opt = dd.createElement( "audioPlaybackProgram" );
|
opt = dd.createElement( "audioPlaybackProgram" );
|
||||||
opt.appendChild( dd.createTextNode( c.preferences.audioPlaybackProgram ) );
|
opt.appendChild( dd.createTextNode( c.preferences.audioPlaybackProgram ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
49
config.hh
49
config.hh
|
@ -177,6 +177,52 @@ struct FullTextSearch
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This class encapsulates supported backend preprocessor logic,
|
||||||
|
/// discourages duplicating backend names in code, which is error-prone.
|
||||||
|
class InternalPlayerBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Returns true if at least one backend is available.
|
||||||
|
static bool anyAvailable();
|
||||||
|
/// Returns the default backend or null backend if none is available.
|
||||||
|
static InternalPlayerBackend defaultBackend();
|
||||||
|
/// Returns the name list of supported backends.
|
||||||
|
static QStringList nameList();
|
||||||
|
|
||||||
|
/// Returns true if built with FFmpeg player support and the name matches.
|
||||||
|
bool isFfmpeg() const;
|
||||||
|
/// Returns true if built with Qt Multimedia player support and the name matches.
|
||||||
|
bool isQtmultimedia() const;
|
||||||
|
|
||||||
|
QString const & uiName() const
|
||||||
|
{ return name; }
|
||||||
|
|
||||||
|
void setUiName( QString const & name_ )
|
||||||
|
{ name = name_; }
|
||||||
|
|
||||||
|
bool operator == ( InternalPlayerBackend const & other ) const
|
||||||
|
{ return name == other.name; }
|
||||||
|
|
||||||
|
bool operator != ( InternalPlayerBackend const & other ) const
|
||||||
|
{ return ! operator == ( other ); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
static InternalPlayerBackend ffmpeg()
|
||||||
|
{ return InternalPlayerBackend( "FFmpeg+libao" ); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
static InternalPlayerBackend qtmultimedia()
|
||||||
|
{ return InternalPlayerBackend( "Qt Multimedia" ); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
explicit InternalPlayerBackend( QString const & name_ ) : name( name_ )
|
||||||
|
{}
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
/// Various user preferences
|
/// Various user preferences
|
||||||
struct Preferences
|
struct Preferences
|
||||||
{
|
{
|
||||||
|
@ -222,8 +268,9 @@ struct Preferences
|
||||||
|
|
||||||
// Whether the word should be pronounced on page load, in main window/popup
|
// Whether the word should be pronounced on page load, in main window/popup
|
||||||
bool pronounceOnLoadMain, pronounceOnLoadPopup;
|
bool pronounceOnLoadMain, pronounceOnLoadPopup;
|
||||||
QString audioPlaybackProgram;
|
|
||||||
bool useInternalPlayer;
|
bool useInternalPlayer;
|
||||||
|
InternalPlayerBackend internalPlayerBackend;
|
||||||
|
QString audioPlaybackProgram;
|
||||||
|
|
||||||
ProxyServer proxyServer;
|
ProxyServer proxyServer;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef DISABLE_INTERNAL_PLAYER
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
|
||||||
#include "ffmpegaudio.hh"
|
#include "ffmpegaudio.hh"
|
||||||
|
|
||||||
|
@ -589,4 +589,4 @@ void DecoderThread::cancel( bool waitUntilFinished )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //DISABLE_INTERNAL_PLAYER
|
#endif // MAKE_FFMPEG_PLAYER
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __FFMPEGAUDIO_HH_INCLUDED__
|
#ifndef __FFMPEGAUDIO_HH_INCLUDED__
|
||||||
#define __FFMPEGAUDIO_HH_INCLUDED__
|
#define __FFMPEGAUDIO_HH_INCLUDED__
|
||||||
|
|
||||||
#ifndef DISABLE_INTERNAL_PLAYER
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
|
@ -52,6 +52,6 @@ signals:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DISABLE_INTERNAL_PLAYER
|
#endif // MAKE_FFMPEG_PLAYER
|
||||||
|
|
||||||
#endif // __FFMPEGAUDIO_HH_INCLUDED__
|
#endif // __FFMPEGAUDIO_HH_INCLUDED__
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "audioplayerinterface.hh"
|
#include "audioplayerinterface.hh"
|
||||||
#include "ffmpegaudio.hh"
|
#include "ffmpegaudio.hh"
|
||||||
|
|
||||||
#ifndef DISABLE_INTERNAL_PLAYER
|
#ifdef MAKE_FFMPEG_PLAYER
|
||||||
|
|
||||||
namespace Ffmpeg
|
namespace Ffmpeg
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,6 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DISABLE_INTERNAL_PLAYER
|
#endif // MAKE_FFMPEG_PLAYER
|
||||||
|
|
||||||
#endif // FFMPEGAUDIOPLAYER_HH_INCLUDED
|
#endif // FFMPEGAUDIOPLAYER_HH_INCLUDED
|
||||||
|
|
|
@ -28,11 +28,21 @@ greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
webkitwidgets \
|
webkitwidgets \
|
||||||
printsupport \
|
printsupport \
|
||||||
help
|
help
|
||||||
|
|
||||||
|
# QMediaPlayer is not available in Qt4.
|
||||||
|
!CONFIG( no_qtmultimedia_player ) {
|
||||||
|
QT += multimedia
|
||||||
|
DEFINES += MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
QT += webkit
|
QT += webkit
|
||||||
CONFIG += help
|
CONFIG += help
|
||||||
}
|
}
|
||||||
|
|
||||||
|
!CONFIG( no_ffmpeg_player ) {
|
||||||
|
DEFINES += MAKE_FFMPEG_PLAYER
|
||||||
|
}
|
||||||
|
|
||||||
QT += sql
|
QT += sql
|
||||||
CONFIG += exceptions \
|
CONFIG += exceptions \
|
||||||
rtti \
|
rtti \
|
||||||
|
@ -46,8 +56,6 @@ LIBS += \
|
||||||
-lbz2 \
|
-lbz2 \
|
||||||
-llzo2
|
-llzo2
|
||||||
|
|
||||||
!isEmpty(DISABLE_INTERNAL_PLAYER): DEFINES += DISABLE_INTERNAL_PLAYER
|
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
TARGET = GoldenDict
|
TARGET = GoldenDict
|
||||||
|
|
||||||
|
@ -97,7 +105,7 @@ win32 {
|
||||||
LIBS += -lvorbisfile \
|
LIBS += -lvorbisfile \
|
||||||
-lvorbis \
|
-lvorbis \
|
||||||
-logg
|
-logg
|
||||||
isEmpty(DISABLE_INTERNAL_PLAYER) {
|
!CONFIG( no_ffmpeg_player ) {
|
||||||
LIBS += -lao \
|
LIBS += -lao \
|
||||||
-lavutil-gd \
|
-lavutil-gd \
|
||||||
-lavformat-gd \
|
-lavformat-gd \
|
||||||
|
@ -143,7 +151,7 @@ unix:!mac {
|
||||||
vorbis \
|
vorbis \
|
||||||
ogg \
|
ogg \
|
||||||
hunspell
|
hunspell
|
||||||
isEmpty(DISABLE_INTERNAL_PLAYER) {
|
!CONFIG( no_ffmpeg_player ) {
|
||||||
PKGCONFIG += ao \
|
PKGCONFIG += ao \
|
||||||
libavutil \
|
libavutil \
|
||||||
libavformat \
|
libavformat \
|
||||||
|
@ -193,7 +201,7 @@ mac {
|
||||||
-logg \
|
-logg \
|
||||||
-lhunspell-1.6.1 \
|
-lhunspell-1.6.1 \
|
||||||
-llzo2
|
-llzo2
|
||||||
isEmpty(DISABLE_INTERNAL_PLAYER) {
|
!CONFIG( no_ffmpeg_player ) {
|
||||||
LIBS += -lao \
|
LIBS += -lao \
|
||||||
-lavutil-gd \
|
-lavutil-gd \
|
||||||
-lavformat-gd \
|
-lavformat-gd \
|
||||||
|
@ -267,6 +275,7 @@ HEADERS += folding.hh \
|
||||||
audioplayerinterface.hh \
|
audioplayerinterface.hh \
|
||||||
audioplayerfactory.hh \
|
audioplayerfactory.hh \
|
||||||
ffmpegaudioplayer.hh \
|
ffmpegaudioplayer.hh \
|
||||||
|
multimediaaudioplayer.hh \
|
||||||
externalaudioplayer.hh \
|
externalaudioplayer.hh \
|
||||||
externalviewer.hh \
|
externalviewer.hh \
|
||||||
wordfinder.hh \
|
wordfinder.hh \
|
||||||
|
@ -399,6 +408,7 @@ SOURCES += folding.cc \
|
||||||
scanpopup.cc \
|
scanpopup.cc \
|
||||||
articleview.cc \
|
articleview.cc \
|
||||||
audioplayerfactory.cc \
|
audioplayerfactory.cc \
|
||||||
|
multimediaaudioplayer.cc \
|
||||||
externalaudioplayer.cc \
|
externalaudioplayer.cc \
|
||||||
externalviewer.cc \
|
externalviewer.cc \
|
||||||
wordfinder.cc \
|
wordfinder.cc \
|
||||||
|
|
43
multimediaaudioplayer.cc
Normal file
43
multimediaaudioplayer.cc
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* This file is (c) 2018 Igor Kushnir <igorkuo@gmail.com>
|
||||||
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||||
|
|
||||||
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QMediaContent>
|
||||||
|
#include "multimediaaudioplayer.hh"
|
||||||
|
|
||||||
|
MultimediaAudioPlayer::MultimediaAudioPlayer() :
|
||||||
|
player( 0, QMediaPlayer::StreamPlayback )
|
||||||
|
{
|
||||||
|
typedef void( QMediaPlayer::* ErrorSignal )( QMediaPlayer::Error );
|
||||||
|
connect( &player, static_cast< ErrorSignal >( &QMediaPlayer::error ),
|
||||||
|
this, &MultimediaAudioPlayer::onMediaPlayerError );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MultimediaAudioPlayer::play( const char * data, int size )
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
|
||||||
|
audioBuffer.setData( data, size );
|
||||||
|
if( !audioBuffer.open( QIODevice::ReadOnly ) )
|
||||||
|
return tr( "Couldn't open audio buffer for reading." );
|
||||||
|
|
||||||
|
player.setMedia( QMediaContent(), &audioBuffer );
|
||||||
|
player.play();
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultimediaAudioPlayer::stop()
|
||||||
|
{
|
||||||
|
player.setMedia( QMediaContent() ); // Forget about audioBuffer.
|
||||||
|
audioBuffer.close();
|
||||||
|
audioBuffer.setData( QByteArray() ); // Free memory.
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultimediaAudioPlayer::onMediaPlayerError()
|
||||||
|
{
|
||||||
|
emit error( player.errorString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MAKE_QTMULTIMEDIA_PLAYER
|
32
multimediaaudioplayer.hh
Normal file
32
multimediaaudioplayer.hh
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/* This file is (c) 2018 Igor Kushnir <igorkuo@gmail.com>
|
||||||
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||||
|
|
||||||
|
#ifndef MULTIMEDIAAUDIOPLAYER_HH_INCLUDED
|
||||||
|
#define MULTIMEDIAAUDIOPLAYER_HH_INCLUDED
|
||||||
|
|
||||||
|
#ifdef MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QMediaPlayer>
|
||||||
|
#include "audioplayerinterface.hh"
|
||||||
|
|
||||||
|
class MultimediaAudioPlayer : public AudioPlayerInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MultimediaAudioPlayer();
|
||||||
|
|
||||||
|
virtual QString play( const char * data, int size );
|
||||||
|
virtual void stop();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onMediaPlayerError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QBuffer audioBuffer;
|
||||||
|
QMediaPlayer player; ///< Depends on audioBuffer.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAKE_QTMULTIMEDIA_PLAYER
|
||||||
|
|
||||||
|
#endif // MULTIMEDIAAUDIOPLAYER_HH_INCLUDED
|
|
@ -243,14 +243,28 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
||||||
ui.pronounceOnLoadMain->setChecked( p.pronounceOnLoadMain );
|
ui.pronounceOnLoadMain->setChecked( p.pronounceOnLoadMain );
|
||||||
ui.pronounceOnLoadPopup->setChecked( p.pronounceOnLoadPopup );
|
ui.pronounceOnLoadPopup->setChecked( p.pronounceOnLoadPopup );
|
||||||
|
|
||||||
#ifdef DISABLE_INTERNAL_PLAYER
|
ui.internalPlayerBackend->addItems( Config::InternalPlayerBackend::nameList() );
|
||||||
ui.useInternalPlayer->hide();
|
|
||||||
#else
|
// Make sure that exactly one radio button in the group is checked and that
|
||||||
if ( p.useInternalPlayer )
|
// on_useExternalPlayer_toggled() is called.
|
||||||
ui.useInternalPlayer->setChecked( true );
|
ui.useExternalPlayer->setChecked( true );
|
||||||
|
|
||||||
|
if( ui.internalPlayerBackend->count() > 0 )
|
||||||
|
{
|
||||||
|
// Checking ui.useInternalPlayer automatically unchecks ui.useExternalPlayer.
|
||||||
|
ui.useInternalPlayer->setChecked( p.useInternalPlayer );
|
||||||
|
|
||||||
|
int index = ui.internalPlayerBackend->findText( p.internalPlayerBackend.uiName() );
|
||||||
|
if( index < 0 ) // The specified backend is unavailable.
|
||||||
|
index = ui.internalPlayerBackend->findText( Config::InternalPlayerBackend::defaultBackend().uiName() );
|
||||||
|
Q_ASSERT( index >= 0 && "Logic error: the default backend must be present in the backend name list." );
|
||||||
|
ui.internalPlayerBackend->setCurrentIndex( index );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
{
|
||||||
ui.useExternalPlayer->setChecked( true );
|
ui.useInternalPlayer->hide();
|
||||||
|
ui.internalPlayerBackend->hide();
|
||||||
|
}
|
||||||
|
|
||||||
ui.audioPlaybackProgram->setText( p.audioPlaybackProgram );
|
ui.audioPlaybackProgram->setText( p.audioPlaybackProgram );
|
||||||
|
|
||||||
|
@ -400,6 +414,7 @@ Config::Preferences Preferences::getPreferences()
|
||||||
p.pronounceOnLoadMain = ui.pronounceOnLoadMain->isChecked();
|
p.pronounceOnLoadMain = ui.pronounceOnLoadMain->isChecked();
|
||||||
p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked();
|
p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked();
|
||||||
p.useInternalPlayer = ui.useInternalPlayer->isChecked();
|
p.useInternalPlayer = ui.useInternalPlayer->isChecked();
|
||||||
|
p.internalPlayerBackend.setUiName( ui.internalPlayerBackend->currentText() );
|
||||||
p.audioPlaybackProgram = ui.audioPlaybackProgram->text();
|
p.audioPlaybackProgram = ui.audioPlaybackProgram->text();
|
||||||
|
|
||||||
p.proxyServer.enabled = ui.useProxyServer->isChecked();
|
p.proxyServer.enabled = ui.useProxyServer->isChecked();
|
||||||
|
@ -592,6 +607,7 @@ void Preferences::on_buttonBox_accepted()
|
||||||
|
|
||||||
void Preferences::on_useExternalPlayer_toggled( bool enabled )
|
void Preferences::on_useExternalPlayer_toggled( bool enabled )
|
||||||
{
|
{
|
||||||
|
ui.internalPlayerBackend->setEnabled( !enabled );
|
||||||
ui.audioPlaybackProgram->setEnabled( enabled );
|
ui.audioPlaybackProgram->setEnabled( enabled );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -902,37 +902,43 @@ p, li { white-space: pre-wrap; }
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Playback</string>
|
<string>Playback</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
<layout class="QGridLayout" name="gridLayout_audioPlayer">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="QRadioButton" name="useInternalPlayer">
|
<widget class="QRadioButton" name="useInternalPlayer">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Play audio files via FFmpeg(libav) and libao</string>
|
<string>Play audio files via built-in audio support</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Use internal player</string>
|
<string>Use internal player:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
<widget class="QComboBox" name="internalPlayerBackend">
|
||||||
<item>
|
<property name="toolTip">
|
||||||
<widget class="QRadioButton" name="useExternalPlayer">
|
<string>Choose audio back end</string>
|
||||||
<property name="toolTip">
|
</property>
|
||||||
<string>Use any external program to play audio files</string>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
<property name="text">
|
<item row="1" column="0">
|
||||||
<string>Use external program:</string>
|
<widget class="QRadioButton" name="useExternalPlayer">
|
||||||
</property>
|
<property name="toolTip">
|
||||||
</widget>
|
<string>Use any external program to play audio files</string>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLineEdit" name="audioPlaybackProgram">
|
<string>Use external program:</string>
|
||||||
<property name="enabled">
|
</property>
|
||||||
<bool>false</bool>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
</widget>
|
<item row="1" column="1">
|
||||||
</item>
|
<widget class="QLineEdit" name="audioPlaybackProgram">
|
||||||
</layout>
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Enter audio player command line</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
Loading…
Reference in a new issue