/* This file is part of the KDE project * * Copyright (C) 2003 Koos Vriezen * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DBUS # include # include #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 * tqparent, Settings * settings, const char * n) : TQObject (tqparent, 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 KProcess; m_process->setUseShell (true); m_process->setEnvironment (TQString::tqfromLatin1 ("SESSION_MANAGER"), TQString::tqfromLatin1 ("")); 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); KProcessController::theKProcessController->waitForProcessExit (1); if (!m_process->isRunning ()) break; m_process->kill (SIGKILL); KProcessController::theKProcessController->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 = KIO::stat (m_url, false); connect(m_job, TQT_SIGNAL (result(KIO::Job *)), this, TQT_SLOT(result(KIO::Job *))); return true; #else return deMediafiedPlay (); #endif } bool Process::deMediafiedPlay () { return false; } void Process::result (KIO::Job * job) { #if KDE_IS_VERSION(3,3,91) KIO::UDSEntry entry = static_cast (job)->statResult (); KIO::UDSEntry::iterator e = entry.end (); for (KIO::UDSEntry::iterator it = entry.begin (); it != e; ++it) if ((*it).m_uds == KIO::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 * tqparent, Settings * settings, const char * n) : Process (tqparent, settings, n), m_use_slave (true) { m_process = new KProcess; } 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 (KProcess *)), this, TQT_SLOT (dataWritten (KProcess *))); connect (m_process, TQT_SIGNAL (processExited (KProcess *)), this, TQT_SLOT (processStopped (KProcess *))); } 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 (KProcess *)), this, TQT_SLOT (processStopped (KProcess *))); 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 { KProcessController::theKProcessController->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 (KProcess *) { 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 (KProcess *) { 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 * tqparent, Settings * settings) : MPlayerBase (tqparent, 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->tqparent ()) 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 += KProcess::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 += KProcess::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 (KProcess *, char *, int)), this, TQT_SLOT (processOutput (KProcess *, char *, int))); connect (m_process, TQT_SIGNAL (receivedStderr (KProcess *, char *, int)), this, TQT_SLOT (processOutput (KProcess *, 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::tqfromLatin1 ("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 " <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 " <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 (n)->getAttribute ("mplayeropts"); if (!plops.isNull ()) { TQStringList sl = TQStringList::split (TQChar (' '), plops); for (int i = 0; i < sl.size (); ++i) { TQString plop = KProcess::quote (sl[i]); fprintf (stderr, " %s", plop.ascii ()); *m_process << " " << plop; } break; } } fprintf (stderr, " %s\n", args); *m_process << " " << args; TQValueList::const_iterator it; TQString sMPArgs; TQValueList::const_iterator end( m_process->args().end() ); for ( it = m_process->args().begin(); it != end; ++it ){ sMPArgs += (*it); } m_process->start (KProcess::NotifyOnExit, KProcess::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 += KProcess::quote (outdir); args += TQString (" -frames 1 -nosound -quiet "); if (pos > 0) args += TQString ("-ss %1 ").arg (pos); args += KProcess::quote (TQString (TQFile::encodeName (myurl))); *m_process << args; kdDebug () << args << endl; m_process->start (KProcess::NotifyOnExit, KProcess::NoCommunication); return m_process->isRunning (); } KDE_NO_EXPORT void MPlayer::processOutput (KProcess *, 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.tqfind ('='); 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.tqfind ('='); 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.tqfind ('='); 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.tqfind ('='); if (pos > 0) { bool ok; TQString val = out.mid (pos + 1); float a = val.toFloat (&ok); if (!ok) { val.tqreplace (',', '.'); a = val.toFloat (&ok); } if (ok && a > 0.001) m_source->setAspect (m_mrl, a); } } else if (out.startsWith ("ID_AID_")) { int pos = out.tqfind ('_', 7); if (pos > 0) { int id = out.mid (7, pos - 7).toInt (); pos = out.tqfind ('=', 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 < 0) { int id = out.mid (7, pos - 7).toInt (); pos = out.tqfind ('=', 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 < 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 * tqparent); TQTable * table; }; } // namespace KDE_NO_CDTOR_EXPORT MPlayerPreferencesFrame::MPlayerPreferencesFrame (TQWidget * tqparent) : TQFrame (tqparent) { TQVBoxLayout * tqlayout = 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); tqlayout->addWidget (table); } KDE_NO_CDTOR_EXPORT MPlayerPreferencesPage::MPlayerPreferencesPage (MPlayer * p) : m_process (p), m_configframe (0L) { } KDE_NO_EXPORT void MPlayerPreferencesPage::write (KConfig * 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 (KConfig * 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(table->cellWidget (2, 1)); TQCheckBox * buildIndex = static_cast(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 * tqparent) { m_configframe = new MPlayerPreferencesFrame (tqparent); return m_configframe; } //----------------------------------------------------------------------------- static const char * mencoder_supports [] = { "dvdsource", "pipesource", "tvscanner", "tvsource", "urlsource", "vcdsource", "audiocdsource", 0L }; KDE_NO_CDTOR_EXPORT MEncoder::MEncoder (TQObject * tqparent, Settings * settings) : MPlayerBase (tqparent, 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.tqreplace (0, 6, TQString (" -vcd ")); else if (!post090 && myurl.startsWith (TQString ("dvd://"))) args += myurl.tqreplace (0, 6, TQString (" -dvd ")); else args += ' ' + KProcess::quote (TQString (TQFile::encodeName (myurl))); } TQString outurl = KProcess::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 (KProcess::NotifyOnExit, KProcess::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 * tqparent, Settings * settings) : MPlayerBase (tqparent, 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.tqreplace (0, 6, TQString (" -vcd ")); else if (!post090 && myurl.startsWith (TQString ("dvd://"))) args += myurl.tqreplace (0, 6, TQString (" -dvd ")); else args += ' ' + KProcess::quote (TQString (TQFile::encodeName (myurl))); } TQString outurl = KProcess::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 (KProcess::NotifyOnExit, KProcess::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 * tqparent, Settings * settings, const char * n, const TQString & menuname) : Process (tqparent, 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 { KProcessController::theKProcessController->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 (KProcess *)), this, TQT_SLOT (processStopped (KProcess *))); connect (m_process, TQT_SIGNAL (receivedStdout (KProcess *, char *, int)), this, TQT_SLOT (processOutput (KProcess *, char *, int))); connect (m_process, TQT_SIGNAL (receivedStderr (KProcess *, char *, int)), this, TQT_SLOT (processOutput (KProcess *, char *, int))); } KDE_NO_EXPORT void CallbackProcess::processOutput (KProcess *, char * str, int slen) { if (viewer () && slen > 0) viewer ()->view ()->addText (TQString::fromLocal8Bit (str, slen)); } KDE_NO_EXPORT void CallbackProcess::processStopped (KProcess *) { 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 * tqparent) { 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 (), Qt::Horizontal, tqparent); } else if (!strcmp (ctype, "num") || !strcmp (ctype, "string")) { w = new TQLineEdit (value, tqparent); } else if (!strcmp (ctype, "bool")) { TQCheckBox * checkbox = new TQCheckBox (tqparent); checkbox->setChecked (value.toInt ()); w = checkbox; } else if (!strcmp (ctype, "enum")) { TQComboBox * combo = new TQComboBox (tqparent); for (NodePtr e = firstChild (); e; e = e->nextSibling ()) if (e->isElementNode () && !strcmp (e->nodeName (), "item")) combo->insertItem (convertNode (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 (w)->value ()); } else if (!strcmp (ctype, "num") || !strcmp (ctype, "string")) { newvalue = static_cast (w)->text (); } else if (!strcmp (ctype, "bool")) { newvalue = TQString::number (static_cast (w)->isChecked()); } else if (!strcmp (ctype, "enum")) { newvalue = TQString::number (static_cast(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 * tqparent, CallbackProcess *); KDE_NO_CDTOR_EXPORT ~XMLPreferencesFrame () {} TQTable * table; protected: void showEvent (TQShowEvent *); private: CallbackProcess * m_process; }; } // namespace KDE_NO_CDTOR_EXPORT XMLPreferencesFrame::XMLPreferencesFrame (TQWidget * tqparent, CallbackProcess * p) : TQFrame (tqparent), m_process (p){ TQVBoxLayout * tqlayout = new TQVBoxLayout (this); table = new TQTable (this); tqlayout->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 (KConfig *) { } KDE_NO_EXPORT void XMLPreferencesPage::read (KConfig *) { } 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 << ""; for (NodePtr e = elm->firstChild (); e; e = e->nextSibling ()) convertNode (e)->changedXML (ts); if (str.length () > 10) { ts << ""; 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 (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 * tqparent) { m_configframe = new XMLPreferencesFrame (tqparent, 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 * tqparent, Settings * settings) : CallbackProcess (tqparent, 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 = KProcess::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 = KProcess::quote ( TQString (TQFile::encodeName (getPath (m_recordurl)))); fprintf (stderr, " -rec %s", rf.ascii ()); *m_process << " -rec " << rf; } fprintf (stderr, "\n"); m_process->start (KProcess::NotifyOnExit, KProcess::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 * tqparent, Settings * settings) : CallbackProcess (tqparent, 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 (KProcess::NotifyOnExit, KProcess::All); return m_process->isRunning (); } //----------------------------------------------------------------------------- static const char * ffmpeg_supports [] = { "tvsource", "urlsource", 0L }; FFMpeg::FFMpeg (TQObject * tqparent, Settings * settings) : Process (tqparent, 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 (KProcess *)), this, TQT_SLOT (processStopped (KProcess *))); 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"); KProcess 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 (KProcess::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 (KProcess::Block); } } else { cmd += TQString ("-i ") + KProcess::quote (TQString (TQFile::encodeName (url.isLocalFile () ? getPath (url) : url.url ()))); } cmd += TQChar (' ') + m_settings->ffmpegarguments; cmd += TQChar (' ') + KProcess::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 (KProcess::NotifyOnExit, KProcess::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 { KProcessController::theKProcessController->waitForProcessExit (2); } while (t.elapsed () < 2000 && m_process->isRunning ()); return Process::quit (); } KDE_NO_EXPORT void FFMpeg::processStopped (KProcess *) { 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 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 (tqparent ()); 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 = KIO::get (url, false, false); job->addMetaData ("errorPage", "false"); connect (job, TQT_SIGNAL (data (KIO::Job *, const TQByteArray &)), this, TQT_SLOT (slotData (KIO::Job *, const TQByteArray &))); connect (job, TQT_SIGNAL (result (KIO::Job *)), this, TQT_SLOT (slotResult (KIO::Job *))); connect (job, TQT_SIGNAL (redirection (KIO::Job *, const KURL &)), this, TQT_SLOT (redirection (KIO::Job *, const KURL &))); connect (job, TQT_SIGNAL (mimetype (KIO::Job *, const TQString &)), TQT_SLOT (slotMimetype (KIO::Job *, const TQString &))); connect (job, TQT_SIGNAL (totalSize (KIO::Job *, KIO::filesize_t)), TQT_SLOT (slotTotalSize (KIO::Job *, KIO::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 (KIO::Job *jb) { kdDebug() << "slotResult " << bytes << " err:" << jb->error () << endl; finish_reason = jb->error () ? BecauseError : BecauseDone; job = 0L; // signal KIO::Job::result deletes itself emit stateChanged (); } KDE_NO_EXPORT void NpStream::slotData (KIO::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 (KIO::Job *, const KURL &u) { url = u; emit redirected (stream_id, url); } void NpStream::slotMimetype (KIO::Job *, const TQString &mime) { mimetype = mime; } void NpStream::slotTotalSize (KIO::Job *, KIO::filesize_t sz) { content_length = sz; } static const char * npplayer_supports [] = { "urlsource", 0L }; KDE_NO_CDTOR_EXPORT NpPlayer::NpPlayer (TQObject * tqparent, Settings * settings, const TQString & srv) : Process (tqparent, 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 (KProcess *)), this, TQT_SLOT (processStopped (KProcess *))); connect (m_process, TQT_SIGNAL (receivedStdout (KProcess *, char *, int)), this, TQT_SLOT (processOutput (KProcess *, char *, int))); connect (m_process, TQT_SIGNAL (receivedStderr (KProcess *, char *, int)), this, TQT_SLOT (processOutput (KProcess *, char *, int))); connect (m_process, TQT_SIGNAL (wroteStdin (KProcess *)), this, TQT_SLOT (wroteStdin (KProcess *))); 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 (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 (KProcess::NotifyOnExit, KProcess::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.tqfindRev (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.tqcontains ((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 { KProcessController::theKProcessController->waitForProcessExit (2); } while (t.elapsed () < 2000 && m_process->isRunning ()); return Process::quit (); } return true; } KDE_NO_EXPORT void NpPlayer::processOutput (KProcess *, char * str, int slen) { if (viewer () && slen > 0) viewer ()->view ()->addText (TQString::fromLocal8Bit (str, slen)); } KDE_NO_EXPORT void NpPlayer::processStopped (KProcess *) { 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").tqarg(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 (KProcess *) { 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 (KIO::Job*) {} void NpStream::slotData (KIO::Job*, const TQByteArray&) {} void NpStream::redirection (KIO::Job *, const KURL &) {} void NpStream::slotMimetype (KIO::Job *, const TQString &) {} void NpStream::slotTotalSize (KIO::Job *, KIO::filesize_t) {} KDE_NO_CDTOR_EXPORT NpPlayer::NpPlayer (TQObject * tqparent, Settings * settings, const TQString &) : Process (tqparent, 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 (KProcess *, char *, int) {} KDE_NO_EXPORT void NpPlayer::processStopped (KProcess *) {} KDE_NO_EXPORT void NpPlayer::wroteStdin (KProcess *) {} 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"