File indexing completed on 2024-04-21 08:43:49

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