File indexing completed on 2024-04-21 15:38:15

0001 /* this file is part of the kmplayer application
0002    copyright (c) 2003 koos vriezen <koos.vriezen@xs4all.nl>
0003 
0004    this program is free software; you can redistribute it and/or
0005    modify it under the terms of the gnu general public
0006    license as published by the free software foundation; either
0007    version 2 of the license, or (at your option) any later version.
0008 
0009    this program is distributed in the hope that it will be useful,
0010    but without any warranty; without even the implied warranty of
0011    merchantability or fitness for a particular purpose.  see the gnu
0012     general public license for more details.
0013 
0014    you should have received a copy of the gnu general public license
0015    along with this program; see the file copying.  if not, write to
0016    the free software foundation, inc., 59 temple place - suite 330,
0017    boston, ma 02111-1307, usa.
0018 */
0019 #include <algorithm>
0020 
0021 #include <qlayout.h>
0022 #include <qlabel.h>
0023 #include <qpushbutton.h>
0024 #include <qtable.h>
0025 #include <qstringlist.h>
0026 #include <qcombobox.h>
0027 #include <qlistbox.h>
0028 #include <qlineedit.h>
0029 #include <qwhatsthis.h>
0030 #include <qtabwidget.h>
0031 #include <qcursor.h>
0032 #include <qdir.h>
0033 #include <qfile.h>
0034 #include <qtimer.h>
0035 
0036 #include <klocalizedstring.h>
0037 #include <kdebug.h>
0038 #include <kled.h>
0039 #include <kconfig.h>
0040 #include <kprocess.h>
0041 #include <kprocctrl.h>
0042 #include <kmessagebox.h>
0043 
0044 #include "kmplayerbroadcast.h"
0045 #include "kmplayerprocess.h"
0046 #include "kmplayerview.h"
0047 #include "kmplayerpartbase.h"
0048 
0049 static const char * strBroadcast = "Broadcast";
0050 static const char * strBindAddress = "Bind Address";
0051 static const char * strFFServerPort = "FFServer Port";
0052 static const char * strMaxClients = "Maximum Connections";
0053 static const char * strMaxBandwidth = "Maximum Bandwidth";
0054 static const char * strFeedFile = "Feed File";
0055 static const char * strFeedFileSize = "Feed File Size";
0056 //static const char * strFFServerSetting = "FFServer Setting";
0057 static const char * strFFServerCustomSetting = "Custom Setting";
0058 static const char * strFFServerProfiles = "Profiles";
0059 
0060 
0061 KDE_NO_CDTOR_EXPORT FFServerSetting::FFServerSetting (int i, const QString & n, const QString & f, const QString & ac, int abr, int asr, const QString & vc, int vbr, int q, int fr, int gs, int w, int h)
0062  : index (i), name (n), format (f), audiocodec (ac),
0063    audiobitrate (abr > 0 ? QString::number (abr) : QString ()),
0064    audiosamplerate (asr > 0 ? QString::number (asr) : QString ()),
0065    videocodec (vc),
0066    videobitrate (vbr > 0 ? QString::number (vbr) : QString ()),
0067    quality (q > 0 ? QString::number (q) : QString ()),
0068    framerate (fr > 0 ? QString::number (fr) : QString ()),
0069    gopsize (gs > 0 ? QString::number (gs) : QString ()),
0070    width (w > 0 ? QString::number (w) : QString ()),
0071    height (h > 0 ? QString::number (h) : QString ()) {}
0072 
0073 KDE_NO_EXPORT FFServerSetting & FFServerSetting::operator = (const FFServerSetting & fs) {
0074     format = fs.format;
0075     audiocodec = fs.audiocodec;
0076     audiobitrate = fs.audiobitrate;
0077     audiosamplerate = fs.audiosamplerate;
0078     videocodec = fs.videocodec;
0079     videobitrate = fs.videobitrate;
0080     quality = fs.quality;
0081     framerate = fs.framerate;
0082     gopsize = fs.gopsize;
0083     width = fs.width;
0084     height = fs.height;
0085     return *this;
0086 }
0087 
0088 KDE_NO_EXPORT FFServerSetting & FFServerSetting::operator = (const QStringList & sl) {
0089     if (sl.count () < 11) {
0090         return *this;
0091     }
0092     QStringList::const_iterator it = sl.begin ();
0093     format = *it++;
0094     audiocodec = *it++;
0095     audiobitrate = *it++;
0096     audiosamplerate = *it++;
0097     videocodec = *it++;
0098     videobitrate = *it++;
0099     quality = *it++;
0100     framerate = *it++;
0101     gopsize = *it++;
0102     width = *it++;
0103     height = *it++;
0104     acl.clear ();
0105     QStringList::const_iterator end( sl.end() );
0106     for (; it != end; ++it)
0107         acl.push_back (*it);
0108     return *this;
0109 }
0110 
0111 KDE_NO_EXPORT QString & FFServerSetting::ffconfig (QString & buf) {
0112     QString nl ("\n");
0113     buf = QString ("Format ") + format + nl;
0114     if (!audiocodec.isEmpty ())
0115         buf += QString ("AudioCodec ") + audiocodec + nl;
0116     if (!audiobitrate.isEmpty ())
0117         buf += QString ("AudioBitRate ") + audiobitrate + nl;
0118     if (!audiosamplerate.isEmpty () > 0)
0119         buf += QString ("AudioSampleRate ") + audiosamplerate + nl;
0120     if (!videocodec.isEmpty ())
0121         buf += QString ("VideoCodec ") + videocodec + nl;
0122     if (!videobitrate.isEmpty ())
0123         buf += QString ("VideoBitRate ") + videobitrate + nl;
0124     if (!quality.isEmpty ())
0125         buf += QString ("VideoQMin ") + quality + nl;
0126     if (!framerate.isEmpty ())
0127         buf += QString ("VideoFrameRate ") + framerate + nl;
0128     if (!gopsize.isEmpty ())
0129         buf += QString ("VideoGopSize ") + gopsize + nl;
0130     if (!width.isEmpty () && !height.isEmpty ())
0131         buf += QString ("VideoSize ") + width + QString ("x") + height + nl;
0132     return buf;
0133 }
0134 
0135 KDE_NO_EXPORT const QStringList FFServerSetting::list () {
0136     QStringList sl;
0137     sl.push_back (format);
0138     sl.push_back (audiocodec);
0139     sl.push_back (audiobitrate);
0140     sl.push_back (audiosamplerate);
0141     sl.push_back (videocodec);
0142     sl.push_back (videobitrate);
0143     sl.push_back (quality);
0144     sl.push_back (framerate);
0145     sl.push_back (gopsize);
0146     sl.push_back (width);
0147     sl.push_back (height);
0148     QStringList::const_iterator it = acl.begin ();
0149     QStringList::const_iterator end( acl.end () );
0150     for (; it != end; ++it)
0151         sl.push_back (*it);
0152     return sl;
0153 }
0154 
0155 //-----------------------------------------------------------------------------
0156 
0157 KDE_NO_CDTOR_EXPORT KMPlayerPrefBroadcastPage::KMPlayerPrefBroadcastPage (QWidget *parent) : QFrame (parent) {
0158     QVBoxLayout *layout = new QVBoxLayout (this, 5);
0159     QGridLayout *gridlayout = new QGridLayout (layout, 6, 2, 2);
0160     QLabel *label = new QLabel (i18n ("Bind address:"), this);
0161     bindaddress = new QLineEdit ("", this);
0162     QWhatsThis::add (bindaddress, i18n ("If you have multiple network devices, you can limit access"));
0163     gridlayout->addWidget (label, 0, 0);
0164     gridlayout->addWidget (bindaddress, 0, 1);
0165     label = new QLabel (i18n ("Listen port:"), this);
0166     port = new QLineEdit ("", this);
0167     gridlayout->addWidget (label, 1, 0);
0168     gridlayout->addWidget (port, 1, 1);
0169     label = new QLabel (i18n ("Maximum connections:"), this);
0170     maxclients = new QLineEdit ("", this);
0171     gridlayout->addWidget (label, 2, 0);
0172     gridlayout->addWidget (maxclients, 2, 1);
0173     label = new QLabel (i18n ("Maximum bandwidth (kbit):"), this);
0174     maxbandwidth = new QLineEdit ("", this);
0175     gridlayout->addWidget (label, 3, 0);
0176     gridlayout->addWidget (maxbandwidth, 3, 1);
0177     label = new QLabel (i18n ("Temporary feed file:"), this);
0178     feedfile = new QLineEdit ("", this);
0179     gridlayout->addWidget (label, 4, 0);
0180     gridlayout->addWidget (feedfile, 4, 1);
0181     label = new QLabel (i18n ("Feed file size (kB):"), this);
0182     feedfilesize = new QLineEdit ("", this);
0183     gridlayout->addWidget (label, 5, 0);
0184     gridlayout->addWidget (feedfilesize, 5, 1);
0185     layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
0186 }
0187 
0188 //-----------------------------------------------------------------------------
0189 
0190 #undef ADDPROPERTY
0191 #define ADDPROPERTY(label,qedit,gridlayout,row,parent)                  \
0192     qedit = new QLineEdit ("", parent);                                 \
0193     gridlayout->addWidget (new QLabel (qedit, label, parent), row, 0);  \
0194     gridlayout->addWidget (qedit, row, 1);
0195 
0196 KDE_NO_CDTOR_EXPORT KMPlayerPrefBroadcastFormatPage::KMPlayerPrefBroadcastFormatPage (QWidget *parent, FFServerSettingList & ffs) : QFrame (parent, "BroadcastPage"), profiles (ffs)
0197 {
0198     QHBoxLayout *layout = new QHBoxLayout (this, 5);
0199     QGridLayout *formatlayout = new QGridLayout (11, 2, 2);
0200     formatlayout->setAlignment (Qt::AlignTop);
0201     QVBoxLayout *leftlayout = new QVBoxLayout (15);
0202     QHBoxLayout *ledlayout = new QHBoxLayout (5);
0203     format = new QComboBox (this);
0204     QLabel * label = new QLabel (format, i18n ("Format:"), this);
0205     format->clear ();
0206     format->insertItem (QString ("asf"));
0207     format->insertItem (QString ("avi"));
0208     format->insertItem (QString ("mpjpeg"));
0209     format->insertItem (QString ("mpeg"));
0210     format->insertItem (QString ("rm"));
0211     format->insertItem (QString ("swf"));
0212     QWhatsThis::add (format, i18n ("Only avi, mpeg and rm work for mplayer playback"));
0213     formatlayout->addWidget (label, 0, 0);
0214     formatlayout->addWidget (format, 0, 1);
0215     ADDPROPERTY (i18n ("Audio codec:"), audiocodec, formatlayout, 1, this);
0216     ADDPROPERTY (i18n ("Audio bit rate (kbit):"), audiobitrate, formatlayout, 2, this);
0217     ADDPROPERTY (i18n ("Audio sample rate (Hz):"), audiosamplerate, formatlayout, 3, this);
0218     ADDPROPERTY (i18n ("Video codec:"), videocodec, formatlayout, 4, this);
0219     ADDPROPERTY (i18n ("Video bit rate (kbit):"), videobitrate, formatlayout, 5, this);
0220     ADDPROPERTY (i18n ("Quality (1-31):"), quality, formatlayout, 6, this);
0221     ADDPROPERTY (i18n ("Frame rate (Hz):"), framerate, formatlayout, 7, this);
0222     ADDPROPERTY (i18n ("Gop size:"), gopsize, formatlayout, 8, this);
0223     ADDPROPERTY (i18n ("Width (pixels):"), moviewidth, formatlayout, 9, this);
0224     ADDPROPERTY (i18n ("Height (pixels):"), movieheight, formatlayout, 10, this);
0225     label = new QLabel (i18n ("Allow access from:"), this);
0226     accesslist = new QTable (40, 1, this);
0227     accesslist->verticalHeader ()->hide ();
0228     accesslist->setLeftMargin (0);
0229     accesslist->setColumnWidth (0, 250);
0230     QWhatsThis::add (accesslist, i18n ("'Single IP' or 'start-IP end-IP' for IP ranges"));
0231     QHeader *header = accesslist->horizontalHeader ();
0232     header->setLabel (0, i18n ("Host/IP or IP Range"));
0233     QFrame *profileframe = new QFrame (this);
0234     QGridLayout *profileslayout = new QGridLayout (profileframe, 5, 2, 2);
0235     profile = new QLineEdit ("", profileframe);
0236     connect (profile, SIGNAL(textChanged (const QString &)),
0237              this, SLOT (slotTextChanged (const QString &)));
0238     profilelist = new QListBox (profileframe);
0239     for (int i = 0; i < (int) profiles.size (); i++)
0240         profilelist->insertItem (profiles[i]->name, i);
0241     connect (profilelist, SIGNAL (selected (int)),
0242              this, SLOT (slotIndexChanged (int)));
0243     connect (profilelist, SIGNAL (highlighted (int)),
0244              this, SLOT (slotItemHighlighted (int)));
0245     load = new QPushButton (i18n ("Load"), profileframe);
0246     save = new QPushButton (i18n ("Save"), profileframe);
0247     del = new QPushButton (i18n ("Delete"), profileframe);
0248     load->setEnabled (false);
0249     save->setEnabled (false);
0250     del->setEnabled (false);
0251     connect (load, SIGNAL (clicked ()), this, SLOT (slotLoad ()));
0252     connect (save, SIGNAL (clicked ()), this, SLOT (slotSave ()));
0253     connect (del, SIGNAL (clicked ()), this, SLOT (slotDelete ()));
0254     profileslayout->addWidget (profile, 0, 0);
0255 #if (QT_VERSION < 0x030200)
0256     profileslayout->addRowSpacing (4, 60);
0257 #else
0258     profileslayout->setRowSpacing (4, 60);
0259 #endif
0260     profileslayout->addMultiCellWidget (profilelist, 1, 4, 0, 0);
0261     profileslayout->addWidget (load, 1, 1);
0262     profileslayout->addWidget (save, 2, 1);
0263     profileslayout->addWidget (del, 3, 1);
0264     leftlayout->addWidget (profileframe);
0265     startbutton = new QPushButton (i18n ("Start"), this);
0266     serverled = new KLed (Qt::green, KLed::Off, KLed::Raised, KLed::Circular, this);
0267     feedled = new KLed (Qt::green, KLed::Off, KLed::Raised, KLed::Circular, this);
0268     ledlayout->addWidget (startbutton);
0269     ledlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
0270     ledlayout->addWidget (serverled);
0271     ledlayout->addWidget (feedled);
0272     leftlayout->addLayout (ledlayout);
0273     QFrame * line = new QFrame (this);
0274     line->setFrameShape (QFrame::HLine);
0275     leftlayout->addWidget (line);
0276     leftlayout->addWidget (label);
0277     leftlayout->addWidget (accesslist);
0278     leftlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
0279     layout->addLayout (leftlayout);
0280     line = new QFrame (this);
0281     line->setFrameShape (QFrame::VLine);
0282     layout->addWidget (line);
0283     layout->addLayout (formatlayout);
0284     layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
0285 }
0286 
0287 #undef ADDPROPERTY
0288 
0289 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::setSettings (const FFServerSetting & fs) {
0290     if (!fs.format.isEmpty ())
0291         format->setCurrentText (fs.format);
0292     audiocodec->setText (fs.audiocodec);
0293     audiobitrate->setText (fs.audiobitrate);
0294     audiosamplerate->setText (fs.audiosamplerate);
0295     videocodec->setText (fs.videocodec);
0296     videobitrate->setText (fs.videobitrate);
0297     quality->setText (fs.quality);
0298     framerate->setText (fs.framerate);
0299     gopsize->setText (fs.gopsize);
0300     moviewidth->setText (fs.width);
0301     movieheight->setText (fs.height);
0302     accesslist->setNumRows (0);
0303     accesslist->setNumRows (50);
0304     QStringList::const_iterator it = fs.acl.begin ();
0305     QStringList::const_iterator end( fs.acl.end () );
0306     for (int i = 0; it != end; ++i, ++it)
0307         accesslist->setItem (i, 0, new QTableItem (accesslist, QTableItem::Always, *it));
0308 }
0309 
0310 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::getSettings (FFServerSetting & fs) {
0311     fs.format = format->currentText ();
0312     fs.audiocodec = audiocodec->text ();
0313     fs.audiobitrate = audiobitrate->text ();
0314     fs.audiosamplerate = audiosamplerate->text ();
0315     fs.videocodec = videocodec->text ();
0316     fs.videobitrate = videobitrate->text ();
0317     fs.quality = quality->text ();
0318     fs.framerate = framerate->text ();
0319     fs.gopsize = gopsize->text ();
0320     fs.width = moviewidth->text ();
0321     fs.height = movieheight->text ();
0322     fs.acl.clear ();
0323     for (int i = 0; i < accesslist->numRows (); ++i) {
0324         if (accesslist->item (i, 0) && !accesslist->item (i, 0)->text ().isEmpty ())
0325             fs.acl.push_back (accesslist->item (i, 0)->text ());
0326     }
0327 }
0328 
0329 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotIndexChanged (int index) {
0330     slotItemHighlighted (index);
0331     if (index >= 0 && index < (int) profiles.size ())
0332         setSettings (*profiles[index]);
0333 }
0334 
0335 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotTextChanged (const QString & txt) {
0336     save->setEnabled (txt.size ());
0337 }
0338 
0339 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotItemHighlighted (int index) {
0340     if (index < 0 || index >= (int) profiles.size ()) {
0341         load->setEnabled (false);
0342         del->setEnabled (false);
0343     } else {
0344         profile->setText (profiles[profilelist->currentItem ()]->name);
0345         load->setEnabled (true);
0346         del->setEnabled (true);
0347         slotTextChanged (profilelist->currentText ());
0348     }
0349 }
0350 
0351 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotSave () {
0352     for (int i = 0; i < (int) profiles.size (); ++i)
0353         if (profiles[i]->name == profile->text ()) {
0354             getSettings (*profiles[i]);
0355             return;
0356         }
0357     FFServerSetting * fs = new FFServerSetting;
0358     fs->name = profile->text ();
0359     getSettings (*fs);
0360     profiles.push_back (fs);
0361     profilelist->insertItem (fs->name);
0362 }
0363 
0364 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotLoad () {
0365     setSettings (*profiles[profilelist->currentItem ()]);
0366 }
0367 
0368 KDE_NO_EXPORT void KMPlayerPrefBroadcastFormatPage::slotDelete () {
0369     FFServerSettingList::iterator it = profiles.begin();
0370     for (int i = 0; i < profilelist->currentItem (); i++)
0371         ++it;
0372     delete *it;
0373     profiles.erase (it);
0374     profilelist->removeItem (profilelist->currentItem ());
0375     load->setEnabled (false);
0376     del->setEnabled (false);
0377 }
0378 
0379 //-----------------------------------------------------------------------------
0380 
0381 static bool stopProcess (KProcess * process, const char * cmd = 0L) {
0382     if (!process || !process->isRunning ()) return true;
0383     do {
0384         if (cmd)
0385             process->writeStdin (cmd, strlen (cmd));
0386         KProcessController::theKProcessController->waitForProcessExit (1);
0387         if (!process->isRunning ())
0388             break;
0389         process->kill (SIGINT);
0390         KProcessController::theKProcessController->waitForProcessExit (3);
0391         if (!process->isRunning ())
0392             break;
0393         process->kill (SIGTERM);
0394         KProcessController::theKProcessController->waitForProcessExit (1);
0395         if (!process->isRunning ())
0396             break;
0397         process->kill (SIGKILL);
0398         KProcessController::theKProcessController->waitForProcessExit (1);
0399         if (process->isRunning ()) {
0400             return false; // give up
0401         }
0402     } while (false);
0403     return true;
0404 }
0405 
0406 
0407 KDE_NO_CDTOR_EXPORT KMPlayerBroadcastConfig::KMPlayerBroadcastConfig (KMPlayer::PartBase * player, KMPlayerFFServerConfig * fsc)
0408  : m_player (player),
0409    m_ffserverconfig (fsc),
0410    m_ffmpeg_process (0L),
0411    m_ffserver_process (0L),
0412    m_endserver (true) {
0413 }
0414 
0415 KDE_NO_CDTOR_EXPORT KMPlayerBroadcastConfig::~KMPlayerBroadcastConfig () {
0416     stopServer ();
0417 }
0418 
0419 KDE_NO_EXPORT void KMPlayerBroadcastConfig::write (KConfig * config) {
0420     config->setGroup (strBroadcast);
0421     config->writeEntry (strFFServerCustomSetting, ffserversettings.list (), ';');
0422     QStringList sl;
0423     for (int i = 0; i < (int) ffserversettingprofiles.size (); i++) {
0424         sl.push_back (ffserversettingprofiles[i]->name);
0425         config->writeEntry (QString ("Profile_") + ffserversettingprofiles[i]->name, ffserversettingprofiles[i]->list(), ';');
0426     }
0427     config->writeEntry (strFFServerProfiles, sl, ';');
0428 }
0429 
0430 KDE_NO_EXPORT void KMPlayerBroadcastConfig::read (KConfig * config) {
0431     std::for_each (ffserversettingprofiles.begin (), ffserversettingprofiles.end (), KMPlayer::Deleter<FFServerSetting>());
0432     ffserversettingprofiles.clear ();
0433     config->setGroup (strBroadcast);
0434     ffserversettings = config->readListEntry (strFFServerCustomSetting, ';');
0435     QStringList profiles = config->readListEntry (strFFServerProfiles, ';');
0436     QStringList::iterator pr_it = profiles.begin ();
0437     QStringList::iterator pr_end( profiles.end () );
0438     for (; pr_it != pr_end; ++pr_it) {
0439         QStringList sl = config->readListEntry (QString ("Profile_") + *pr_it, ';');
0440         if (sl.size () > 10) {
0441             FFServerSetting * ffs = new FFServerSetting (sl);
0442             ffs->name = *pr_it;
0443             ffserversettingprofiles.push_back (ffs);
0444         }
0445     }
0446 }
0447 
0448 KDE_NO_EXPORT void KMPlayerBroadcastConfig::sync (bool fromUI) {
0449     if (fromUI) {
0450         m_configpage->getSettings(ffserversettings);
0451     } else {
0452         m_configpage->setSettings (ffserversettings);
0453         m_configpage->profile->setText (QString ());
0454     }
0455 }
0456 
0457 KDE_NO_EXPORT void KMPlayerBroadcastConfig::prefLocation (QString & item, QString & icon, QString & tab) {
0458     item = i18n ("Broadcasting");
0459     icon = QString ("share");
0460     tab = i18n ("Profiles");
0461 }
0462 
0463 QFrame * KMPlayerBroadcastConfig::prefPage (QWidget * parent) {
0464     if (!m_configpage) {
0465         m_configpage = new KMPlayerPrefBroadcastFormatPage (parent, ffserversettingprofiles);
0466         connect (m_configpage->startbutton, SIGNAL (clicked ()), this, SLOT (startServer ()));
0467         connect (m_player, SIGNAL (sourceChanged (KMPlayer::Source *, KMPlayer::Source *)), this, SLOT (sourceChanged (KMPlayer::Source *,KMPlayer::Source *)));
0468         m_configpage->startbutton->setEnabled
0469             (!m_player->source ()->videoDevice ().isEmpty ());
0470     }
0471     return m_configpage;
0472 }
0473 
0474 KDE_NO_EXPORT bool KMPlayerBroadcastConfig::broadcasting () const {
0475     return m_ffserver_process && m_ffserver_process->isRunning ();
0476 }
0477 #include <kglobal.h>
0478 #include <kstandarddirs.h>
0479 
0480 static const char ffserverconf[] =
0481 "Port %d\nBindAddress %s\nMaxClients %d\nMaxBandwidth %d\n"
0482 "CustomLog -\nNoDaemon\n"
0483 "<Feed kmplayer.ffm>\nFile %s\nFileMaxSize %dK\nACL allow 127.0.0.1\n</Feed>\n"
0484 "<Stream video.%s>\nFeed kmplayer.ffm\n%s\n%s%s\n</Stream>\n"
0485 "<Stream stat.html>\nFormat status\nACL allow localhost\n</Stream>\n";
0486 
0487 KDE_NO_EXPORT void KMPlayerBroadcastConfig::startServer () {
0488     if (broadcasting ()) {
0489         stopServer ();
0490         return;
0491     }
0492     m_configpage->setCursor (QCursor (Qt::WaitCursor));
0493     m_ffserver_process = new KProcess;
0494     m_ffserver_process->setUseShell (true);
0495     connect (m_ffserver_process, SIGNAL (processExited (KProcess *)),
0496              this, SLOT (processStopped (KProcess *)));
0497     QString conffile = KStandardDirs::locateLocal ("data", "kmplayer/ffserver.conf");
0498     const char * noaudio = m_player->source ()->audioDevice ().isEmpty () ? "NoAudio" : "";
0499     FFServerSetting ffs;
0500     m_configpage->getSettings (ffs);
0501     QString acl;
0502     QStringList::iterator it = ffs.acl.begin ();
0503     QStringList::iterator end(  ffs.acl.end () );
0504     for (; it != end; ++it)
0505         acl += QString ("ACL allow ") + *it + QString ("\n");
0506     unlink (m_ffserverconfig->feedfile.ascii ());
0507     QFile qfile (conffile);
0508     qfile.open (IO_WriteOnly);
0509     QString configdata;
0510     QString buf;
0511     configdata.sprintf (ffserverconf, m_ffserverconfig->ffserverport, m_ffserverconfig->bindaddress.ascii (), m_ffserverconfig->maxclients, m_ffserverconfig->maxbandwidth, m_ffserverconfig->feedfile.ascii (), m_ffserverconfig->feedfilesize, ffs.format.ascii (), acl.ascii (), ffs.ffconfig (buf).ascii (), noaudio);
0512     qfile.writeBlock (configdata.ascii (), configdata.size ());
0513     qfile.close ();
0514     kdDebug () << configdata << endl;
0515     kdDebug () << "ffserver -f " << conffile << endl;
0516     *m_ffserver_process << "ffserver -f " << conffile;
0517     m_ffserver_out.truncate (0);
0518     connect (m_ffserver_process,
0519              SIGNAL (receivedStderr (KProcess *, char *, int)),
0520              this, SLOT (processOutput (KProcess *, char *, int)));
0521     m_ffserver_process->start (KProcess::NotifyOnExit, KProcess::Stderr);
0522     if (m_ffserver_process->isRunning ()) {
0523         m_configpage->startbutton->setText (i18n ("Stop"));
0524         m_configpage->serverled->setState (KLed::On);
0525         emit broadcastStarted ();
0526     }
0527     QTimer::singleShot (500, this, SLOT (startFeed ()));
0528 }
0529 
0530 KDE_NO_EXPORT void KMPlayerBroadcastConfig::stopServer () {
0531     m_endserver = true;
0532     if (m_ffmpeg_process)
0533         m_ffmpeg_process->stop ();
0534     if (!stopProcess (m_ffserver_process))
0535         KMessageBox::error (m_configpage, i18n ("Failed to end ffserver process."), i18n ("Error"));
0536 }
0537 
0538 KDE_NO_EXPORT void KMPlayerBroadcastConfig::processOutput (KProcess * p, char * s, int) {
0539     if (p == m_ffserver_process)
0540         m_ffserver_out += QString (s);
0541 }
0542 
0543 KDE_NO_EXPORT void KMPlayerBroadcastConfig::startFeed () {
0544     if (!m_configpage) {
0545         stopServer ();
0546         return;
0547     }
0548     FFServerSetting ffs;
0549     m_configpage->getSettings (ffs);
0550     QString ffurl;
0551     if (!m_ffserver_process || !m_ffserver_process->isRunning ()) {
0552         KMessageBox::error (m_configpage, i18n ("Failed to start ffserver.\n") + m_ffserver_out, i18n ("Error"));
0553         goto bail_out;
0554     }
0555     disconnect (m_ffserver_process, SIGNAL (receivedStderr (KProcess *, char *, int)),
0556                 this, SLOT (processOutput (KProcess *, char *, int)));
0557     if (m_ffmpeg_process)
0558         m_ffmpeg_process->stop ();
0559     delete m_ffmpeg_process;
0560     m_ffmpeg_process = new KMPlayer::FFMpeg (m_player, NULL, m_player->settings ());
0561     connect (m_ffmpeg_process, SIGNAL (stateChange (KMPlayer::Process::State, KMPlayer::Process::State)), this, SLOT (stateChange (KMPlayer::Process::State, KMPlayer::Process::State)));
0562     ffurl.sprintf ("http://localhost:%d/kmplayer.ffm", m_ffserverconfig->ffserverport);
0563     //m_ffmpeg_process->setUrl (KUrl(ffurl));
0564     if (!m_ffmpeg_process->play ()) {
0565         KMessageBox::error (m_configpage, i18n ("Failed to start ffmpeg."), i18n ("Error"));
0566         stopProcess (m_ffserver_process);
0567         goto bail_out;
0568     }
0569     if (m_ffmpeg_process->running ()) {
0570         m_ffserver_url.sprintf ("http://localhost:%d/video.%s", m_ffserverconfig->ffserverport, ffs.format.ascii ());
0571         m_endserver = false;
0572         m_configpage->feedled->setState (KLed::On);
0573         m_player->openUrl (KUrl (m_ffserver_url));
0574     } else
0575         stopServer ();
0576 bail_out:
0577     m_configpage->setCursor (QCursor (Qt::ArrowCursor));
0578 }
0579 /*
0580 KDE_NO_EXPORT void KMPlayerBroadcastConfig::stateChange (KMPlayer::Process::State old, KMPlayer::Process::State state) {
0581     if (state < KMPlayer::Process::Buffering && old >KMPlayer::Process::Ready) {
0582         if (m_configpage)
0583             m_configpage->feedled->setState (KLed::Off);
0584         m_ffmpeg_process->deleteLater ();
0585         m_ffmpeg_process = 0L;
0586         kdDebug () << "ffmpeg process stopped " << m_endserver << endl;
0587         if (m_endserver && !stopProcess (m_ffserver_process)) {
0588             disconnect (m_ffserver_process,
0589                     SIGNAL (receivedStderr (KProcess *, char *, int)),
0590                     this, SLOT (processOutput (KProcess *, char *, int)));
0591             KMessageBox::error (m_configpage, i18n ("Failed to end ffserver process."), i18n ("Error"));
0592             processStopped (0L);
0593         }
0594     }
0595 }
0596 */
0597 KDE_NO_EXPORT void KMPlayerBroadcastConfig::processStopped (KProcess *) {
0598     kdDebug () << "ffserver process stopped" << endl;
0599     if (m_configpage) {
0600         m_configpage->serverled->setState (KLed::Off);
0601         m_configpage->startbutton->setText (i18n ("Start"));
0602         m_configpage->startbutton->setEnabled
0603             (!m_player->source ()->videoDevice ().isEmpty ());
0604     }
0605     m_ffserver_process->deleteLater ();
0606     m_ffserver_process = 0L;
0607     emit broadcastStopped ();
0608 }
0609 
0610 KDE_NO_EXPORT void KMPlayerBroadcastConfig::sourceChanged (KMPlayer::Source *, KMPlayer::Source * source) {
0611     if (m_configpage)
0612         m_configpage->startbutton->setEnabled (broadcasting () || (source && !source->videoDevice ().isEmpty ()));
0613 }
0614 //-----------------------------------------------------------------------------
0615 
0616 KDE_NO_CDTOR_EXPORT KMPlayerFFServerConfig::KMPlayerFFServerConfig () {
0617 }
0618 
0619 KDE_NO_EXPORT void KMPlayerFFServerConfig::write (KConfig * config) {
0620     config->setGroup (strBroadcast);
0621     config->writeEntry (strBindAddress, bindaddress);
0622     config->writeEntry (strFFServerPort, ffserverport);
0623     config->writeEntry (strMaxClients, maxclients);
0624     config->writeEntry (strMaxBandwidth, maxbandwidth);
0625     config->writePathEntry (strFeedFile, feedfile);
0626     config->writeEntry (strFeedFileSize, feedfilesize);
0627 }
0628 
0629 KDE_NO_EXPORT void KMPlayerFFServerConfig::read (KConfig * config) {
0630     config->setGroup (strBroadcast);
0631     bindaddress = config->readEntry (strBindAddress, "0.0.0.0");
0632     ffserverport = config->readNumEntry (strFFServerPort, 8090);
0633     maxclients = config->readNumEntry (strMaxClients, 10);
0634     maxbandwidth = config->readNumEntry (strMaxBandwidth, 1000);
0635     feedfile = config->readPathEntry (strFeedFile, "/tmp/kmplayer.ffm");
0636     feedfilesize = config->readNumEntry (strFeedFileSize, 512);
0637 }
0638 
0639 KDE_NO_EXPORT void KMPlayerFFServerConfig::sync (bool fromUI) {
0640     if (fromUI) {
0641         bindaddress = m_configpage->bindaddress->text ();
0642         ffserverport = m_configpage->port->text ().toInt ();
0643         maxclients = m_configpage->maxclients->text ().toInt ();
0644         maxbandwidth = m_configpage->maxbandwidth->text ().toInt();
0645         feedfile = m_configpage->feedfile->text ();
0646         feedfilesize = m_configpage->feedfilesize->text ().toInt();
0647     } else {
0648         m_configpage->bindaddress->setText (bindaddress);
0649         m_configpage->port->setText (QString::number (ffserverport));
0650         m_configpage->maxclients->setText (QString::number (maxclients));
0651         m_configpage->maxbandwidth->setText (QString::number (maxbandwidth));
0652         m_configpage->feedfile->setText (feedfile);
0653         m_configpage->feedfilesize->setText (QString::number (feedfilesize));
0654     }
0655 }
0656 
0657 KDE_NO_EXPORT void KMPlayerFFServerConfig::prefLocation (QString & item, QString & icon, QString & tab) {
0658     item = i18n ("Broadcasting");
0659     icon = QString ("share");
0660     tab = i18n ("FFServer");
0661 }
0662 
0663 KDE_NO_EXPORT QFrame *KMPlayerFFServerConfig::prefPage (QWidget * parent) {
0664     if (!m_configpage)
0665         m_configpage = new KMPlayerPrefBroadcastPage (parent);
0666     return m_configpage;
0667 }
0668 
0669 
0670 #include "kmplayerbroadcast.moc"