You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2568 lines
92 KiB
2568 lines
92 KiB
/* This file is part of the KDE project
|
|
*
|
|
* Copyright (C) 2003 Koos Vriezen <koos.vriezen@xs4all.nl>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
#include <math.h>
|
|
#include <config.h>
|
|
#include <tqstring.h>
|
|
#include <tqfile.h>
|
|
#include <tqfileinfo.h>
|
|
#include <tqtimer.h>
|
|
#include <tqlayout.h>
|
|
#include <tqtable.h>
|
|
#include <tqlineedit.h>
|
|
#include <tqslider.h>
|
|
#include <tqcombobox.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tqspinbox.h>
|
|
#include <tqlabel.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <dcopobject.h>
|
|
#include <dcopclient.h>
|
|
#include <kprocess.h>
|
|
#include <kdebug.h>
|
|
#include <kprocctrl.h>
|
|
#include <tdeprotocolmanager.h>
|
|
#include <tdefiledialog.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tdelocale.h>
|
|
#include <tdeapplication.h>
|
|
#include <kstandarddirs.h>
|
|
#include <tdeio/job.h>
|
|
|
|
#ifdef HAVE_DBUS
|
|
# include <kstaticdeleter.h>
|
|
# include <dbus/connection.h>
|
|
#endif
|
|
|
|
#include "kmplayerview.h"
|
|
#include "kmplayercontrolpanel.h"
|
|
#include "kmplayerprocess.h"
|
|
#include "kmplayersource.h"
|
|
#include "kmplayerconfig.h"
|
|
#include "kmplayer_callback.h"
|
|
#include "kmplayer_backend_stub.h"
|
|
|
|
using namespace KMPlayer;
|
|
|
|
static const char * default_supported [] = { 0L };
|
|
|
|
static TQString getPath (const KURL & url) {
|
|
TQString p = KURL::decode_string (url.url ());
|
|
if (p.startsWith (TQString ("file:/"))) {
|
|
p = p.mid (5);
|
|
unsigned int i = 0;
|
|
for (; i < p.length () && p[i] == TQChar ('/'); ++i)
|
|
;
|
|
//kdDebug () << "getPath " << p.mid (i-1) << endl;
|
|
if (i > 0)
|
|
return p.mid (i-1);
|
|
return TQString (TQChar ('/') + p);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
Process::Process (TQObject * parent, Settings * settings, const char * n)
|
|
: TQObject (parent, n), m_source (0L), m_settings (settings),
|
|
m_state (NotRunning), m_old_state (NotRunning), m_process (0L), m_job(0L),
|
|
m_supported_sources (default_supported), m_viewer (0L) {}
|
|
|
|
Process::~Process () {
|
|
stop ();
|
|
delete m_process;
|
|
}
|
|
|
|
void Process::init () {
|
|
}
|
|
|
|
TQString Process::menuName () const {
|
|
return TQString (className ());
|
|
}
|
|
|
|
void Process::initProcess (Viewer * viewer) {
|
|
m_viewer = viewer;
|
|
delete m_process;
|
|
m_process = new TDEProcess;
|
|
m_process->setUseShell (true);
|
|
m_process->setEnvironment (TQString::fromLatin1 ("SESSION_MANAGER"), TQString::fromLatin1 (""));
|
|
if (m_source) m_source->setPosition (0);
|
|
}
|
|
|
|
WId Process::widget () {
|
|
return 0;
|
|
}
|
|
|
|
bool Process::playing () const {
|
|
return m_process && m_process->isRunning ();
|
|
}
|
|
|
|
void Process::setAudioLang (int, const TQString &) {}
|
|
|
|
void Process::setSubtitle (int, const TQString &) {}
|
|
|
|
bool Process::pause () {
|
|
return false;
|
|
}
|
|
|
|
bool Process::seek (int /*pos*/, bool /*absolute*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::volume (int /*pos*/, bool /*absolute*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::saturation (int /*pos*/, bool /*absolute*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::hue (int /*pos*/, bool /*absolute*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::contrast (int /*pos*/, bool /*absolute*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::brightness (int /*pos*/, bool /*absolute*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::grabPicture (const KURL & /*url*/, int /*pos*/) {
|
|
return false;
|
|
}
|
|
|
|
bool Process::supports (const char * source) const {
|
|
for (const char ** s = m_supported_sources; s[0]; ++s) {
|
|
if (!strcmp (s[0], source))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Process::stop () {
|
|
if (!playing ())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Process::quit () {
|
|
while (playing ()) {
|
|
if (m_source && !m_source->pipeCmd ().isEmpty ()) {
|
|
void (*oldhandler)(int) = signal(SIGTERM, SIG_IGN);
|
|
::kill (-1 * ::getpid (), SIGTERM);
|
|
signal(SIGTERM, oldhandler);
|
|
} else
|
|
m_process->kill (SIGTERM);
|
|
TDEProcessController::theTDEProcessController->waitForProcessExit (1);
|
|
if (!m_process->isRunning ())
|
|
break;
|
|
m_process->kill (SIGKILL);
|
|
TDEProcessController::theTDEProcessController->waitForProcessExit (1);
|
|
if (m_process->isRunning ()) {
|
|
KMessageBox::error (viewer (), i18n ("Failed to end player process."), i18n ("Error"));
|
|
}
|
|
break;
|
|
}
|
|
setState (NotRunning);
|
|
return !playing ();
|
|
}
|
|
|
|
void Process::setState (State newstate) {
|
|
if (m_state != newstate) {
|
|
bool need_timer = m_old_state == m_state;
|
|
m_old_state = m_state;
|
|
m_state = newstate;
|
|
if (need_timer && m_source)
|
|
TQTimer::singleShot (0, this, TQT_SLOT (rescheduledStateChanged ()));
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void Process::rescheduledStateChanged () {
|
|
State old_state = m_old_state;
|
|
m_old_state = m_state;
|
|
m_source->stateChange (this, old_state, m_state);
|
|
}
|
|
|
|
bool Process::play (Source * src, NodePtr _mrl) {
|
|
m_source = src;
|
|
m_mrl = _mrl;
|
|
Mrl * m = _mrl ? _mrl->mrl () : 0L;
|
|
TQString url = m ? m->absolutePath () : TQString ();
|
|
bool changed = m_url != url;
|
|
m_url = url;
|
|
#if KDE_IS_VERSION(3,3,91)
|
|
if (!changed || KURL (m_url).isLocalFile ())
|
|
return deMediafiedPlay ();
|
|
m_url = url;
|
|
m_job = TDEIO::stat (m_url, false);
|
|
connect(m_job, TQT_SIGNAL (result(TDEIO::Job *)), this, TQT_SLOT(result(TDEIO::Job *)));
|
|
return true;
|
|
#else
|
|
return deMediafiedPlay ();
|
|
#endif
|
|
}
|
|
|
|
bool Process::deMediafiedPlay () {
|
|
return false;
|
|
}
|
|
|
|
void Process::result (TDEIO::Job * job) {
|
|
#if KDE_IS_VERSION(3,3,91)
|
|
TDEIO::UDSEntry entry = static_cast <TDEIO::StatJob *> (job)->statResult ();
|
|
TDEIO::UDSEntry::iterator e = entry.end ();
|
|
for (TDEIO::UDSEntry::iterator it = entry.begin (); it != e; ++it)
|
|
if ((*it).m_uds == TDEIO::UDS_LOCAL_PATH) {
|
|
m_url = KURL::fromPathOrURL ((*it).m_str).url ();
|
|
break;
|
|
}
|
|
m_job = 0L;
|
|
deMediafiedPlay ();
|
|
#endif
|
|
}
|
|
|
|
void Process::terminateJobs () {
|
|
if (m_job) {
|
|
m_job->kill ();
|
|
m_job = 0L;
|
|
}
|
|
}
|
|
|
|
bool Process::ready (Viewer * viewer) {
|
|
m_viewer = viewer;
|
|
setState (Ready);
|
|
return true;
|
|
}
|
|
|
|
Viewer * Process::viewer () const {
|
|
return (m_viewer ? (Viewer*)m_viewer :
|
|
(m_settings->defaultView() ? m_settings->defaultView()->viewer() : 0L));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static bool proxyForURL (const KURL& url, TQString& proxy) {
|
|
KProtocolManager::slaveProtocol (url, proxy);
|
|
return !proxy.isNull ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayerBase::MPlayerBase (TQObject * parent, Settings * settings, const char * n)
|
|
: Process (parent, settings, n), m_use_slave (true) {
|
|
m_process = new TDEProcess;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayerBase::~MPlayerBase () {
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerBase::initProcess (Viewer * viewer) {
|
|
Process::initProcess (viewer);
|
|
const KURL & url (m_source->url ());
|
|
if (!url.isEmpty ()) {
|
|
TQString proxy_url;
|
|
if (KProtocolManager::useProxy () && proxyForURL (url, proxy_url))
|
|
m_process->setEnvironment("http_proxy", proxy_url);
|
|
}
|
|
connect (m_process, TQT_SIGNAL (wroteStdin (TDEProcess *)),
|
|
this, TQT_SLOT (dataWritten (TDEProcess *)));
|
|
connect (m_process, TQT_SIGNAL (processExited (TDEProcess *)),
|
|
this, TQT_SLOT (processStopped (TDEProcess *)));
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayerBase::sendCommand (const TQString & cmd) {
|
|
if (playing () && m_use_slave) {
|
|
commands.push_front (cmd + '\n');
|
|
fprintf (stderr, "eval %s", commands.last ().latin1 ());
|
|
if (commands.size () < 2)
|
|
m_process->writeStdin (TQFile::encodeName(commands.last ()),
|
|
commands.last ().length ());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayerBase::stop () {
|
|
terminateJobs ();
|
|
if (!m_source || !m_process || !m_process->isRunning ())
|
|
return true;
|
|
return true;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayerBase::quit () {
|
|
if (playing ()) {
|
|
stop ();
|
|
disconnect (m_process, TQT_SIGNAL (processExited (TDEProcess *)),
|
|
this, TQT_SLOT (processStopped (TDEProcess *)));
|
|
if (!m_use_slave) {
|
|
void (*oldhandler)(int) = signal(SIGTERM, SIG_IGN);
|
|
::kill (-1 * ::getpid (), SIGTERM);
|
|
signal(SIGTERM, oldhandler);
|
|
}
|
|
#if KDE_IS_VERSION(3, 1, 90)
|
|
m_process->wait(2);
|
|
#else
|
|
TQTime t;
|
|
t.start ();
|
|
do {
|
|
TDEProcessController::theTDEProcessController->waitForProcessExit (2);
|
|
} while (t.elapsed () < 2000 && m_process->isRunning ());
|
|
#endif
|
|
if (m_process->isRunning ())
|
|
Process::quit ();
|
|
processStopped (0L);
|
|
commands.clear ();
|
|
}
|
|
return Process::quit ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerBase::dataWritten (TDEProcess *) {
|
|
if (!commands.size ()) return;
|
|
kdDebug() << "eval done " << commands.last () << endl;
|
|
commands.pop_back ();
|
|
if (commands.size ())
|
|
m_process->writeStdin (TQFile::encodeName(commands.last ()),
|
|
commands.last ().length ());
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerBase::processStopped (TDEProcess *) {
|
|
kdDebug() << "process stopped" << endl;
|
|
commands.clear ();
|
|
setState (Ready);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static const char * mplayer_supports [] = {
|
|
"dvdsource", "exitsource", "hrefsource", "introsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L
|
|
};
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayer::MPlayer (TQObject * parent, Settings * settings)
|
|
: MPlayerBase (parent, settings, "mplayer"),
|
|
m_widget (0L),
|
|
m_configpage (new MPlayerPreferencesPage (this)),
|
|
aid (-1), sid (-1),
|
|
m_needs_restarted (false) {
|
|
m_supported_sources = mplayer_supports;
|
|
m_settings->addPage (m_configpage);
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayer::~MPlayer () {
|
|
if (m_widget && !m_widget->parent ())
|
|
delete m_widget;
|
|
delete m_configpage;
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayer::init () {
|
|
}
|
|
|
|
TQString MPlayer::menuName () const {
|
|
return i18n ("&MPlayer");
|
|
}
|
|
|
|
KDE_NO_EXPORT WId MPlayer::widget () {
|
|
return viewer ()->embeddedWinId ();
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::ready (Viewer * viewer) {
|
|
Process::ready (viewer);
|
|
viewer->changeProtocol (QXEmbed::XPLAIN);
|
|
return false;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::deMediafiedPlay () {
|
|
if (playing ())
|
|
return sendCommand (TQString ("gui_play"));
|
|
if (!m_needs_restarted && playing ())
|
|
quit (); // rescheduling of setState will reset state just-in-time
|
|
initProcess (viewer ());
|
|
m_source->setPosition (0);
|
|
if (!m_needs_restarted) {
|
|
aid = sid = -1;
|
|
} else
|
|
m_needs_restarted = false;
|
|
alanglist = 0L;
|
|
slanglist = 0L;
|
|
m_request_seek = -1;
|
|
TQString args = m_source->options () + ' ';
|
|
KURL url (m_url);
|
|
if (!url.isEmpty ()) {
|
|
if (m_source->url ().isLocalFile ())
|
|
m_process->setWorkingDirectory
|
|
(TQFileInfo (m_source->url ().path ()).dirPath (true));
|
|
if (url.isLocalFile ()) {
|
|
m_url = getPath (url);
|
|
if (m_configpage->alwaysbuildindex &&
|
|
(m_url.lower ().endsWith (".avi") ||
|
|
m_url.lower ().endsWith (".divx")))
|
|
args += TQString (" -idx ");
|
|
} else {
|
|
int cache = m_configpage->cachesize;
|
|
if (cache > 3 && !url.url ().startsWith (TQString ("dvd")) &&
|
|
!url.url ().startsWith (TQString ("vcd")) &&
|
|
!url.url ().startsWith (TQString ("tv://")))
|
|
args += TQString ("-cache %1 ").arg (cache);
|
|
if (m_url.startsWith (TQString ("cdda:/")) &&
|
|
!m_url.startsWith (TQString ("cdda://")))
|
|
m_url = TQString ("cdda://") + m_url.mid (6);
|
|
}
|
|
if (url.protocol () != TQString ("stdin"))
|
|
args += TDEProcess::quote (TQString (TQFile::encodeName (m_url)));
|
|
}
|
|
m_tmpURL.truncate (0);
|
|
if (!m_source->identified () && !m_settings->mplayerpost090) {
|
|
args += TQString (" -quiet -nocache -identify -frames 0 ");
|
|
} else {
|
|
if (m_mrl->mrl ()->repeat > 0)
|
|
args += TQString(" -loop " +TQString::number(m_mrl->mrl()->repeat+1));
|
|
else if (m_settings->loop)
|
|
args += TQString (" -loop 0");
|
|
if (m_settings->mplayerpost090)
|
|
args += TQString (" -identify");
|
|
if (!m_source->subUrl ().isEmpty ()) {
|
|
args += TQString (" -sub ");
|
|
const KURL & sub_url (m_source->subUrl ());
|
|
if (!sub_url.isEmpty ()) {
|
|
TQString myurl (sub_url.isLocalFile () ? getPath (sub_url) : sub_url.url ());
|
|
args += TDEProcess::quote (TQString (TQFile::encodeName (myurl)));
|
|
}
|
|
}
|
|
}
|
|
return run (args.ascii (), m_source->pipeCmd ().ascii ());
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::stop () {
|
|
terminateJobs ();
|
|
if (!m_source || !m_process || !m_process->isRunning ()) return true;
|
|
if (m_use_slave)
|
|
sendCommand (TQString ("quit"));
|
|
return MPlayerBase::stop ();
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::pause () {
|
|
return sendCommand (TQString ("pause"));
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::seek (int pos, bool absolute) {
|
|
if (!m_source || !m_source->hasLength () ||
|
|
(absolute && m_source->position () == pos))
|
|
return false;
|
|
if (m_request_seek >= 0 && commands.size () > 1) {
|
|
TQStringList::iterator i = commands.begin ();
|
|
TQStringList::iterator end ( commands.end () );
|
|
for (++i; i != end; ++i)
|
|
if ((*i).startsWith (TQString ("seek"))) {
|
|
i = commands.erase (i);
|
|
m_request_seek = -1;
|
|
break;
|
|
}
|
|
}
|
|
if (m_request_seek >= 0) {
|
|
//m_request_seek = pos;
|
|
return false;
|
|
}
|
|
m_request_seek = pos;
|
|
TQString cmd;
|
|
cmd.sprintf ("seek %d %d", pos/10, absolute ? 2 : 0);
|
|
if (!absolute)
|
|
pos = m_source->position () + pos;
|
|
m_source->setPosition (pos);
|
|
return sendCommand (cmd);
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::volume (int incdec, bool absolute) {
|
|
if (absolute)
|
|
incdec -= old_volume;
|
|
if (incdec == 0)
|
|
return true;
|
|
old_volume += incdec;
|
|
return sendCommand (TQString ("volume ") + TQString::number (incdec));
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::saturation (int val, bool absolute) {
|
|
TQString cmd;
|
|
cmd.sprintf ("saturation %d %d", val, absolute ? 1 : 0);
|
|
return sendCommand (cmd);
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::hue (int val, bool absolute) {
|
|
TQString cmd;
|
|
cmd.sprintf ("hue %d %d", val, absolute ? 1 : 0);
|
|
return sendCommand (cmd);
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::contrast (int val, bool /*absolute*/) {
|
|
TQString cmd;
|
|
cmd.sprintf ("contrast %d 1", val);
|
|
return sendCommand (cmd);
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::brightness (int val, bool /*absolute*/) {
|
|
TQString cmd;
|
|
cmd.sprintf ("brightness %d 1", val);
|
|
return sendCommand (cmd);
|
|
}
|
|
|
|
bool MPlayer::run (const char * args, const char * pipe) {
|
|
//m_view->consoleOutput ()->clear ();
|
|
m_process_output = TQString ();
|
|
connect (m_process, TQT_SIGNAL (receivedStdout (TDEProcess *, char *, int)),
|
|
this, TQT_SLOT (processOutput (TDEProcess *, char *, int)));
|
|
connect (m_process, TQT_SIGNAL (receivedStderr (TDEProcess *, char *, int)),
|
|
this, TQT_SLOT (processOutput (TDEProcess *, char *, int)));
|
|
m_use_slave = !(pipe && pipe[0]);
|
|
if (!m_use_slave) {
|
|
fprintf (stderr, "%s | ", pipe);
|
|
*m_process << pipe << " | ";
|
|
}
|
|
TQString exe = m_configpage->mplayer_path;
|
|
if (exe.isEmpty ())
|
|
exe = "mplayer";
|
|
fprintf (stderr, "%s -wid %lu ", exe.ascii(), (unsigned long) widget ());
|
|
*m_process << exe << " -wid " << TQString::number (widget ());
|
|
|
|
if (m_use_slave) {
|
|
fprintf (stderr, "-slave ");
|
|
*m_process << "-slave ";
|
|
}
|
|
|
|
TQString strVideoDriver = TQString (m_settings->videodrivers[m_settings->videodriver].driver);
|
|
if (!strVideoDriver.isEmpty ()) {
|
|
fprintf (stderr, " -vo %s", strVideoDriver.lower().ascii());
|
|
*m_process << " -vo " << strVideoDriver.lower();
|
|
if (viewer ()->view ()->keepSizeRatio () &&
|
|
strVideoDriver.lower() == TQString::fromLatin1 ("x11")) {
|
|
fprintf (stderr, " -zoom");
|
|
*m_process << " -zoom";
|
|
}
|
|
}
|
|
TQString strAudioDriver = TQString (m_settings->audiodrivers[m_settings->audiodriver].driver);
|
|
if (!strAudioDriver.isEmpty ()) {
|
|
fprintf (stderr, " -ao %s", strAudioDriver.lower().ascii());
|
|
*m_process << " -ao " << strAudioDriver.lower();
|
|
}
|
|
if (m_settings->framedrop) {
|
|
fprintf (stderr, " -framedrop");
|
|
*m_process << " -framedrop";
|
|
}
|
|
|
|
if (m_configpage->additionalarguments.length () > 0) {
|
|
fprintf (stderr, " %s", m_configpage->additionalarguments.ascii());
|
|
*m_process << " " << m_configpage->additionalarguments;
|
|
}
|
|
// postproc thingies
|
|
|
|
fprintf (stderr, " %s", m_source->filterOptions ().ascii ());
|
|
*m_process << " " << m_source->filterOptions ();
|
|
|
|
if (m_settings->autoadjustcolors) {
|
|
fprintf (stderr, " -contrast %d", m_settings->contrast);
|
|
*m_process << " -contrast " << TQString::number (m_settings->contrast);
|
|
|
|
fprintf (stderr, " -brightness %d", m_settings->brightness);
|
|
*m_process << " -brightness " <<TQString::number(m_settings->brightness);
|
|
|
|
fprintf (stderr, " -hue %d", m_settings->hue);
|
|
*m_process << " -hue " << TQString::number (m_settings->hue);
|
|
|
|
fprintf (stderr, " -saturation %d", m_settings->saturation);
|
|
*m_process << " -saturation " <<TQString::number(m_settings->saturation);
|
|
}
|
|
if (aid > -1) {
|
|
fprintf (stderr, " -aid %d", aid);
|
|
*m_process << " -aid " << TQString::number (aid);
|
|
}
|
|
|
|
if (sid > -1) {
|
|
fprintf (stderr, " -sid %d", sid);
|
|
*m_process << " -sid " << TQString::number (sid);
|
|
}
|
|
for (NodePtr n = m_mrl; n; n = n->parentNode ()) {
|
|
if (n->id != id_node_group_node && n->id != id_node_playlist_item)
|
|
break;
|
|
TQString plops = convertNode <Element> (n)->getAttribute ("mplayeropts");
|
|
if (!plops.isNull ()) {
|
|
TQStringList sl = TQStringList::split (TQChar (' '), plops);
|
|
for (int i = 0; i < sl.size (); ++i) {
|
|
TQString plop = TDEProcess::quote (sl[i]);
|
|
fprintf (stderr, " %s", plop.ascii ());
|
|
*m_process << " " << plop;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
fprintf (stderr, " %s\n", args);
|
|
*m_process << " " << args;
|
|
|
|
TQValueList<TQCString>::const_iterator it;
|
|
TQString sMPArgs;
|
|
TQValueList<TQCString>::const_iterator end( m_process->args().end() );
|
|
for ( it = m_process->args().begin(); it != end; ++it ){
|
|
sMPArgs += (*it);
|
|
}
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::All);
|
|
|
|
old_volume = viewer ()->view ()->controlPanel ()->volumeBar ()->value ();
|
|
|
|
if (m_process->isRunning ()) {
|
|
setState (Buffering); // wait for start regexp for state Playing
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayer::grabPicture (const KURL & url, int pos) {
|
|
stop ();
|
|
initProcess (viewer ());
|
|
TQString outdir = locateLocal ("data", "kmplayer/");
|
|
m_grabfile = outdir + TQString ("00000001.jpg");
|
|
unlink (m_grabfile.ascii ());
|
|
TQString myurl (url.isLocalFile () ? getPath (url) : url.url ());
|
|
TQString args ("mplayer ");
|
|
if (m_settings->mplayerpost090)
|
|
args += "-vo jpeg:outdir=";
|
|
else
|
|
args += "-vo jpeg -jpeg outdir=";
|
|
args += TDEProcess::quote (outdir);
|
|
args += TQString (" -frames 1 -nosound -quiet ");
|
|
if (pos > 0)
|
|
args += TQString ("-ss %1 ").arg (pos);
|
|
args += TDEProcess::quote (TQString (TQFile::encodeName (myurl)));
|
|
*m_process << args;
|
|
kdDebug () << args << endl;
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::NoCommunication);
|
|
return m_process->isRunning ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayer::processOutput (TDEProcess *, char * str, int slen) {
|
|
if (!viewer () || slen <= 0) return;
|
|
View * v = viewer ()->view ();
|
|
|
|
bool ok;
|
|
TQRegExp * patterns = m_configpage->m_patterns;
|
|
TQRegExp & m_refURLRegExp = patterns[MPlayerPreferencesPage::pat_refurl];
|
|
TQRegExp & m_refRegExp = patterns[MPlayerPreferencesPage::pat_ref];
|
|
do {
|
|
int len = strcspn (str, "\r\n");
|
|
TQString out = m_process_output + TQString::fromLocal8Bit (str, len);
|
|
m_process_output = TQString ();
|
|
str += len;
|
|
slen -= len;
|
|
if (slen <= 0) {
|
|
m_process_output = out;
|
|
break;
|
|
}
|
|
bool process_stats = false;
|
|
if (str[0] == '\r') {
|
|
if (slen > 1 && str[1] == '\n') {
|
|
str++;
|
|
slen--;
|
|
} else
|
|
process_stats = true;
|
|
}
|
|
str++;
|
|
slen--;
|
|
|
|
if (process_stats) {
|
|
TQRegExp & m_posRegExp = patterns[MPlayerPreferencesPage::pat_pos];
|
|
TQRegExp & m_cacheRegExp = patterns[MPlayerPreferencesPage::pat_cache];
|
|
if (m_source->hasLength () && m_posRegExp.search (out) > -1) {
|
|
int pos = int (10.0 * m_posRegExp.cap (1).toFloat ());
|
|
m_source->setPosition (pos);
|
|
m_request_seek = -1;
|
|
} else if (m_cacheRegExp.search (out) > -1) {
|
|
m_source->setLoading (int (m_cacheRegExp.cap(1).toDouble()));
|
|
}
|
|
} else if (out.startsWith ("ID_LENGTH")) {
|
|
int pos = out.find ('=');
|
|
if (pos > 0) {
|
|
int l = (int) out.mid (pos + 1).toDouble (&ok);
|
|
if (ok && l >= 0) {
|
|
m_source->setLength (m_mrl, 10 * l);
|
|
}
|
|
}
|
|
} else if (m_refURLRegExp.search(out) > -1) {
|
|
kdDebug () << "Reference mrl " << m_refURLRegExp.cap (1) << endl;
|
|
if (!m_tmpURL.isEmpty () && m_url != m_tmpURL)
|
|
m_source->insertURL (m_mrl, m_tmpURL);;
|
|
m_tmpURL = KURL::fromPathOrURL (m_refURLRegExp.cap (1)).url ();
|
|
if (m_source->url () == m_tmpURL || m_url == m_tmpURL)
|
|
m_tmpURL.truncate (0);
|
|
} else if (m_refRegExp.search (out) > -1) {
|
|
kdDebug () << "Reference File " << endl;
|
|
m_tmpURL.truncate (0);
|
|
} else if (out.startsWith ("ID_VIDEO_WIDTH")) {
|
|
int pos = out.find ('=');
|
|
if (pos > 0) {
|
|
int w = out.mid (pos + 1).toInt ();
|
|
m_source->setDimensions (m_mrl, w, m_source->height ());
|
|
}
|
|
} else if (out.startsWith ("ID_VIDEO_HEIGHT")) {
|
|
int pos = out.find ('=');
|
|
if (pos > 0) {
|
|
int h = out.mid (pos + 1).toInt ();
|
|
m_source->setDimensions (m_mrl, m_source->width (), h);
|
|
}
|
|
} else if (out.startsWith ("ID_VIDEO_ASPECT")) {
|
|
int pos = out.find ('=');
|
|
if (pos > 0) {
|
|
bool ok;
|
|
TQString val = out.mid (pos + 1);
|
|
float a = val.toFloat (&ok);
|
|
if (!ok) {
|
|
val.replace (',', '.');
|
|
a = val.toFloat (&ok);
|
|
}
|
|
if (ok && a > 0.001)
|
|
m_source->setAspect (m_mrl, a);
|
|
}
|
|
} else if (out.startsWith ("ID_AID_")) {
|
|
int pos = out.find ('_', 7);
|
|
if (pos > 0) {
|
|
int id = out.mid (7, pos - 7).toInt ();
|
|
pos = out.find ('=', pos);
|
|
if (pos > 0) {
|
|
if (!alanglist_end) {
|
|
alanglist = new LangInfo (id, out.mid (pos + 1));
|
|
alanglist_end = alanglist;
|
|
} else {
|
|
alanglist_end->next = new LangInfo (id, out.mid(pos+1));
|
|
alanglist_end = alanglist_end->next;
|
|
}
|
|
kdDebug () << "lang " << id << " " << alanglist_end->name <<endl;
|
|
}
|
|
}
|
|
} else if (out.startsWith ("ID_SID_")) {
|
|
int pos = out.find ('_', 7);
|
|
if (pos > 0) {
|
|
int id = out.mid (7, pos - 7).toInt ();
|
|
pos = out.find ('=', pos);
|
|
if (pos > 0) {
|
|
if (!slanglist_end) {
|
|
slanglist = new LangInfo (id, out.mid (pos + 1));
|
|
slanglist_end = slanglist;
|
|
} else {
|
|
slanglist_end->next = new LangInfo (id, out.mid(pos+1));
|
|
slanglist_end = slanglist_end->next;
|
|
}
|
|
kdDebug () << "sid " << id << " " << slanglist_end->name <<endl;
|
|
}
|
|
}
|
|
} else if (out.startsWith ("ICY Info")) {
|
|
int p = out.find ("StreamTitle=", 8);
|
|
if (p > -1) {
|
|
p += 12;
|
|
int e = out.find (';', p);
|
|
if (e > -1)
|
|
e -= p;
|
|
((PlayListNotify *)m_source)->setInfoMessage (out.mid (p, e));
|
|
}
|
|
} else {
|
|
TQRegExp & m_startRegExp = patterns[MPlayerPreferencesPage::pat_start];
|
|
TQRegExp & m_sizeRegExp = patterns[MPlayerPreferencesPage::pat_size];
|
|
v->addText (out, true);
|
|
if (!m_source->processOutput (out)) {
|
|
// int movie_width = m_source->width ();
|
|
if (/*movie_width <= 0 &&*/ m_sizeRegExp.search (out) > -1) {
|
|
int movie_width = m_sizeRegExp.cap (1).toInt (&ok);
|
|
int movie_height = ok ? m_sizeRegExp.cap (2).toInt (&ok) : 0;
|
|
if (ok && movie_width > 0 && movie_height > 0) {
|
|
m_source->setDimensions(m_mrl,movie_width,movie_height);
|
|
m_source->setAspect (m_mrl, 1.0*movie_width/movie_height);
|
|
}
|
|
} else if (m_startRegExp.search (out) > -1) {
|
|
if (m_settings->mplayerpost090) {
|
|
if (!m_tmpURL.isEmpty () && m_url != m_tmpURL) {
|
|
m_source->insertURL (m_mrl, m_tmpURL);;
|
|
m_tmpURL.truncate (0);
|
|
}
|
|
m_source->setIdentified ();
|
|
}
|
|
TQStringList alst, slst;
|
|
for (SharedPtr <LangInfo> li = alanglist; li; li = li->next)
|
|
alst.push_back (li->name);
|
|
for (SharedPtr <LangInfo> li = slanglist; li; li = li->next)
|
|
slst.push_back (li->name);
|
|
m_source->setLanguages (alst, slst);
|
|
setState (Playing);
|
|
}
|
|
}
|
|
}
|
|
} while (slen > 0);
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayer::processStopped (TDEProcess * p) {
|
|
if (p && !m_grabfile.isEmpty ()) {
|
|
emit grabReady (m_grabfile);
|
|
m_grabfile.truncate (0);
|
|
} else if (p) {
|
|
TQString url;
|
|
if (!m_source->identified ()) {
|
|
m_source->setIdentified ();
|
|
if (!m_tmpURL.isEmpty () && m_url != m_tmpURL) {
|
|
m_source->insertURL (m_mrl, m_tmpURL);;
|
|
m_tmpURL.truncate (0);
|
|
}
|
|
}
|
|
if (m_source && m_needs_restarted) {
|
|
commands.clear ();
|
|
int pos = m_source->position ();
|
|
play (m_source, m_mrl);
|
|
seek (pos, true);
|
|
} else
|
|
MPlayerBase::processStopped (p);
|
|
}
|
|
}
|
|
|
|
void MPlayer::setAudioLang (int id, const TQString &) {
|
|
SharedPtr <LangInfo> li = alanglist;
|
|
for (; id > 0 && li; li = li->next)
|
|
id--;
|
|
if (li)
|
|
aid = li->id;
|
|
m_needs_restarted = true;
|
|
sendCommand (TQString ("quit"));
|
|
}
|
|
|
|
void MPlayer::setSubtitle (int id, const TQString &) {
|
|
SharedPtr <LangInfo> li = slanglist;
|
|
for (; id > 0 && li; li = li->next)
|
|
id--;
|
|
if (li)
|
|
sid = li->id;
|
|
m_needs_restarted = true;
|
|
sendCommand (TQString ("quit"));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern const char * strMPlayerGroup;
|
|
static const char * strMPlayerPatternGroup = "MPlayer Output Matching";
|
|
static const char * strMPlayerPath = "MPlayer Path";
|
|
static const char * strAddArgs = "Additional Arguments";
|
|
static const char * strCacheSize = "Cache Size for Streaming";
|
|
static const char * strAlwaysBuildIndex = "Always build index";
|
|
static const int non_patterns = 4;
|
|
|
|
static struct MPlayerPattern {
|
|
TQString caption;
|
|
const char * name;
|
|
const char * pattern;
|
|
} _mplayer_patterns [] = {
|
|
{ i18n ("Size pattern"), "Movie Size", "VO:.*[^0-9]([0-9]+)x([0-9]+)" },
|
|
{ i18n ("Cache pattern"), "Cache Fill", "Cache fill:[^0-9]*([0-9\\.]+)%" },
|
|
{ i18n ("Position pattern"), "Movie Position", "V:\\s*([0-9\\.]+)" },
|
|
{ i18n ("Index pattern"), "Index Pattern", "Generating Index: +([0-9]+)%" },
|
|
{ i18n ("Reference URL pattern"), "Reference URL Pattern", "Playing\\s+(.*[^\\.])\\.?\\s*$" },
|
|
{ i18n ("Reference pattern"), "Reference Pattern", "Reference Media file" },
|
|
{ i18n ("Start pattern"), "Start Playing", "Start[^ ]* play" },
|
|
{ i18n ("DVD language pattern"), "DVD Language", "\\[open].*audio.*language: ([A-Za-z]+).*aid.*[^0-9]([0-9]+)" },
|
|
{ i18n ("DVD subtitle pattern"), "DVD Sub Title", "\\[open].*subtitle.*[^0-9]([0-9]+).*language: ([A-Za-z]+)" },
|
|
{ i18n ("DVD titles pattern"), "DVD Titles", "There are ([0-9]+) titles" },
|
|
{ i18n ("DVD chapters pattern"), "DVD Chapters", "There are ([0-9]+) chapters" },
|
|
{ i18n ("VCD track pattern"), "VCD Tracks", "track ([0-9]+):" },
|
|
{ i18n ("Audio CD tracks pattern"), "CDROM Tracks", "[Aa]udio CD[^0-9]+([0-9]+)[^0-9]tracks" }
|
|
};
|
|
|
|
namespace KMPlayer {
|
|
|
|
class KMPLAYER_NO_EXPORT MPlayerPreferencesFrame : public TQFrame {
|
|
public:
|
|
MPlayerPreferencesFrame (TQWidget * parent);
|
|
TQTable * table;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayerPreferencesFrame::MPlayerPreferencesFrame (TQWidget * parent)
|
|
: TQFrame (parent) {
|
|
TQVBoxLayout * layout = new TQVBoxLayout (this);
|
|
table = new TQTable (int (MPlayerPreferencesPage::pat_last)+non_patterns, 2, this);
|
|
table->verticalHeader ()->hide ();
|
|
table->setLeftMargin (0);
|
|
table->horizontalHeader ()->hide ();
|
|
table->setTopMargin (0);
|
|
table->setColumnReadOnly (0, true);
|
|
table->setText (0, 0, i18n ("MPlayer command:"));
|
|
table->setText (1, 0, i18n ("Additional command line arguments:"));
|
|
table->setText (2, 0, TQString("%1 (%2)").arg (i18n ("Cache size:")).arg (i18n ("kB"))); // FIXME for new translations
|
|
table->setCellWidget (2, 1, new TQSpinBox (0, 32767, 32, table->viewport()));
|
|
table->setText (3, 0, i18n ("Build new index when possible"));
|
|
table->setCellWidget (3, 1, new TQCheckBox (table->viewport()));
|
|
TQWhatsThis::add (table->cellWidget (3, 1), i18n ("Allows seeking in indexed files (AVIs)"));
|
|
for (int i = 0; i < int (MPlayerPreferencesPage::pat_last); i++)
|
|
table->setText (i+non_patterns, 0, _mplayer_patterns[i].caption);
|
|
TQFontMetrics metrics (table->font ());
|
|
int first_column_width = 50;
|
|
for (int i = 0; i < int (MPlayerPreferencesPage::pat_last+non_patterns); i++) {
|
|
int strwidth = metrics.boundingRect (table->text (i, 0)).width ();
|
|
if (strwidth > first_column_width)
|
|
first_column_width = strwidth + 4;
|
|
}
|
|
table->setColumnWidth (0, first_column_width);
|
|
table->setColumnStretchable (1, true);
|
|
layout->addWidget (table);
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayerPreferencesPage::MPlayerPreferencesPage (MPlayer * p)
|
|
: m_process (p), m_configframe (0L) {
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerPreferencesPage::write (TDEConfig * config) {
|
|
config->setGroup (strMPlayerPatternGroup);
|
|
for (int i = 0; i < int (pat_last); i++)
|
|
config->writeEntry
|
|
(_mplayer_patterns[i].name, TQString(m_patterns[i].pattern ()));
|
|
config->setGroup (strMPlayerGroup);
|
|
config->writeEntry (strMPlayerPath, mplayer_path);
|
|
config->writeEntry (strAddArgs, additionalarguments);
|
|
config->writeEntry (strCacheSize, cachesize);
|
|
config->writeEntry (strAlwaysBuildIndex, alwaysbuildindex);
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerPreferencesPage::read (TDEConfig * config) {
|
|
config->setGroup (strMPlayerPatternGroup);
|
|
for (int i = 0; i < int (pat_last); i++)
|
|
m_patterns[i].setPattern (config->readEntry
|
|
(_mplayer_patterns[i].name, _mplayer_patterns[i].pattern));
|
|
config->setGroup (strMPlayerGroup);
|
|
mplayer_path = config->readEntry (strMPlayerPath, "mplayer");
|
|
additionalarguments = config->readEntry (strAddArgs);
|
|
cachesize = config->readNumEntry (strCacheSize, 384);
|
|
alwaysbuildindex = config->readBoolEntry (strAlwaysBuildIndex, false);
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerPreferencesPage::sync (bool fromUI) {
|
|
TQTable * table = m_configframe->table;
|
|
TQSpinBox * cacheSize = static_cast<TQSpinBox *>(table->cellWidget (2, 1));
|
|
TQCheckBox * buildIndex = static_cast<TQCheckBox *>(table->cellWidget (3, 1));
|
|
if (fromUI) {
|
|
mplayer_path = table->text (0, 1);
|
|
additionalarguments = table->text (1, 1);
|
|
for (int i = 0; i < int (pat_last); i++)
|
|
m_patterns[i].setPattern (table->text (i+non_patterns, 1));
|
|
cachesize = cacheSize->value();
|
|
alwaysbuildindex = buildIndex->isChecked ();
|
|
} else {
|
|
table->setText (0, 1, mplayer_path);
|
|
table->setText (1, 1, additionalarguments);
|
|
for (int i = 0; i < int (pat_last); i++)
|
|
table->setText (i+non_patterns, 1, m_patterns[i].pattern ());
|
|
if (cachesize > 0)
|
|
cacheSize->setValue(cachesize);
|
|
buildIndex->setChecked (alwaysbuildindex);
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerPreferencesPage::prefLocation (TQString & item, TQString & icon, TQString & tab) {
|
|
item = i18n ("General Options");
|
|
icon = TQString ("kmplayer");
|
|
tab = i18n ("MPlayer");
|
|
}
|
|
|
|
KDE_NO_EXPORT TQFrame * MPlayerPreferencesPage::prefPage (TQWidget * parent) {
|
|
m_configframe = new MPlayerPreferencesFrame (parent);
|
|
return m_configframe;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static const char * mencoder_supports [] = {
|
|
"dvdsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L
|
|
};
|
|
|
|
KDE_NO_CDTOR_EXPORT MEncoder::MEncoder (TQObject * parent, Settings * settings)
|
|
: MPlayerBase (parent, settings, "mencoder") {
|
|
m_supported_sources = mencoder_supports;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT MEncoder::~MEncoder () {
|
|
}
|
|
|
|
KDE_NO_EXPORT void MEncoder::init () {
|
|
}
|
|
|
|
bool MEncoder::deMediafiedPlay () {
|
|
bool success = false;
|
|
stop ();
|
|
initProcess (viewer ());
|
|
KURL url (m_url);
|
|
m_source->setPosition (0);
|
|
TQString args;
|
|
m_use_slave = m_source->pipeCmd ().isEmpty ();
|
|
if (!m_use_slave)
|
|
args = m_source->pipeCmd () + TQString (" | ");
|
|
TQString margs = m_settings->mencoderarguments;
|
|
if (m_settings->recordcopy)
|
|
margs = TQString ("-oac copy -ovc copy");
|
|
args += TQString ("mencoder ") + margs + ' ' + m_source->recordCmd ();
|
|
// FIXME if (m_player->source () == source) // ugly
|
|
// m_player->stop ();
|
|
TQString myurl = url.isLocalFile () ? getPath (url) : url.url ();
|
|
bool post090 = m_settings->mplayerpost090;
|
|
if (!myurl.isEmpty ()) {
|
|
if (!post090 && myurl.startsWith (TQString ("tv://")))
|
|
; // skip it
|
|
else if (!post090 && myurl.startsWith (TQString ("vcd://")))
|
|
args += myurl.replace (0, 6, TQString (" -vcd "));
|
|
else if (!post090 && myurl.startsWith (TQString ("dvd://")))
|
|
args += myurl.replace (0, 6, TQString (" -dvd "));
|
|
else
|
|
args += ' ' + TDEProcess::quote (TQString (TQFile::encodeName (myurl)));
|
|
}
|
|
TQString outurl = TDEProcess::quote (TQString (TQFile::encodeName (m_recordurl.isLocalFile () ? getPath (m_recordurl) : m_recordurl.url ())));
|
|
kdDebug () << args << " -o " << outurl << endl;
|
|
*m_process << args << " -o " << outurl;
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::NoCommunication);
|
|
success = m_process->isRunning ();
|
|
if (success)
|
|
setState (Playing);
|
|
return success;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MEncoder::stop () {
|
|
terminateJobs ();
|
|
if (!m_source || !m_process || !m_process->isRunning ()) return true;
|
|
kdDebug () << "MEncoder::stop ()" << endl;
|
|
if (m_use_slave)
|
|
m_process->kill (SIGINT);
|
|
return MPlayerBase::stop ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static const char * mplayerdump_supports [] = {
|
|
"dvdsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L
|
|
};
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
MPlayerDumpstream::MPlayerDumpstream (TQObject * parent, Settings * settings)
|
|
: MPlayerBase (parent, settings, "mplayerdumpstream") {
|
|
m_supported_sources = mplayerdump_supports;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT MPlayerDumpstream::~MPlayerDumpstream () {
|
|
}
|
|
|
|
KDE_NO_EXPORT void MPlayerDumpstream::init () {
|
|
}
|
|
|
|
bool MPlayerDumpstream::deMediafiedPlay () {
|
|
bool success = false;
|
|
stop ();
|
|
initProcess (viewer ());
|
|
KURL url (m_url);
|
|
m_source->setPosition (0);
|
|
TQString args;
|
|
m_use_slave = m_source->pipeCmd ().isEmpty ();
|
|
if (!m_use_slave)
|
|
args = m_source->pipeCmd () + TQString (" | ");
|
|
args += TQString ("mplayer ") + m_source->recordCmd ();
|
|
// FIXME if (m_player->source () == source) // ugly
|
|
// m_player->stop ();
|
|
TQString myurl = url.isLocalFile () ? getPath (url) : url.url ();
|
|
bool post090 = m_settings->mplayerpost090;
|
|
if (!myurl.isEmpty ()) {
|
|
if (!post090 && myurl.startsWith (TQString ("tv://")))
|
|
; // skip it
|
|
else if (!post090 && myurl.startsWith (TQString ("vcd://")))
|
|
args += myurl.replace (0, 6, TQString (" -vcd "));
|
|
else if (!post090 && myurl.startsWith (TQString ("dvd://")))
|
|
args += myurl.replace (0, 6, TQString (" -dvd "));
|
|
else
|
|
args += ' ' + TDEProcess::quote (TQString (TQFile::encodeName (myurl)));
|
|
}
|
|
TQString outurl = TDEProcess::quote (TQString (TQFile::encodeName (m_recordurl.isLocalFile () ? getPath (m_recordurl) : m_recordurl.url ())));
|
|
kdDebug () << args << " -dumpstream -dumpfile " << outurl << endl;
|
|
*m_process << args << " -dumpstream -dumpfile " << outurl;
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::NoCommunication);
|
|
success = m_process->isRunning ();
|
|
if (success)
|
|
setState (Playing);
|
|
return success;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool MPlayerDumpstream::stop () {
|
|
terminateJobs ();
|
|
if (!m_source || !m_process || !m_process->isRunning ()) return true;
|
|
kdDebug () << "MPlayerDumpstream::stop ()" << endl;
|
|
if (m_use_slave)
|
|
m_process->kill (SIGINT);
|
|
return MPlayerBase::stop ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static int callback_counter = 0;
|
|
|
|
Callback::Callback (CallbackProcess * process)
|
|
: DCOPObject (TQString (TQString ("KMPlayerCallback-") +
|
|
TQString::number (callback_counter++)).ascii ()),
|
|
m_process (process) {}
|
|
|
|
void Callback::statusMessage (int code, TQString msg) {
|
|
if (!m_process->m_source) return;
|
|
switch ((StatusCode) code) {
|
|
case stat_newtitle:
|
|
//m_process->source ()->setTitle (msg);
|
|
if (m_process->viewer ())
|
|
((PlayListNotify *) m_process->source ())->setInfoMessage (msg);
|
|
break;
|
|
case stat_hasvideo:
|
|
if (m_process->viewer ())
|
|
m_process->viewer ()->view ()->videoStart ();
|
|
break;
|
|
default:
|
|
m_process->setStatusMessage (msg);
|
|
};
|
|
}
|
|
|
|
void Callback::subMrl (TQString mrl, TQString title) {
|
|
if (!m_process->m_source) return;
|
|
m_process->m_source->insertURL (m_process->m_mrl, KURL::fromPathOrURL (mrl).url (), title);
|
|
if (m_process->m_mrl && m_process->m_mrl->active ())
|
|
m_process->m_mrl->defer (); // Xine detected this is a playlist
|
|
}
|
|
|
|
void Callback::errorMessage (int code, TQString msg) {
|
|
m_process->setErrorMessage (code, msg);
|
|
}
|
|
|
|
void Callback::finished () {
|
|
m_process->setFinished ();
|
|
}
|
|
|
|
void Callback::playing () {
|
|
m_process->setPlaying ();
|
|
}
|
|
|
|
void Callback::started (TQCString dcopname, TQByteArray data) {
|
|
m_process->setStarted (dcopname, data);
|
|
}
|
|
|
|
void Callback::movieParams (int length, int w, int h, float aspect, TQStringList alang, TQStringList slang) {
|
|
m_process->setMovieParams (length, w, h, aspect, alang, slang);
|
|
}
|
|
|
|
void Callback::moviePosition (int position) {
|
|
m_process->setMoviePosition (position);
|
|
}
|
|
|
|
void Callback::loadingProgress (int percentage) {
|
|
m_process->setLoadingProgress (percentage);
|
|
}
|
|
|
|
void Callback::toggleFullScreen () {
|
|
Viewer * v = m_process->viewer ();
|
|
if (v)
|
|
v->view ()->fullScreen ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CallbackProcess::CallbackProcess (TQObject * parent, Settings * settings, const char * n, const TQString & menuname)
|
|
: Process (parent, settings, n),
|
|
m_callback (new Callback (this)),
|
|
m_backend (0L),
|
|
m_menuname (menuname),
|
|
m_configpage (new XMLPreferencesPage (this)),
|
|
in_gui_update (false),
|
|
m_have_config (config_unknown),
|
|
m_send_config (send_no) {
|
|
}
|
|
|
|
CallbackProcess::~CallbackProcess () {
|
|
delete m_callback;
|
|
delete m_configpage;
|
|
if (configdoc)
|
|
configdoc->document()->dispose ();
|
|
}
|
|
|
|
void CallbackProcess::setStatusMessage (const TQString & /*msg*/) {
|
|
}
|
|
|
|
TQString CallbackProcess::menuName () const {
|
|
return m_menuname;
|
|
}
|
|
|
|
void CallbackProcess::setErrorMessage (int code, const TQString & msg) {
|
|
kdDebug () << "setErrorMessage " << code << " " << msg << endl;
|
|
if (code == 0 && m_send_config != send_no) {
|
|
if (m_send_config == send_new)
|
|
stop ();
|
|
m_send_config = send_no;
|
|
}
|
|
}
|
|
|
|
void CallbackProcess::setFinished () {
|
|
setState (Ready);
|
|
}
|
|
|
|
void CallbackProcess::setPlaying () {
|
|
setState (Playing);
|
|
}
|
|
|
|
void CallbackProcess::setStarted (TQCString dcopname, TQByteArray & data) {
|
|
if (data.size ())
|
|
m_configdata = data;
|
|
kdDebug () << "up and running " << dcopname << endl;
|
|
m_backend = new Backend_stub (dcopname, "Backend");
|
|
if (m_send_config == send_new) {
|
|
m_backend->setConfig (m_changeddata);
|
|
}
|
|
if (m_have_config == config_probe || m_have_config == config_unknown) {
|
|
bool was_probe = m_have_config == config_probe;
|
|
m_have_config = data.size () ? config_yes : config_no;
|
|
if (m_have_config == config_yes) {
|
|
configdoc = new ConfigDocument ();
|
|
TQTextStream ts (data, IO_ReadOnly);
|
|
readXML (configdoc, ts, TQString ());
|
|
configdoc->normalize ();
|
|
//kdDebug () << mydoc->innerText () << endl;
|
|
}
|
|
emit configReceived ();
|
|
if (m_configpage)
|
|
m_configpage->sync (false);
|
|
if (was_probe) {
|
|
quit ();
|
|
return;
|
|
}
|
|
}
|
|
if (m_settings->autoadjustcolors) {
|
|
saturation (m_settings->saturation, true);
|
|
hue (m_settings->hue, true);
|
|
brightness (m_settings->brightness, true);
|
|
contrast (m_settings->contrast, true);
|
|
}
|
|
setState (Ready);
|
|
}
|
|
|
|
void CallbackProcess::setMovieParams (int len, int w, int h, float a, const TQStringList & alang, const TQStringList & slang) {
|
|
kdDebug () << "setMovieParams " << len << " " << w << "," << h << " " << a << endl;
|
|
if (!m_source) return;
|
|
in_gui_update = true;
|
|
m_source->setDimensions (m_mrl, w, h);
|
|
m_source->setAspect (m_mrl, a);
|
|
m_source->setLength (m_mrl, len);
|
|
m_source->setLanguages (alang, slang);
|
|
in_gui_update = false;
|
|
}
|
|
|
|
void CallbackProcess::setMoviePosition (int position) {
|
|
if (!m_source) return;
|
|
in_gui_update = true;
|
|
m_source->setPosition (position);
|
|
m_request_seek = -1;
|
|
in_gui_update = false;
|
|
}
|
|
|
|
void CallbackProcess::setLoadingProgress (int percentage) {
|
|
in_gui_update = true;
|
|
m_source->setLoading (percentage);
|
|
in_gui_update = false;
|
|
}
|
|
|
|
bool CallbackProcess::getConfigData () {
|
|
if (m_have_config == config_no)
|
|
return false;
|
|
if (m_have_config == config_unknown && !playing ()) {
|
|
m_have_config = config_probe;
|
|
ready (viewer ());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CallbackProcess::setChangedData (const TQByteArray & data) {
|
|
m_changeddata = data;
|
|
m_send_config = playing () ? send_try : send_new;
|
|
if (m_send_config == send_try)
|
|
m_backend->setConfig (data);
|
|
else
|
|
ready (viewer ());
|
|
}
|
|
|
|
bool CallbackProcess::deMediafiedPlay () {
|
|
if (!m_backend)
|
|
return false;
|
|
kdDebug () << "CallbackProcess::play " << m_url << endl;
|
|
TQString u = m_url;
|
|
if (u == "tv://" && !m_source->tuner ().isEmpty ()) {
|
|
u = "v4l:/" + m_source->tuner ();
|
|
if (m_source->frequency () > 0)
|
|
u += TQChar ('/') + TQString::number (m_source->frequency ());
|
|
}
|
|
KURL url (u);
|
|
TQString myurl = url.isLocalFile () ? getPath (url) : url.url ();
|
|
m_backend->setURL (myurl);
|
|
const KURL & sub_url = m_source->subUrl ();
|
|
if (!sub_url.isEmpty ())
|
|
m_backend->setSubTitleURL (TQString (TQFile::encodeName (sub_url.isLocalFile () ? TQFileInfo (getPath (sub_url)).absFilePath () : sub_url.url ())));
|
|
if (m_source->frequency () > 0)
|
|
m_backend->frequency (m_source->frequency ());
|
|
m_backend->play (m_mrl ? m_mrl->mrl ()->repeat : 0);
|
|
setState (Buffering);
|
|
return true;
|
|
}
|
|
|
|
bool CallbackProcess::stop () {
|
|
terminateJobs ();
|
|
if (!m_process || !m_process->isRunning () || m_state < Buffering)
|
|
return true;
|
|
kdDebug () << "CallbackProcess::stop ()" << m_backend << endl;
|
|
if (m_backend)
|
|
m_backend->stop ();
|
|
return true;
|
|
}
|
|
|
|
bool CallbackProcess::quit () {
|
|
if (m_have_config == config_probe)
|
|
m_have_config = config_unknown; // hmm
|
|
if (m_send_config == send_new)
|
|
m_send_config = send_no; // oh well
|
|
if (playing ()) {
|
|
kdDebug () << "CallbackProcess::quit ()" << endl;
|
|
if (m_backend)
|
|
m_backend->quit ();
|
|
else if (viewer ())
|
|
viewer ()->sendKeyEvent ('q');
|
|
#if KDE_IS_VERSION(3, 1, 90)
|
|
m_process->wait(1);
|
|
#else
|
|
TQTime t;
|
|
t.start ();
|
|
do {
|
|
TDEProcessController::theTDEProcessController->waitForProcessExit (2);
|
|
} while (t.elapsed () < 1000 && m_process->isRunning ());
|
|
#endif
|
|
}
|
|
return Process::quit ();
|
|
}
|
|
|
|
bool CallbackProcess::pause () {
|
|
if (!playing () || !m_backend) return false;
|
|
m_backend->pause ();
|
|
return true;
|
|
}
|
|
|
|
void CallbackProcess::setAudioLang (int id, const TQString & al) {
|
|
if (!m_backend) return;
|
|
m_backend->setAudioLang (id, al);
|
|
}
|
|
|
|
void CallbackProcess::setSubtitle (int id, const TQString & sl) {
|
|
if (!m_backend) return;
|
|
m_backend->setSubtitle (id, sl);
|
|
}
|
|
|
|
bool CallbackProcess::seek (int pos, bool absolute) {
|
|
if (in_gui_update || !playing () ||
|
|
!m_backend || !m_source ||
|
|
!m_source->hasLength () ||
|
|
(absolute && m_source->position () == pos))
|
|
return false;
|
|
if (!absolute)
|
|
pos = m_source->position () + pos;
|
|
m_source->setPosition (pos);
|
|
if (m_request_seek < 0)
|
|
m_backend->seek (pos, true);
|
|
m_request_seek = pos;
|
|
return true;
|
|
}
|
|
|
|
bool CallbackProcess::volume (int val, bool b) {
|
|
if (m_backend)
|
|
m_backend->volume (int (sqrt (val*100)), b);
|
|
//m_backend->volume (100 * log (1.0*val) / log (100.0), b);
|
|
return !!m_backend;
|
|
}
|
|
|
|
bool CallbackProcess::saturation (int val, bool b) {
|
|
if (m_backend)
|
|
m_backend->saturation (val, b);
|
|
return !!m_backend;
|
|
}
|
|
|
|
bool CallbackProcess::hue (int val, bool b) {
|
|
if (m_backend)
|
|
m_backend->hue (val, b);
|
|
return !!m_backend;
|
|
}
|
|
|
|
bool CallbackProcess::brightness (int val, bool b) {
|
|
if (m_backend)
|
|
m_backend->brightness (val, b);
|
|
return !!m_backend;
|
|
}
|
|
|
|
bool CallbackProcess::contrast (int val, bool b) {
|
|
if (m_backend)
|
|
m_backend->contrast (val, b);
|
|
return !!m_backend;
|
|
}
|
|
|
|
TQString CallbackProcess::dcopName () {
|
|
TQString cbname;
|
|
cbname.sprintf ("%s/%s", TQString (kapp->dcopClient ()->appId ()).ascii (),
|
|
TQString (m_callback->objId ()).ascii ());
|
|
return cbname;
|
|
}
|
|
|
|
void CallbackProcess::initProcess (Viewer * viewer) {
|
|
Process::initProcess (viewer);
|
|
connect (m_process, TQT_SIGNAL (processExited (TDEProcess *)),
|
|
this, TQT_SLOT (processStopped (TDEProcess *)));
|
|
connect (m_process, TQT_SIGNAL (receivedStdout (TDEProcess *, char *, int)),
|
|
this, TQT_SLOT (processOutput (TDEProcess *, char *, int)));
|
|
connect (m_process, TQT_SIGNAL (receivedStderr (TDEProcess *, char *, int)),
|
|
this, TQT_SLOT (processOutput (TDEProcess *, char *, int)));
|
|
}
|
|
|
|
KDE_NO_EXPORT void CallbackProcess::processOutput (TDEProcess *, char * str, int slen) {
|
|
if (viewer () && slen > 0)
|
|
viewer ()->view ()->addText (TQString::fromLocal8Bit (str, slen));
|
|
}
|
|
|
|
KDE_NO_EXPORT void CallbackProcess::processStopped (TDEProcess *) {
|
|
if (m_source)
|
|
((PlayListNotify *) m_source)->setInfoMessage (TQString ());
|
|
delete m_backend;
|
|
m_backend = 0L;
|
|
setState (NotRunning);
|
|
if (m_send_config == send_try) {
|
|
m_send_config = send_new; // we failed, retry ..
|
|
ready (viewer ());
|
|
}
|
|
}
|
|
|
|
WId CallbackProcess::widget () {
|
|
return viewer () ? viewer ()->embeddedWinId () : 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
KDE_NO_CDTOR_EXPORT ConfigDocument::ConfigDocument ()
|
|
: Document (TQString ()) {}
|
|
|
|
KDE_NO_CDTOR_EXPORT ConfigDocument::~ConfigDocument () {
|
|
kdDebug () << "~ConfigDocument" << endl;
|
|
}
|
|
|
|
namespace KMPlayer {
|
|
/*
|
|
* Element for ConfigDocument
|
|
*/
|
|
struct KMPLAYER_NO_EXPORT SomeNode : public ConfigNode {
|
|
KDE_NO_CDTOR_EXPORT SomeNode (NodePtr & d, const TQString & t)
|
|
: ConfigNode (d, t) {}
|
|
KDE_NO_CDTOR_EXPORT ~SomeNode () {}
|
|
NodePtr childFromTag (const TQString & t);
|
|
};
|
|
} // namespace
|
|
|
|
KDE_NO_CDTOR_EXPORT ConfigNode::ConfigNode (NodePtr & d, const TQString & t)
|
|
: DarkNode (d, t), w (0L) {}
|
|
|
|
NodePtr ConfigDocument::childFromTag (const TQString & tag) {
|
|
if (tag.lower () == TQString ("document"))
|
|
return new ConfigNode (m_doc, tag);
|
|
return 0L;
|
|
}
|
|
|
|
NodePtr ConfigNode::childFromTag (const TQString & t) {
|
|
return new TypeNode (m_doc, t);
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT TypeNode::TypeNode (NodePtr & d, const TQString & t)
|
|
: ConfigNode (d, t), tag (t) {}
|
|
|
|
NodePtr TypeNode::childFromTag (const TQString & tag) {
|
|
return new SomeNode (m_doc, tag);
|
|
}
|
|
|
|
NodePtr SomeNode::childFromTag (const TQString & t) {
|
|
return new SomeNode (m_doc, t);
|
|
}
|
|
|
|
TQWidget * TypeNode::createWidget (TQWidget * parent) {
|
|
TQString type_attr = getAttribute (StringPool::attr_type);
|
|
const char * ctype = type_attr.ascii ();
|
|
TQString value = getAttribute (StringPool::attr_value);
|
|
if (!strcmp (ctype, "range")) {
|
|
w = new TQSlider (getAttribute (TQString ("START")).toInt (),
|
|
getAttribute (StringPool::attr_end).toInt (),
|
|
1, value.toInt (), TQt::Horizontal, parent);
|
|
} else if (!strcmp (ctype, "num") || !strcmp (ctype, "string")) {
|
|
w = new TQLineEdit (value, parent);
|
|
} else if (!strcmp (ctype, "bool")) {
|
|
TQCheckBox * checkbox = new TQCheckBox (parent);
|
|
checkbox->setChecked (value.toInt ());
|
|
w = checkbox;
|
|
} else if (!strcmp (ctype, "enum")) {
|
|
TQComboBox * combo = new TQComboBox (parent);
|
|
for (NodePtr e = firstChild (); e; e = e->nextSibling ())
|
|
if (e->isElementNode () && !strcmp (e->nodeName (), "item"))
|
|
combo->insertItem (convertNode <Element> (e)->getAttribute (StringPool::attr_value));
|
|
combo->setCurrentItem (value.toInt ());
|
|
w = combo;
|
|
} else if (!strcmp (ctype, "tree")) {
|
|
} else
|
|
kdDebug() << "Unknown type:" << ctype << endl;
|
|
return w;
|
|
}
|
|
|
|
void TypeNode::changedXML (TQTextStream & out) {
|
|
if (!w) return;
|
|
TQString type_attr = getAttribute (StringPool::attr_type);
|
|
const char * ctype = type_attr.ascii ();
|
|
TQString value = getAttribute (StringPool::attr_value);
|
|
TQString newvalue;
|
|
if (!strcmp (ctype, "range")) {
|
|
newvalue = TQString::number (static_cast <TQSlider *> (w)->value ());
|
|
} else if (!strcmp (ctype, "num") || !strcmp (ctype, "string")) {
|
|
newvalue = static_cast <TQLineEdit *> (w)->text ();
|
|
} else if (!strcmp (ctype, "bool")) {
|
|
newvalue = TQString::number (static_cast <TQCheckBox *> (w)->isChecked());
|
|
} else if (!strcmp (ctype, "enum")) {
|
|
newvalue = TQString::number (static_cast<TQComboBox *>(w)->currentItem());
|
|
} else if (!strcmp (ctype, "tree")) {
|
|
} else
|
|
kdDebug() << "Unknown type:" << ctype << endl;
|
|
if (value != newvalue) {
|
|
value = newvalue;
|
|
setAttribute (StringPool::attr_value, newvalue);
|
|
out << outerXML ();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace KMPlayer {
|
|
|
|
class KMPLAYER_NO_EXPORT XMLPreferencesFrame : public TQFrame {
|
|
public:
|
|
XMLPreferencesFrame (TQWidget * parent, CallbackProcess *);
|
|
KDE_NO_CDTOR_EXPORT ~XMLPreferencesFrame () {}
|
|
TQTable * table;
|
|
protected:
|
|
void showEvent (TQShowEvent *);
|
|
private:
|
|
CallbackProcess * m_process;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
KDE_NO_CDTOR_EXPORT XMLPreferencesFrame::XMLPreferencesFrame
|
|
(TQWidget * parent, CallbackProcess * p)
|
|
: TQFrame (parent), m_process (p){
|
|
TQVBoxLayout * layout = new TQVBoxLayout (this);
|
|
table = new TQTable (this);
|
|
layout->addWidget (table);
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT XMLPreferencesPage::XMLPreferencesPage (CallbackProcess * p)
|
|
: m_process (p), m_configframe (0L) {
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT XMLPreferencesPage::~XMLPreferencesPage () {
|
|
}
|
|
|
|
KDE_NO_EXPORT void XMLPreferencesFrame::showEvent (TQShowEvent *) {
|
|
if (!m_process->haveConfig ())
|
|
m_process->getConfigData ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void XMLPreferencesPage::write (TDEConfig *) {
|
|
}
|
|
|
|
KDE_NO_EXPORT void XMLPreferencesPage::read (TDEConfig *) {
|
|
}
|
|
|
|
KDE_NO_EXPORT void XMLPreferencesPage::sync (bool fromUI) {
|
|
if (!m_configframe) return;
|
|
TQTable * table = m_configframe->table;
|
|
int row = 0;
|
|
if (fromUI) {
|
|
NodePtr configdoc = m_process->configDocument ();
|
|
if (!configdoc || m_configframe->table->numCols () < 1) //not yet created
|
|
return;
|
|
NodePtr elm = configdoc->firstChild (); // document
|
|
if (!elm || !elm->hasChildNodes ()) {
|
|
kdDebug () << "No valid data" << endl;
|
|
return;
|
|
}
|
|
TQString str;
|
|
TQTextStream ts (&str, IO_WriteOnly);
|
|
ts << "<document>";
|
|
for (NodePtr e = elm->firstChild (); e; e = e->nextSibling ())
|
|
convertNode <TypeNode> (e)->changedXML (ts);
|
|
if (str.length () > 10) {
|
|
ts << "</document>";
|
|
TQByteArray changeddata = TQCString (str.ascii ());
|
|
kdDebug () << str << " " << changeddata.size () << str.length () << endl;
|
|
changeddata.resize (str.length ());
|
|
m_process->setChangedData (changeddata);
|
|
}
|
|
} else {
|
|
if (!m_process->haveConfig ())
|
|
return;
|
|
NodePtr configdoc = m_process->configDocument ();
|
|
if (!configdoc)
|
|
return;
|
|
if (m_configframe->table->numCols () < 1) { // not yet created
|
|
TQString err;
|
|
int first_column_width = 50;
|
|
NodePtr elm = configdoc->firstChild (); // document
|
|
if (!elm || !elm->hasChildNodes ()) {
|
|
kdDebug () << "No valid data" << endl;
|
|
return;
|
|
}
|
|
// set up the table fields
|
|
table->setNumCols (2);
|
|
table->setNumRows (elm->childNodes ()->length ());
|
|
table->verticalHeader ()->hide ();
|
|
table->setLeftMargin (0);
|
|
table->horizontalHeader ()->hide ();
|
|
table->setTopMargin (0);
|
|
table->setColumnReadOnly (0, true);
|
|
TQFontMetrics metrics (table->font ());
|
|
for (elm=elm->firstChild (); elm; elm=elm->nextSibling (), row++) {
|
|
TypeNode * tn = convertNode <TypeNode> (elm);
|
|
TQString name = tn->getAttribute (StringPool::attr_name);
|
|
m_configframe->table->setText (row, 0, name);
|
|
int strwid = metrics.boundingRect (name).width ();
|
|
if (strwid > first_column_width)
|
|
first_column_width = strwid + 4;
|
|
TQWidget * w = tn->createWidget (table->viewport ());
|
|
if (w) {
|
|
table->setCellWidget (row, 1, w);
|
|
TQWhatsThis::add (w, elm->innerText ());
|
|
} else
|
|
kdDebug () << "No widget for " << name;
|
|
}
|
|
table->setColumnWidth (0, first_column_width);
|
|
table->setColumnStretchable (1, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void XMLPreferencesPage::prefLocation (TQString & item, TQString & icon, TQString & tab) {
|
|
item = i18n ("General Options");
|
|
icon = TQString ("kmplayer");
|
|
tab = m_process->menuName ();
|
|
}
|
|
|
|
KDE_NO_EXPORT TQFrame * XMLPreferencesPage::prefPage (TQWidget * parent) {
|
|
m_configframe = new XMLPreferencesFrame (parent, m_process);
|
|
return m_configframe;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static const char * xine_supported [] = {
|
|
"dvdnavsource", "dvdsource", "exitsource", "introsource", "pipesource",
|
|
"tvsource", "urlsource", "vcdsource", "audiocdsource", 0L
|
|
};
|
|
|
|
KDE_NO_CDTOR_EXPORT Xine::Xine (TQObject * parent, Settings * settings)
|
|
: CallbackProcess (parent, settings, "xine", i18n ("&Xine")) {
|
|
#ifdef HAVE_XINE
|
|
m_supported_sources = xine_supported;
|
|
m_settings->addPage (m_configpage);
|
|
#endif
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT Xine::~Xine () {}
|
|
|
|
bool Xine::ready (Viewer * viewer) {
|
|
initProcess (viewer);
|
|
viewer->changeProtocol (QXEmbed::XPLAIN);
|
|
TQString xine_config = TDEProcess::quote (TQString (TQFile::encodeName (locateLocal ("data", "kmplayer/") + TQString ("xine_config"))));
|
|
m_request_seek = -1;
|
|
if (m_source && !m_source->pipeCmd ().isEmpty ()) {
|
|
fprintf (stderr, "%s | ", m_source->pipeCmd ().ascii ());
|
|
*m_process << m_source->pipeCmd ().ascii () << " | ";
|
|
}
|
|
fprintf (stderr, "kxineplayer -wid %lu", (unsigned long) widget ());
|
|
*m_process << "kxineplayer -wid " << TQString::number (widget ());
|
|
fprintf (stderr, " -f %s", xine_config.ascii ());
|
|
*m_process << " -f " << xine_config;
|
|
|
|
TQString strVideoDriver = TQString (m_settings->videodrivers[m_settings->videodriver].driver);
|
|
if (!strVideoDriver.isEmpty ()) {
|
|
fprintf (stderr, " -vo %s", strVideoDriver.lower().ascii());
|
|
*m_process << " -vo " << strVideoDriver.lower();
|
|
}
|
|
TQString strAudioDriver = TQString (m_settings->audiodrivers[m_settings->audiodriver].driver);
|
|
if (!strAudioDriver.isEmpty ()) {
|
|
if (strAudioDriver.startsWith (TQString ("alsa")))
|
|
strAudioDriver = TQString ("alsa");
|
|
fprintf (stderr, " -ao %s", strAudioDriver.lower().ascii());
|
|
*m_process << " -ao " << strAudioDriver.lower();
|
|
}
|
|
fprintf (stderr, " -cb %s", dcopName ().ascii());
|
|
*m_process << " -cb " << dcopName ();
|
|
if (m_have_config == config_unknown || m_have_config == config_probe) {
|
|
fprintf (stderr, " -c");
|
|
*m_process << " -c";
|
|
}
|
|
if (m_source)
|
|
if (m_source->url ().url ().startsWith (TQString ("dvd://")) &&
|
|
!m_settings->dvddevice.isEmpty ()) {
|
|
fprintf (stderr, " -dvd-device %s", m_settings->dvddevice.ascii ());
|
|
*m_process << " -dvd-device " << m_settings->dvddevice;
|
|
} else if (m_source->url ().url ().startsWith (TQString ("vcd://")) &&
|
|
!m_settings->vcddevice.isEmpty ()) {
|
|
fprintf (stderr, " -vcd-device %s", m_settings->vcddevice.ascii ());
|
|
*m_process << " -vcd-device " << m_settings->vcddevice;
|
|
} else if (m_source->url ().url ().startsWith (TQString ("tv://")) &&
|
|
!m_source->videoDevice ().isEmpty ()) {
|
|
fprintf (stderr, " -vd %s", m_source->videoDevice ().ascii ());
|
|
*m_process << " -vd " << m_source->videoDevice ();
|
|
}
|
|
if (!m_recordurl.isEmpty ()) {
|
|
TQString rf = TDEProcess::quote (
|
|
TQString (TQFile::encodeName (getPath (m_recordurl))));
|
|
fprintf (stderr, " -rec %s", rf.ascii ());
|
|
*m_process << " -rec " << rf;
|
|
}
|
|
fprintf (stderr, "\n");
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::All);
|
|
return m_process->isRunning ();
|
|
}
|
|
|
|
// TODO:input.v4l_video_device_path input.v4l_radio_device_path
|
|
// v4l:/Webcam/0 v4l:/Television/21600 v4l:/Radio/96
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static const char * gst_supported [] = {
|
|
"exitsource", "introsource", "urlsource", "vcdsource", "audiocdsource", 0L
|
|
};
|
|
|
|
KDE_NO_CDTOR_EXPORT GStreamer::GStreamer (TQObject * parent, Settings * settings)
|
|
: CallbackProcess (parent, settings, "gstreamer", i18n ("&GStreamer")) {
|
|
#ifdef HAVE_GSTREAMER
|
|
m_supported_sources = gst_supported;
|
|
#endif
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT GStreamer::~GStreamer () {}
|
|
|
|
KDE_NO_EXPORT bool GStreamer::ready (Viewer * viewer) {
|
|
initProcess (viewer);
|
|
viewer->changeProtocol (QXEmbed::XPLAIN);
|
|
m_request_seek = -1;
|
|
fprintf (stderr, "kgstplayer -wid %lu", (unsigned long) widget ());
|
|
*m_process << "kgstplayer -wid " << TQString::number (widget ());
|
|
|
|
TQString strVideoDriver = TQString (m_settings->videodrivers[m_settings->videodriver].driver);
|
|
if (!strVideoDriver.isEmpty ()) {
|
|
fprintf (stderr, " -vo %s", strVideoDriver.lower().ascii());
|
|
*m_process << " -vo " << strVideoDriver.lower();
|
|
}
|
|
TQString strAudioDriver = TQString (m_settings->audiodrivers[m_settings->audiodriver].driver);
|
|
if (!strAudioDriver.isEmpty ()) {
|
|
if (strAudioDriver.startsWith (TQString ("alsa")))
|
|
strAudioDriver = TQString ("alsa");
|
|
fprintf (stderr, " -ao %s", strAudioDriver.lower().ascii());
|
|
*m_process << " -ao " << strAudioDriver.lower();
|
|
}
|
|
fprintf (stderr, " -cb %s", dcopName ().ascii());
|
|
*m_process << " -cb " << dcopName ();
|
|
if (m_source)
|
|
if (m_source->url ().url ().startsWith (TQString ("dvd://")) &&
|
|
!m_settings->dvddevice.isEmpty ()) {
|
|
fprintf (stderr, " -dvd-device %s", m_settings->dvddevice.ascii ());
|
|
*m_process << " -dvd-device " << m_settings->dvddevice;
|
|
} else if (m_source->url ().url ().startsWith (TQString ("vcd://")) &&
|
|
!m_settings->vcddevice.isEmpty ()) {
|
|
fprintf (stderr, " -vcd-device %s", m_settings->vcddevice.ascii ());
|
|
*m_process << " -vcd-device " << m_settings->vcddevice;
|
|
}
|
|
fprintf (stderr, "\n");
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::All);
|
|
return m_process->isRunning ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static const char * ffmpeg_supports [] = {
|
|
"tvsource", "urlsource", 0L
|
|
};
|
|
|
|
FFMpeg::FFMpeg (TQObject * parent, Settings * settings)
|
|
: Process (parent, settings, "ffmpeg") {
|
|
m_supported_sources = ffmpeg_supports;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT FFMpeg::~FFMpeg () {
|
|
}
|
|
|
|
KDE_NO_EXPORT void FFMpeg::init () {
|
|
}
|
|
|
|
bool FFMpeg::deMediafiedPlay () {
|
|
initProcess (viewer ());
|
|
KURL url (m_url);
|
|
connect (m_process, TQT_SIGNAL (processExited (TDEProcess *)),
|
|
this, TQT_SLOT (processStopped (TDEProcess *)));
|
|
TQString outurl = TQString (TQFile::encodeName (m_recordurl.isLocalFile () ? getPath (m_recordurl) : m_recordurl.url ()));
|
|
if (m_recordurl.isLocalFile ())
|
|
TQFile (outurl).remove ();
|
|
TQString cmd ("ffmpeg ");
|
|
if (!m_source->videoDevice ().isEmpty () ||
|
|
!m_source->audioDevice ().isEmpty ()) {
|
|
if (!m_source->videoDevice ().isEmpty ())
|
|
cmd += TQString ("-vd ") + m_source->videoDevice ();
|
|
else
|
|
cmd += TQString ("-vn");
|
|
if (!m_source->audioDevice ().isEmpty ())
|
|
cmd += TQString (" -ad ") + m_source->audioDevice ();
|
|
else
|
|
cmd += TQString (" -an");
|
|
TDEProcess process;
|
|
process.setUseShell (true);
|
|
if (!m_source->videoNorm ().isEmpty ()) {
|
|
process << "v4lctl -c " << m_source->videoDevice () << " setnorm " << m_source->videoNorm ();
|
|
kdDebug () << "v4lctl -c " << m_source->videoDevice () << " setnorm " << m_source->videoNorm () << endl;
|
|
process.start (TDEProcess::Block);
|
|
cmd += TQString (" -tvstd ") + m_source->videoNorm ();
|
|
}
|
|
if (m_source->frequency () > 0) {
|
|
process.clearArguments();
|
|
process << "v4lctl -c " << m_source->videoDevice () << " setfreq " << TQString::number (m_source->frequency ());
|
|
kdDebug () << "v4lctl -c " << m_source->videoDevice () << " setfreq " << m_source->frequency () << endl;
|
|
process.start (TDEProcess::Block);
|
|
}
|
|
} else {
|
|
cmd += TQString ("-i ") + TDEProcess::quote (TQString (TQFile::encodeName (url.isLocalFile () ? getPath (url) : url.url ())));
|
|
}
|
|
cmd += TQChar (' ') + m_settings->ffmpegarguments;
|
|
cmd += TQChar (' ') + TDEProcess::quote (TQString (TQFile::encodeName (outurl)));
|
|
fprintf (stderr, "%s\n", (const char *) cmd.local8Bit ());
|
|
*m_process << cmd;
|
|
// FIXME if (m_player->source () == source) // ugly
|
|
// m_player->stop ();
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::All);
|
|
if (m_process->isRunning ())
|
|
setState (Playing);
|
|
return m_process->isRunning ();
|
|
}
|
|
|
|
KDE_NO_EXPORT bool FFMpeg::stop () {
|
|
terminateJobs ();
|
|
if (!playing ()) return true;
|
|
kdDebug () << "FFMpeg::stop" << endl;
|
|
m_process->writeStdin ("q", 1);
|
|
return true;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool FFMpeg::quit () {
|
|
stop ();
|
|
if (!playing ()) return true;
|
|
TQTime t;
|
|
t.start ();
|
|
do {
|
|
TDEProcessController::theTDEProcessController->waitForProcessExit (2);
|
|
} while (t.elapsed () < 2000 && m_process->isRunning ());
|
|
return Process::quit ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void FFMpeg::processStopped (TDEProcess *) {
|
|
setState (NotRunning);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifdef HAVE_NSPR
|
|
|
|
struct KMPLAYER_NO_EXPORT DBusStatic {
|
|
DBusStatic ();
|
|
~DBusStatic ();
|
|
DBusQt::Connection *connection; // FIXME find a way to detect if already connected
|
|
DBusConnection *dbus_connnection;
|
|
};
|
|
|
|
static DBusStatic * dbus_static = 0L;
|
|
|
|
DBusStatic::DBusStatic ()
|
|
: connection (new DBusQt::Connection (DBUS_BUS_SESSION, 0L)),
|
|
dbus_connnection (0L) {}
|
|
|
|
DBusStatic::~DBusStatic () {
|
|
dbus_connection_unref (dbus_connnection);
|
|
delete connection;
|
|
dbus_static = 0L;
|
|
}
|
|
|
|
static KStaticDeleter <DBusStatic> dbus_static_deleter;
|
|
|
|
//------------------%<---------------------------------------------------------
|
|
|
|
static DBusHandlerResult
|
|
dbusFilter (DBusConnection *conn, DBusMessage *msg, void *data) {
|
|
DBusMessageIter args;
|
|
//const char *iface = "org.kde.kmplayer.backend";
|
|
NpPlayer *process = (NpPlayer *) data;
|
|
const char * iface = process->interface ().ascii ();
|
|
const char * path = dbus_message_get_path (msg);
|
|
|
|
if (dbus_message_has_destination (msg, process->destination ().ascii ()) &&
|
|
dbus_message_has_interface (msg, iface) &&
|
|
TQString (path).startsWith(process->objectPath ()))
|
|
{
|
|
//kdDebug () << "dbusFilter " << sender <<
|
|
// " iface:" << dbus_message_get_interface (msg) <<
|
|
// " member:" << dbus_message_get_member (msg) <<
|
|
// " dest:" << dbus_message_get_destination (msg) << endl;
|
|
|
|
if (dbus_message_is_method_call (msg, iface, "getUrl")) {
|
|
char *param = 0;
|
|
TQString url, target;
|
|
if (dbus_message_iter_init (msg, &args) &&
|
|
DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) {
|
|
dbus_message_iter_get_basic (&args, ¶m);
|
|
url = TQString::fromLocal8Bit (param);
|
|
if (dbus_message_iter_next (&args) &&
|
|
DBUS_TYPE_STRING==dbus_message_iter_get_arg_type(&args)) {
|
|
dbus_message_iter_get_basic (&args, ¶m);
|
|
target = TQString::fromLocal8Bit (param);
|
|
}
|
|
process->requestStream (path, url, target);
|
|
}
|
|
//kdDebug () << "getUrl " << param << endl;
|
|
|
|
} else if (dbus_message_is_method_call (msg, iface, "evaluate")) {
|
|
char *param = 0;
|
|
if (dbus_message_iter_init (msg, &args) &&
|
|
DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) {
|
|
dbus_message_iter_get_basic (&args, ¶m);
|
|
TQString r = process->evaluateScript (TQString::fromUtf8 (param));
|
|
DBusMessage * rmsg = dbus_message_new_method_return (msg);
|
|
char *res = strdup (r.utf8 ().data ());
|
|
//kdDebug () << "evaluate => " << res << endl;
|
|
dbus_message_append_args (rmsg,
|
|
DBUS_TYPE_STRING, &res,
|
|
DBUS_TYPE_INVALID);
|
|
dbus_connection_send (conn, rmsg, NULL);
|
|
dbus_connection_flush (conn);
|
|
dbus_message_unref (rmsg);
|
|
free (res);
|
|
}
|
|
|
|
} else if (dbus_message_is_method_call (msg, iface, "destroy")) {
|
|
TQString stream =TQString(path).mid(process->objectPath().length()+1);
|
|
process->destroyStream (stream);
|
|
|
|
} else if (dbus_message_is_method_call (msg, iface, "running")) {
|
|
char *param = 0;
|
|
if (dbus_message_iter_init (msg, &args) &&
|
|
DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args)) {
|
|
dbus_message_iter_get_basic (&args, ¶m);
|
|
process->setStarted (TQString (param));
|
|
}
|
|
|
|
} else if (dbus_message_is_method_call (msg, iface, "plugged")) {
|
|
process->viewer ()->view ()->videoStart ();
|
|
} else if (dbus_message_is_method_call (msg, iface, "dimension")) {
|
|
TQ_UINT32 w, h;
|
|
if (dbus_message_iter_init (msg, &args) &&
|
|
DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)) {
|
|
dbus_message_iter_get_basic (&args, &w);
|
|
if (dbus_message_iter_next (&args) &&
|
|
DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args)) {
|
|
dbus_message_iter_get_basic (&args, &h);
|
|
if (h > 0)
|
|
process->source ()->setAspect (process->mrl(), 1.0*w/h);
|
|
}
|
|
}
|
|
}
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
NpStream::NpStream (TQObject *p, TQ_UINT32 sid, const KURL & u)
|
|
: TQObject (p),
|
|
url (u),
|
|
job (0L), bytes (0), content_length (0),
|
|
stream_id (sid),
|
|
finish_reason (NoReason) {
|
|
data_arrival.tv_sec = 0;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT NpStream::~NpStream () {
|
|
close ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpStream::open () {
|
|
kdDebug () << "NpStream " << stream_id << " open " << url.url () << endl;
|
|
if (url.url().startsWith ("javascript:")) {
|
|
NpPlayer *npp = static_cast <NpPlayer *> (parent ());
|
|
TQString result = npp->evaluateScript (url.url().mid (11));
|
|
if (!result.isEmpty ()) {
|
|
TQCString cr = result.local8Bit ();
|
|
int len = cr.length ();
|
|
pending_buf.resize (len + 1);
|
|
memcpy (pending_buf.data (), cr.data (), len);
|
|
pending_buf.data ()[len] = 0;
|
|
gettimeofday (&data_arrival, 0L);
|
|
}
|
|
kdDebug () << "result is " << pending_buf.data () << endl;
|
|
finish_reason = BecauseDone;
|
|
emit stateChanged ();
|
|
} else {
|
|
job = TDEIO::get (url, false, false);
|
|
job->addMetaData ("errorPage", "false");
|
|
connect (job, TQT_SIGNAL (data (TDEIO::Job *, const TQByteArray &)),
|
|
this, TQT_SLOT (slotData (TDEIO::Job *, const TQByteArray &)));
|
|
connect (job, TQT_SIGNAL (result (TDEIO::Job *)),
|
|
this, TQT_SLOT (slotResult (TDEIO::Job *)));
|
|
connect (job, TQT_SIGNAL (redirection (TDEIO::Job *, const KURL &)),
|
|
this, TQT_SLOT (redirection (TDEIO::Job *, const KURL &)));
|
|
connect (job, TQT_SIGNAL (mimetype (TDEIO::Job *, const TQString &)),
|
|
TQT_SLOT (slotMimetype (TDEIO::Job *, const TQString &)));
|
|
connect (job, TQT_SIGNAL (totalSize (TDEIO::Job *, TDEIO::filesize_t)),
|
|
TQT_SLOT (slotTotalSize (TDEIO::Job *, TDEIO::filesize_t)));
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpStream::close () {
|
|
if (job) {
|
|
job->kill (); // quiet, no result signal
|
|
job = 0L;
|
|
finish_reason = BecauseStopped;
|
|
// don't emit stateChanged(), because always triggered from NpPlayer
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpStream::slotResult (TDEIO::Job *jb) {
|
|
kdDebug() << "slotResult " << bytes << " err:" << jb->error () << endl;
|
|
finish_reason = jb->error () ? BecauseError : BecauseDone;
|
|
job = 0L; // signal TDEIO::Job::result deletes itself
|
|
emit stateChanged ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpStream::slotData (TDEIO::Job*, const TQByteArray& qb) {
|
|
pending_buf = qb; // we suspend job, so qb should be valid until resume
|
|
if (qb.size()) {
|
|
job->suspend ();
|
|
gettimeofday (&data_arrival, 0L);
|
|
emit stateChanged ();
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpStream::redirection (TDEIO::Job *, const KURL &u) {
|
|
url = u;
|
|
emit redirected (stream_id, url);
|
|
}
|
|
|
|
void NpStream::slotMimetype (TDEIO::Job *, const TQString &mime) {
|
|
mimetype = mime;
|
|
}
|
|
|
|
void NpStream::slotTotalSize (TDEIO::Job *, TDEIO::filesize_t sz) {
|
|
content_length = sz;
|
|
}
|
|
|
|
static const char * npplayer_supports [] = {
|
|
"urlsource", 0L
|
|
};
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
NpPlayer::NpPlayer (TQObject * parent, Settings * settings, const TQString & srv)
|
|
: Process (parent, settings, "npp"),
|
|
service (srv),
|
|
write_in_progress (false) {
|
|
m_supported_sources = npplayer_supports;
|
|
}
|
|
|
|
KDE_NO_CDTOR_EXPORT NpPlayer::~NpPlayer () {
|
|
if (!iface.isEmpty ()) {
|
|
DBusError dberr;
|
|
dbus_error_init (&dberr);
|
|
DBusConnection *conn = dbus_static->dbus_connnection;
|
|
if (conn) {
|
|
dbus_bus_remove_match (conn, filter.ascii(), &dberr);
|
|
if (dbus_error_is_set (&dberr))
|
|
dbus_error_free (&dberr);
|
|
dbus_connection_remove_filter (conn, dbusFilter, this);
|
|
dbus_connection_flush (conn);
|
|
}
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::init () {
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::initProcess (Viewer * viewer) {
|
|
Process::initProcess (viewer);
|
|
connect (m_process, TQT_SIGNAL (processExited (TDEProcess *)),
|
|
this, TQT_SLOT (processStopped (TDEProcess *)));
|
|
connect (m_process, TQT_SIGNAL (receivedStdout (TDEProcess *, char *, int)),
|
|
this, TQT_SLOT (processOutput (TDEProcess *, char *, int)));
|
|
connect (m_process, TQT_SIGNAL (receivedStderr (TDEProcess *, char *, int)),
|
|
this, TQT_SLOT (processOutput (TDEProcess *, char *, int)));
|
|
connect (m_process, TQT_SIGNAL (wroteStdin (TDEProcess *)),
|
|
this, TQT_SLOT (wroteStdin (TDEProcess *)));
|
|
if (!dbus_static)
|
|
dbus_static = dbus_static_deleter.setObject (new DBusStatic ());
|
|
if (iface.isEmpty ()) {
|
|
DBusError dberr;
|
|
iface = TQString ("org.kde.kmplayer.callback");
|
|
static int count = 0;
|
|
path = TQString ("/npplayer%1").arg (count++);
|
|
filter = TQString ("type='method_call',interface='org.kde.kmplayer.callback'");
|
|
|
|
dbus_error_init (&dberr);
|
|
DBusConnection *conn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);
|
|
if (dbus_error_is_set (&dberr))
|
|
dbus_error_free (&dberr);
|
|
if (!conn) {
|
|
kdError () << "Failed to get dbus connection: " << dberr.message << endl;
|
|
return;
|
|
}
|
|
bool has_service = !service.isEmpty();
|
|
if (has_service) { // standalone kmplayer
|
|
dbus_bus_request_name (conn, service.ascii(),
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &dberr);
|
|
if (dbus_error_is_set (&dberr)) {
|
|
kdError () << "Failed to register name " << service << ": " << dberr.message;
|
|
dbus_error_free (&dberr);
|
|
has_service = false;
|
|
}
|
|
}
|
|
if (!has_service) // plugin, accept what-is [sic]
|
|
service = TQString (dbus_bus_get_unique_name (conn));
|
|
kdDebug() << "using service " << service << " interface " << iface << endl;
|
|
dbus_bus_add_match (conn, filter.ascii(), &dberr);
|
|
if (dbus_error_is_set (&dberr)) {
|
|
kdError () << "Failed to set match " << filter << ": " << dberr.message << endl;
|
|
dbus_error_free (&dberr);
|
|
}
|
|
dbus_connection_add_filter (conn, dbusFilter, this, 0L);
|
|
dbus_connection_flush (conn);
|
|
dbus_static->dbus_connnection = conn;
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT bool NpPlayer::deMediafiedPlay () {
|
|
kdDebug() << "NpPlayer::play '" << m_url << "'" << endl;
|
|
// if we change from XPLAIN to XEMBED, the DestroyNotify may come later
|
|
viewer ()->changeProtocol (QXEmbed::XEMBED);
|
|
if (m_mrl && !m_url.isEmpty () && dbus_static->dbus_connnection) {
|
|
TQString mime = "text/plain";
|
|
TQString plugin;
|
|
Element *elm = m_mrl->mrl ();
|
|
if (elm->id == id_node_html_object) {
|
|
// this sucks to have to do this here ..
|
|
for (NodePtr n = elm->firstChild (); n; n = n->nextSibling ())
|
|
if (n->id == KMPlayer::id_node_html_embed) {
|
|
elm = convertNode <Element> (n);
|
|
break;
|
|
}
|
|
}
|
|
for (NodePtr n = m_mrl; n; n = n->parentNode ()) {
|
|
Mrl *mrl = n->mrl ();
|
|
if (mrl && m_base_url.isEmpty ())
|
|
m_base_url = mrl->getAttribute ("pluginbaseurl");
|
|
if (mrl && !mrl->mimetype.isEmpty ()) {
|
|
plugin = m_source->plugin (mrl->mimetype);
|
|
kdDebug() << "search plugin " << mrl->mimetype << "->" << plugin << endl;
|
|
if (!plugin.isEmpty ()) {
|
|
mime = mrl->mimetype;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!plugin.isEmpty ()) {
|
|
DBusMessage *msg = dbus_message_new_method_call (
|
|
remote_service.ascii(),
|
|
"/plugin",
|
|
"org.kde.kmplayer.backend",
|
|
"play");
|
|
char *c_url = strdup (m_url.local8Bit().data ());
|
|
char *c_mime = strdup (mime.ascii ());
|
|
char *c_plugin = strdup (plugin.ascii ());
|
|
DBusMessageIter it;
|
|
dbus_message_iter_init_append (msg, &it);
|
|
dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &c_url);
|
|
dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &c_mime);
|
|
dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &c_plugin);
|
|
unsigned int param_len = elm->attributes ()->length ();
|
|
char **argn = (char **) malloc (param_len * sizeof (char *));
|
|
char **argv = (char **) malloc (param_len * sizeof (char *));
|
|
dbus_message_iter_append_basic (&it, DBUS_TYPE_UINT32, ¶m_len);
|
|
DBusMessageIter ait;
|
|
dbus_message_iter_open_container (&it, DBUS_TYPE_ARRAY,"{ss}",&ait);
|
|
AttributePtr a = elm->attributes ()->first ();
|
|
for (int i = 0; i < param_len && a; i++, a = a->nextSibling ()) {
|
|
DBusMessageIter dit;
|
|
dbus_message_iter_open_container (&ait,
|
|
DBUS_TYPE_DICT_ENTRY,
|
|
NULL,
|
|
&dit);
|
|
argn[i] = strdup (a->name ().toString ().local8Bit().data ());
|
|
argv[i] = strdup (a->value ().local8Bit().data ());
|
|
dbus_message_iter_append_basic (&dit, DBUS_TYPE_STRING, &argn[i]);
|
|
dbus_message_iter_append_basic (&dit, DBUS_TYPE_STRING, &argv[i]);
|
|
dbus_message_iter_close_container (&ait, &dit);
|
|
}
|
|
dbus_message_iter_close_container (&it, &ait);
|
|
dbus_message_set_no_reply (msg, TRUE);
|
|
dbus_connection_send (dbus_static->dbus_connnection, msg, NULL);
|
|
dbus_message_unref (msg);
|
|
dbus_connection_flush (dbus_static->dbus_connnection);
|
|
free (c_url);
|
|
free (c_mime);
|
|
free (c_plugin);
|
|
for (int i = 0; i < param_len; i++) {
|
|
free (argn[i]);
|
|
free (argv[i]);
|
|
}
|
|
free (argn);
|
|
free (argv);
|
|
setState (Buffering);
|
|
return true;
|
|
}
|
|
}
|
|
stop ();
|
|
return false;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool NpPlayer::ready (Viewer * viewer) {
|
|
if (playing ())
|
|
return true; // wait for callback
|
|
initProcess (viewer);
|
|
viewer->changeProtocol (QXEmbed::XEMBED);
|
|
kdDebug() << "NpPlayer::ready" << endl;
|
|
TQString cmd ("knpplayer");
|
|
cmd += TQString (" -cb ");
|
|
cmd += service;
|
|
cmd += path;
|
|
cmd += TQString (" -wid ");
|
|
cmd += TQString::number (viewer->winId ());
|
|
fprintf (stderr, "%s\n", cmd.local8Bit ().data ());
|
|
*m_process << cmd;
|
|
m_process->start (TDEProcess::NotifyOnExit, TDEProcess::All);
|
|
return m_process->isRunning ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::setStarted (const TQString & srv) {
|
|
remote_service = srv;
|
|
kdDebug () << "NpPlayer::setStarted " << srv << endl;
|
|
setState (Ready);
|
|
}
|
|
|
|
KDE_NO_EXPORT TQString NpPlayer::evaluateScript (const TQString & script) {
|
|
TQString result;
|
|
emit evaluate (script, result);
|
|
//kdDebug () << "evaluateScript " << script << " => " << result << endl;
|
|
return result;
|
|
}
|
|
|
|
static int getStreamId (const TQString &path) {
|
|
int p = path.findRev (TQChar ('_'));
|
|
if (p < 0) {
|
|
kdError() << "wrong object path " << path << endl;
|
|
return -1;
|
|
}
|
|
bool ok;
|
|
TQ_UINT32 sid = path.mid (p+1).toInt (&ok);
|
|
if (!ok) {
|
|
kdError() << "wrong object path suffix " << path.mid (p+1) << endl;
|
|
return -1;
|
|
}
|
|
return sid;
|
|
}
|
|
|
|
KDE_NO_EXPORT
|
|
void NpPlayer::requestStream (const TQString &path, const TQString & url, const TQString & target) {
|
|
KURL uri (m_base_url.isEmpty () ? m_url : m_base_url, url);
|
|
kdDebug () << "NpPlayer::request " << path << " '" << uri << "'" << endl;
|
|
TQ_UINT32 sid = getStreamId (path);
|
|
if (sid >= 0) {
|
|
if (!target.isEmpty ()) {
|
|
kdDebug () << "new page request " << target << endl;
|
|
if (url.startsWith ("javascript:")) {
|
|
TQString result = evaluateScript (url.mid (11));
|
|
kdDebug() << "result is " << result << endl;
|
|
if (result == "undefined")
|
|
uri = KURL ();
|
|
else
|
|
uri = KURL (m_url, result); // probably wrong ..
|
|
}
|
|
if (uri.isValid ())
|
|
emit openUrl (uri, target);
|
|
sendFinish (sid, 0, NpStream::BecauseDone);
|
|
} else {
|
|
NpStream * ns = new NpStream (this, sid, uri);
|
|
connect (ns, TQT_SIGNAL (stateChanged ()),
|
|
this, TQT_SLOT (streamStateChanged ()));
|
|
streams[sid] = ns;
|
|
if (url != uri.url ())
|
|
streamRedirected (sid, uri.url ());
|
|
if (!write_in_progress)
|
|
processStreams ();
|
|
}
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::destroyStream (const TQString &s) {
|
|
int sid = getStreamId (s);
|
|
if (sid >= 0 && streams.contains ((TQ_UINT32) sid)) {
|
|
NpStream *ns = streams[(TQ_UINT32) sid];
|
|
ns->close ();
|
|
if (!write_in_progress)
|
|
processStreams ();
|
|
} else {
|
|
kdWarning () << "Object " << s << " not found" << endl;
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT
|
|
void NpPlayer::sendFinish (TQ_UINT32 sid, TQ_UINT32 bytes, NpStream::Reason because) {
|
|
if (playing () && dbus_static->dbus_connnection) {
|
|
TQ_UINT32 reason = (int) because;
|
|
TQString objpath = TQString ("/plugin/stream_%1").arg (sid);
|
|
DBusMessage *msg = dbus_message_new_method_call (
|
|
remote_service.ascii(),
|
|
objpath.ascii (),
|
|
"org.kde.kmplayer.backend",
|
|
"eof");
|
|
dbus_message_append_args(msg,
|
|
DBUS_TYPE_UINT32, &bytes,
|
|
DBUS_TYPE_UINT32, &reason,
|
|
DBUS_TYPE_INVALID);
|
|
dbus_message_set_no_reply (msg, TRUE);
|
|
dbus_connection_send (dbus_static->dbus_connnection, msg, NULL);
|
|
dbus_message_unref (msg);
|
|
dbus_connection_flush (dbus_static->dbus_connnection);
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::terminateJobs () {
|
|
Process::terminateJobs ();
|
|
const StreamMap::iterator e = streams.end ();
|
|
for (StreamMap::iterator i = streams.begin (); i != e; ++i)
|
|
delete i.data ();
|
|
streams.clear ();
|
|
}
|
|
|
|
KDE_NO_EXPORT bool NpPlayer::stop () {
|
|
terminateJobs ();
|
|
if (!playing ()) return true;
|
|
kdDebug () << "NpPlayer::stop " << endl;
|
|
if (dbus_static->dbus_connnection) {
|
|
DBusMessage *msg = dbus_message_new_method_call (
|
|
remote_service.ascii(),
|
|
"/plugin",
|
|
"org.kde.kmplayer.backend",
|
|
"quit");
|
|
dbus_message_set_no_reply (msg, TRUE);
|
|
dbus_connection_send (dbus_static->dbus_connnection, msg, NULL);
|
|
dbus_message_unref (msg);
|
|
dbus_connection_flush (dbus_static->dbus_connnection);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
KDE_NO_EXPORT bool NpPlayer::quit () {
|
|
if (playing ()) {
|
|
stop ();
|
|
TQTime t;
|
|
t.start ();
|
|
do {
|
|
TDEProcessController::theTDEProcessController->waitForProcessExit (2);
|
|
} while (t.elapsed () < 2000 && m_process->isRunning ());
|
|
return Process::quit ();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::processOutput (TDEProcess *, char * str, int slen) {
|
|
if (viewer () && slen > 0)
|
|
viewer ()->view ()->addText (TQString::fromLocal8Bit (str, slen));
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::processStopped (TDEProcess *) {
|
|
terminateJobs ();
|
|
if (m_source)
|
|
((PlayListNotify *) m_source)->setInfoMessage (TQString ());
|
|
setState (NotRunning);
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::streamStateChanged () {
|
|
setState (Playing); // hmm, this doesn't really fit in current states
|
|
if (!write_in_progress)
|
|
processStreams ();
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::streamRedirected (TQ_UINT32 sid, const KURL &u) {
|
|
if (playing () && dbus_static->dbus_connnection) {
|
|
kdDebug() << "redirected " << sid << " to " << u.url() << endl;
|
|
char *cu = strdup (u.url ().local8Bit().data ());
|
|
TQString objpath = TQString ("/plugin/stream_%1").arg (sid);
|
|
DBusMessage *msg = dbus_message_new_method_call (
|
|
remote_service.ascii(),
|
|
objpath.ascii (),
|
|
"org.kde.kmplayer.backend",
|
|
"redirected");
|
|
dbus_message_append_args(msg, DBUS_TYPE_STRING, &cu, DBUS_TYPE_INVALID);
|
|
dbus_message_set_no_reply (msg, TRUE);
|
|
dbus_connection_send (dbus_static->dbus_connnection, msg, NULL);
|
|
dbus_message_unref (msg);
|
|
dbus_connection_flush (dbus_static->dbus_connnection);
|
|
free (cu);
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::processStreams () {
|
|
NpStream *stream = 0L;
|
|
TQ_UINT32 stream_id;
|
|
timeval tv = { 0x7fffffff, 0 };
|
|
const StreamMap::iterator e = streams.end ();
|
|
int active_count = 0;
|
|
//kdDebug() << "NpPlayer::processStreams " << streams.size() << endl;
|
|
for (StreamMap::iterator i = streams.begin (); i != e;) {
|
|
NpStream *ns = i.data ();
|
|
if (ns->job) {
|
|
active_count++;
|
|
} else if (active_count < 5 &&
|
|
ns->finish_reason == NpStream::NoReason) {
|
|
write_in_progress = true; // javascript: urls emit stateChange
|
|
ns->open ();
|
|
write_in_progress = false;
|
|
if (ns->job) {
|
|
connect (ns, TQT_SIGNAL (redirected (TQ_UINT32, const KURL&)),
|
|
this, TQT_SLOT (streamRedirected (TQ_UINT32, const KURL&)));
|
|
active_count++;
|
|
}
|
|
}
|
|
if (ns->finish_reason == NpStream::BecauseStopped ||
|
|
ns->finish_reason == NpStream::BecauseError ||
|
|
(ns->finish_reason == NpStream::BecauseDone &&
|
|
ns->pending_buf.size () == 0)) {
|
|
sendFinish (i.key(), ns->bytes, ns->finish_reason);
|
|
StreamMap::iterator ii = i;
|
|
++ii;
|
|
streams.erase (i);
|
|
i = ii;
|
|
delete ns;
|
|
} else {
|
|
if (ns->pending_buf.size () > 0 &&
|
|
(ns->data_arrival.tv_sec < tv.tv_sec ||
|
|
(ns->data_arrival.tv_sec == tv.tv_sec &&
|
|
ns->data_arrival.tv_usec < tv.tv_usec))) {
|
|
tv = ns->data_arrival;
|
|
stream = ns;
|
|
stream_id = i.key();
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
//kdDebug() << "NpPlayer::processStreams " << stream << endl;
|
|
if (stream) {
|
|
if (dbus_static->dbus_connnection &&
|
|
!stream->bytes &&
|
|
(!stream->mimetype.isEmpty() || stream->content_length)) {
|
|
char *mt = strdup (stream->mimetype.isEmpty ()
|
|
? ""
|
|
: stream->mimetype.utf8 ().data ());
|
|
TQString objpath=TQString("/plugin/stream_%1").arg(stream->stream_id);
|
|
DBusMessage *msg = dbus_message_new_method_call (
|
|
remote_service.ascii(),
|
|
objpath.ascii (),
|
|
"org.kde.kmplayer.backend",
|
|
"streamInfo");
|
|
dbus_message_append_args (msg,
|
|
DBUS_TYPE_STRING, &mt,
|
|
DBUS_TYPE_UINT32, &stream->content_length,
|
|
DBUS_TYPE_INVALID);
|
|
dbus_message_set_no_reply (msg, TRUE);
|
|
dbus_connection_send (dbus_static->dbus_connnection, msg, NULL);
|
|
dbus_message_unref (msg);
|
|
dbus_connection_flush (dbus_static->dbus_connnection);
|
|
free (mt);
|
|
}
|
|
const int header_len = 2 * sizeof (TQ_UINT32);
|
|
TQ_UINT32 chunk = stream->pending_buf.size();
|
|
send_buf.resize (chunk + header_len);
|
|
memcpy (send_buf.data (), &stream_id, sizeof (TQ_UINT32));
|
|
memcpy (send_buf.data() + sizeof (TQ_UINT32), &chunk, sizeof (TQ_UINT32));
|
|
memcpy (send_buf.data()+header_len, stream->pending_buf.data (), chunk);
|
|
stream->pending_buf = TQByteArray ();
|
|
/*fprintf (stderr, " => %d %d\n", (long)stream_id, chunk);*/
|
|
stream->bytes += chunk;
|
|
write_in_progress = true;
|
|
m_process->writeStdin (send_buf.data (), send_buf.size ());
|
|
if (stream->finish_reason == NpStream::NoReason)
|
|
stream->job->resume ();
|
|
}
|
|
}
|
|
|
|
KDE_NO_EXPORT void NpPlayer::wroteStdin (TDEProcess *) {
|
|
write_in_progress = false;
|
|
if (playing ())
|
|
processStreams ();
|
|
}
|
|
|
|
KDE_NO_EXPORT TQString NpPlayer::menuName () const {
|
|
return i18n ("&Ice Ape");
|
|
}
|
|
|
|
#else
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
NpStream::NpStream (TQObject *p, TQ_UINT32, const KURL & url)
|
|
: TQObject (p) {}
|
|
|
|
KDE_NO_CDTOR_EXPORT NpStream::~NpStream () {}
|
|
void NpStream::slotResult (TDEIO::Job*) {}
|
|
void NpStream::slotData (TDEIO::Job*, const TQByteArray&) {}
|
|
void NpStream::redirection (TDEIO::Job *, const KURL &) {}
|
|
void NpStream::slotMimetype (TDEIO::Job *, const TQString &) {}
|
|
void NpStream::slotTotalSize (TDEIO::Job *, TDEIO::filesize_t) {}
|
|
|
|
KDE_NO_CDTOR_EXPORT
|
|
NpPlayer::NpPlayer (TQObject * parent, Settings * settings, const TQString &)
|
|
: Process (parent, settings, "npp") {}
|
|
KDE_NO_CDTOR_EXPORT NpPlayer::~NpPlayer () {}
|
|
KDE_NO_EXPORT void NpPlayer::init () {}
|
|
KDE_NO_EXPORT bool NpPlayer::deMediafiedPlay () { return false; }
|
|
KDE_NO_EXPORT void NpPlayer::initProcess (Viewer *) {}
|
|
KDE_NO_EXPORT TQString NpPlayer::menuName () const { return TQString (); }
|
|
KDE_NO_EXPORT void NpPlayer::setStarted (const TQString &) {}
|
|
KDE_NO_EXPORT bool NpPlayer::stop () { return false; }
|
|
KDE_NO_EXPORT bool NpPlayer::quit () { return false; }
|
|
KDE_NO_EXPORT bool NpPlayer::ready (Viewer *) { return false; }
|
|
KDE_NO_EXPORT void NpPlayer::processOutput (TDEProcess *, char *, int) {}
|
|
KDE_NO_EXPORT void NpPlayer::processStopped (TDEProcess *) {}
|
|
KDE_NO_EXPORT void NpPlayer::wroteStdin (TDEProcess *) {}
|
|
KDE_NO_EXPORT void NpPlayer::streamStateChanged () {}
|
|
KDE_NO_EXPORT void NpPlayer::streamRedirected (TQ_UINT32, const KURL &) {}
|
|
KDE_NO_EXPORT void NpPlayer::terminateJobs () {}
|
|
|
|
#endif
|
|
|
|
#include "kmplayerprocess.moc"
|