File indexing completed on 2024-04-21 04:53:50
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 <QLayout> 0009 #include <QLabel> 0010 #include <QTimer> 0011 #include <QPushButton> 0012 #include <QCheckBox> 0013 #include <QTableWidget> 0014 #include <QStringList> 0015 #include <QComboBox> 0016 #include <QLineEdit> 0017 #include <QGroupBox> 0018 #include <QWhatsThis> 0019 #include <QTabWidget> 0020 #include <QMessageBox> 0021 #include <QHeaderView> 0022 #include <QMenu> 0023 #include <QStandardPaths> 0024 #include <QFontMetrics> 0025 0026 #include <kwidgetsaddons_version.h> 0027 #include <KLocalizedString> 0028 #include <KMessageBox> 0029 #include <KLineEdit> 0030 #include <KUrlRequester> 0031 #include <KComboBox> 0032 #include <KConfig> 0033 #include <KConfigGroup> 0034 0035 #include "kmplayerapp_log.h" 0036 #include "kmplayerpartbase.h" 0037 #include "kmplayerprocess.h" 0038 #include "kmplayerconfig.h" 0039 #include "kmplayertvsource.h" 0040 #include "playmodel.h" 0041 #include "playlistview.h" 0042 #include "viewarea.h" 0043 #include "kmplayer.h" 0044 #include "kmplayercontrolpanel.h" 0045 0046 static const char * strTV = "TV"; 0047 static const char * strTVDriver = "Driver"; 0048 0049 0050 TVDevicePage::TVDevicePage (QWidget *parent, KMPlayer::NodePtr dev) 0051 : QFrame (parent), device_doc (dev) { 0052 setObjectName("PageTVDevice"); 0053 TVDevice * device = KMPlayer::convertNode <TVDevice> (device_doc); 0054 QLabel* deviceLabel = new QLabel(i18n("Video device:") + device->src); 0055 QLabel* audioLabel = new QLabel(i18n("Audio device:")); 0056 audiodevice = new KUrlRequester (QUrl::fromUserInput (device->getAttribute ("audio"))); 0057 QLabel* nameLabel = new QLabel(i18n("Name:")); 0058 name = new QLineEdit(device->title); 0059 QLabel *sizewidthLabel = new QLabel(i18n("Width:")); 0060 sizewidth = new QLineEdit(device->getAttribute(KMPlayer::Ids::attr_width)); 0061 QLabel* sizeheightLabel = new QLabel (i18n ("Height:")); 0062 sizeheight = new QLineEdit(device->getAttribute(KMPlayer::Ids::attr_height)); 0063 noplayback = new QCheckBox(i18n("Do not immediately play")); 0064 noplayback->setChecked (!device->getAttribute ("playback").toInt ()); 0065 noplayback->setWhatsThis(i18n("Only start playing after clicking the play button")); 0066 inputsTab = new QTabWidget; 0067 for (KMPlayer::Node *ip = device->firstChild (); ip; ip = ip->nextSibling ()) { 0068 if (ip->id != id_node_tv_input) 0069 continue; 0070 TVInput * input = KMPlayer::convertNode <TVInput> (ip); 0071 QWidget* widget = new QWidget; 0072 QHBoxLayout* tablayout = new QHBoxLayout; 0073 if (!input->getAttribute ("tuner").isEmpty ()) { 0074 QHBoxLayout* horzlayout = new QHBoxLayout; 0075 QVBoxLayout* vertlayout = new QVBoxLayout; 0076 horzlayout->addWidget(new QLabel(i18n("Norm:"))); 0077 QComboBox* norms = new QComboBox; 0078 norms->setObjectName("PageTVNorm"); 0079 norms->addItem(QString("NTSC")); 0080 norms->addItem(QString("PAL")); 0081 norms->addItem(QString("SECAM")); 0082 norms->setCurrentIndex(norms->findText(input->getAttribute ("norm"))); 0083 horzlayout->addWidget (norms); 0084 vertlayout->addLayout (horzlayout); 0085 vertlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); 0086 QTableWidget* table = new QTableWidget(90, 2); 0087 table->setObjectName("PageTVChannels"); 0088 table->setContentsMargins(0, 0, 0, 0); 0089 QFontMetrics metrics (table->font ()); 0090 QStringList labels = QStringList() << i18n("Channel") << i18n("Frequency (MHz)"); 0091 table->setHorizontalHeaderLabels(labels); 0092 int index = 0; 0093 int first_column_width = QFontMetrics(table->horizontalHeader()->font()).boundingRect(labels[0]).width() + 20; 0094 for (KMPlayer::Node *c=input->firstChild();c;c=c->nextSibling()) { 0095 if (c->id != id_node_tv_channel) 0096 continue; 0097 int strwid = metrics.boundingRect (c->mrl ()->title).width (); 0098 if (strwid > first_column_width) 0099 first_column_width = strwid + 4; 0100 table->setItem(index, 0, new QTableWidgetItem(c->mrl()->title)); 0101 table->setItem(index++, 1, new QTableWidgetItem(KMPlayer::convertNode<TVChannel>(c)->getAttribute("frequency"))); 0102 } 0103 table->setColumnWidth (0, first_column_width); 0104 table->horizontalHeader()->setStretchLastSection(true); 0105 tablayout->addWidget (table); 0106 tablayout->addLayout (vertlayout); 0107 } 0108 widget->setLayout(tablayout); 0109 inputsTab->addTab (widget, input->mrl ()->title); 0110 } 0111 QPushButton* delButton = new QPushButton(i18n("Delete")); 0112 connect (delButton, &QPushButton::clicked, this, &TVDevicePage::slotDelete); 0113 QGridLayout* gridlayout = new QGridLayout; 0114 gridlayout->addWidget (audioLabel, 0, 0); 0115 gridlayout->addWidget (audiodevice, 0, 0, 1, 3); 0116 gridlayout->addWidget (nameLabel, 1, 0); 0117 gridlayout->addWidget (name, 1, 1, 1, 3); 0118 gridlayout->addWidget (sizewidthLabel, 2, 0); 0119 gridlayout->addWidget (sizewidth, 2, 1); 0120 gridlayout->addWidget (sizeheightLabel, 2, 2); 0121 gridlayout->addWidget (sizeheight, 2, 3); 0122 QVBoxLayout* layout = new QVBoxLayout; 0123 layout->addWidget(deviceLabel); 0124 layout->addLayout(gridlayout); 0125 layout->addWidget (inputsTab); 0126 layout->addSpacing (5); 0127 layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); 0128 QHBoxLayout *buttonlayout = new QHBoxLayout (); 0129 buttonlayout->addWidget (noplayback); 0130 buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); 0131 buttonlayout->addWidget (delButton); 0132 layout->addLayout (buttonlayout); 0133 setLayout(layout); 0134 } 0135 0136 void TVDevicePage::slotDelete () { 0137 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0138 if (KMessageBox::warningTwoActions (this, 0139 #else 0140 if (KMessageBox::warningYesNo (this, 0141 #endif 0142 i18n ("You are about to delete this device from the Source menu.\nContinue?"), 0143 i18n ("Confirm"), 0144 KStandardGuiItem::del(), KStandardGuiItem::cancel()) 0145 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0146 == KMessageBox::PrimaryAction) 0147 #else 0148 == KMessageBox::Yes) 0149 #endif 0150 Q_EMIT deleted (this); 0151 } 0152 0153 //----------------------------------------------------------------------------- 0154 0155 KMPlayerPrefSourcePageTV::KMPlayerPrefSourcePageTV (QWidget *parent, KMPlayerTVSource * tvsource) 0156 : QFrame (parent), m_tvsource (tvsource) { 0157 notebook = new QTabWidget; 0158 notebook->setTabPosition (QTabWidget::South); 0159 QWidget * general = new QWidget (notebook); 0160 QLabel* driverLabel = new QLabel(i18n("Driver:")); 0161 driver = new QLineEdit; 0162 driver->setWhatsThis(i18n("dummy, v4l or bsdbt848")); 0163 QLabel *deviceLabel = new QLabel(i18n("Device:")); 0164 device = new KUrlRequester(QUrl::fromLocalFile("/dev/video")); 0165 device->setWhatsThis(i18n("Path to your video device, eg. /dev/video0")); 0166 scan = new QPushButton(i18n("Scan...")); 0167 QGridLayout *gridlayout = new QGridLayout; 0168 gridlayout->addWidget (driverLabel, 0, 0); 0169 gridlayout->addWidget (driver, 0, 1); 0170 gridlayout->addWidget (deviceLabel, 1, 0); 0171 gridlayout->addWidget (device, 1, 1); 0172 QHBoxLayout *buttonlayout = new QHBoxLayout; 0173 buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum)); 0174 buttonlayout->addWidget (scan); 0175 QVBoxLayout *layout = new QVBoxLayout; 0176 layout->addLayout(gridlayout); 0177 layout->addLayout (buttonlayout); 0178 layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); 0179 general->setLayout(layout); 0180 notebook->addTab(general, i18n("General")); 0181 QVBoxLayout* mainlayout = new QVBoxLayout; 0182 mainlayout->addWidget(notebook); 0183 setLayout(mainlayout); 0184 } 0185 0186 void KMPlayerPrefSourcePageTV::showEvent (QShowEvent *) { 0187 m_tvsource->readXML (); 0188 } 0189 0190 //----------------------------------------------------------------------------- 0191 0192 TVNode::TVNode (KMPlayer::NodePtr &d, const QString & s, const char * t, short id, const QString & n) : KMPlayer::GenericMrl (d, s, n, t) { 0193 this->id = id; 0194 editable = true; 0195 } 0196 0197 void TVNode::setNodeName (const QString & nn) { 0198 title = nn; 0199 setAttribute (KMPlayer::Ids::attr_name, nn); 0200 } 0201 0202 //----------------------------------------------------------------------------- 0203 0204 TVChannel::TVChannel (KMPlayer::NodePtr & d, const QString & n, double freq) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel, n) { 0205 setAttribute (KMPlayer::Ids::attr_name, n); 0206 setAttribute ("frequency", QString::number (freq, 'f', 2)); 0207 } 0208 0209 TVChannel::TVChannel (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel) { 0210 } 0211 0212 void TVChannel::closed () { 0213 title = getAttribute (KMPlayer::Ids::attr_name); 0214 Mrl::closed (); 0215 } 0216 0217 //----------------------------------------------------------------------------- 0218 0219 TVInput::TVInput (KMPlayer::NodePtr & d, const QString & n, int id) 0220 : TVNode (d, QString ("tv://"), "input", id_node_tv_input, n) { 0221 setAttribute (KMPlayer::Ids::attr_name, n); 0222 setAttribute (KMPlayer::Ids::attr_id, QString::number (id)); 0223 } 0224 0225 TVInput::TVInput (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "input", id_node_tv_input) { 0226 } 0227 0228 KMPlayer::Node *TVInput::childFromTag (const QString & tag) { 0229 // qCDebug(LOG_KMPLAYER_APP) << nodeName () << " childFromTag " << tag; 0230 if (tag == QString::fromLatin1 ("channel")) { 0231 return new TVChannel (m_doc); 0232 } else 0233 return nullptr; 0234 } 0235 0236 void TVInput::closed () { 0237 //title = getAttribute (KMPlayer::Ids::attr_name); 0238 Mrl::closed (); 0239 } 0240 0241 void TVInput::setNodeName (const QString & name) { 0242 Node *p = parentNode (); 0243 QString nm (name); 0244 if (p && p->id == id_node_tv_device) { 0245 int pos = name.indexOf (QString (" - ") + p->mrl ()->title); 0246 if (pos > -1) 0247 nm.truncate (pos); 0248 } 0249 title = nm + QString (" - ") + title; 0250 TVNode::setNodeName (nm); 0251 } 0252 0253 //----------------------------------------------------------------------------- 0254 0255 TVDevice::TVDevice (KMPlayer::NodePtr & doc, const QString & d) : TVNode (doc, d, "device", id_node_tv_device), zombie (false) { 0256 setAttribute ("path", d); 0257 } 0258 0259 TVDevice::TVDevice (KMPlayer::NodePtr & doc) 0260 : TVNode (doc, i18n ("tv device"), "device", id_node_tv_device), zombie (false) { 0261 } 0262 0263 TVDevice::~TVDevice () { 0264 if (device_page) 0265 device_page->deleteLater (); 0266 } 0267 0268 KMPlayer::Node *TVDevice::childFromTag (const QString & tag) { 0269 // qCDebug(LOG_KMPLAYER_APP) << nodeName () << " childFromTag " << tag; 0270 if (tag == QString::fromLatin1 ("input")) 0271 return new TVInput (m_doc); 0272 return nullptr; 0273 } 0274 0275 void TVDevice::closed () { 0276 updateNodeName (); 0277 Mrl::closed (); 0278 } 0279 0280 void TVDevice::message (KMPlayer::MessageType msg, void *data) { 0281 if (KMPlayer::MsgChildFinished == msg) 0282 finish (); 0283 else 0284 TVNode::message (msg, data); 0285 } 0286 0287 void *TVDevice::role (KMPlayer::RoleType msg, void *content) 0288 { 0289 if (KMPlayer::RolePlaylist == msg) 0290 return nullptr; 0291 return TVNode::role (msg, content); 0292 } 0293 0294 void TVDevice::setNodeName (const QString & name) { 0295 TVNode::setNodeName (name); 0296 updateNodeName (); 0297 } 0298 0299 void TVDevice::updateNodeName () { 0300 title = getAttribute (KMPlayer::Ids::attr_name); 0301 src = getAttribute ("path"); 0302 for (KMPlayer::Node *c = firstChild (); c; c = c->nextSibling ()) 0303 if (c->id == id_node_tv_input) { 0304 TVInput * i = static_cast <TVInput *> (c); 0305 i->title = i->getAttribute (KMPlayer::Ids::attr_name) + 0306 QString (" - ") + title; 0307 } 0308 } 0309 0310 void TVDevice::updateDevicePage () { 0311 if (!device_page) 0312 return; 0313 title = device_page->name->text (); 0314 setAttribute (KMPlayer::Ids::attr_name, title); 0315 setAttribute ("audio", device_page->audiodevice->lineEdit()->text ()); 0316 setAttribute ("playback", device_page->noplayback->isChecked() ? "0" : "1"); 0317 setAttribute (KMPlayer::Ids::attr_width, device_page->sizewidth->text ()); 0318 setAttribute (KMPlayer::Ids::attr_height, device_page->sizeheight->text ()); 0319 int i = 0; 0320 for (KMPlayer::Node *ip = firstChild(); ip; ip=ip->nextSibling(),++i) { 0321 if (ip->id != id_node_tv_input) 0322 continue; 0323 TVInput * input = KMPlayer::convertNode <TVInput> (ip); 0324 bool ok; 0325 if (input->getAttribute ("tuner").toInt (&ok) && ok) { 0326 QWidget* widget = device_page->inputsTab->widget(i); 0327 QTableWidget* table = static_cast<QTableWidget*>(widget->findChild<QTableWidget*>("PageTVChannels")); 0328 if (table) { 0329 input->clearChildren (); 0330 for (int j = 0; j<table->rowCount() && table->item (j, 1); ++j) { 0331 input->appendChild (new TVChannel (m_doc, table->item (j, 0)->text (), table->item (j, 1)->text ().toDouble ())); 0332 } 0333 } 0334 QComboBox* norms = static_cast<QComboBox*>(widget->findChild<QComboBox*>("PageTVNorm")); 0335 if (norms) { 0336 input->setAttribute ("norm", norms->currentText ()); 0337 } 0338 } 0339 } 0340 } 0341 0342 //----------------------------------------------------------------------------- 0343 0344 TVDocument::TVDocument (KMPlayerTVSource * source) 0345 : FileDocument (id_node_tv_document, "tv://", source), m_source (source) { 0346 title = i18n ("Television"); 0347 bookmarkable = false; 0348 } 0349 0350 KMPlayer::Node *TVDocument::childFromTag (const QString & tag) { 0351 // qCDebug(LOG_KMPLAYER_APP) << nodeName () << " childFromTag " << tag; 0352 if (tag == QString::fromLatin1 ("device")) 0353 return new TVDevice (m_doc); 0354 return FileDocument::childFromTag (tag); 0355 } 0356 0357 void TVDocument::message (KMPlayer::MessageType msg, void *data) { 0358 if (KMPlayer::MsgChildFinished == msg) 0359 finish (); 0360 else 0361 FileDocument::message (msg, data); 0362 } 0363 0364 void TVDocument::defer () { 0365 if (!resolved) { 0366 resolved = true; 0367 readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml"); 0368 } 0369 } 0370 0371 //----------------------------------------------------------------------------- 0372 0373 KMPlayerTVSource::KMPlayerTVSource(KMPlayerApp* a) 0374 : KMPlayer::Source (i18n ("TV"), a->player(), "tvsource"), m_app(a), m_configpage(nullptr), scanner(nullptr), config_read(false) { 0375 m_url = QUrl("tv://"); 0376 m_document = new TVDocument (this); 0377 m_player->settings ()->addPage (this); 0378 tree_id = m_player->playModel()->addTree (m_document, "tvsource", "video-television", KMPlayer::PlayModel::TreeEdit | KMPlayer::PlayModel::Moveable | KMPlayer::PlayModel::Deleteable); 0379 } 0380 0381 KMPlayerTVSource::~KMPlayerTVSource () { 0382 static_cast <TVDocument *> (m_document.ptr ())->sync 0383 (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml"); 0384 } 0385 0386 void KMPlayerTVSource::activate () { 0387 m_identified = true; 0388 //if (m_player->settings ()->showbroadcastbutton) 0389 // m_app->view()->controlPanel()->broadcastButton ()->show (); 0390 if (m_cur_tvdevice && !m_current) { 0391 for (KMPlayer::Node *i = m_cur_tvdevice->firstChild(); i && !m_current; i=i->nextSibling()) 0392 if (i->id == id_node_tv_input) { 0393 TVInput * input = KMPlayer::convertNode <TVInput> (i); 0394 bool ok; 0395 m_cur_tvinput = i; 0396 if (input->getAttribute ("tuner").toInt (&ok) && ok) { 0397 for (KMPlayer::Node *c = i->firstChild (); c; c = c->nextSibling ()) 0398 if (c->id == id_node_tv_channel) { 0399 setCurrent (c->mrl ()); 0400 break; 0401 } 0402 } else 0403 m_current = i; 0404 } 0405 } else if (!m_cur_tvdevice) 0406 KMPlayer::Source::reset (); 0407 if (m_cur_tvdevice) { 0408 QString playback = static_cast <KMPlayer::Element *> (m_cur_tvdevice.ptr ())->getAttribute (QString::fromLatin1 ("playback")); 0409 if (playback.isEmpty () || playback.toInt ()) 0410 QTimer::singleShot (0, m_player, &KMPlayer::PartBase::play); 0411 } 0412 } 0413 /* TODO: playback by 0414 * ffmpeg -vd /dev/video0 -r 25 -s 768x576 -f rawvideo - |mplayer -nocache -ao arts -rawvideo on:w=768:h=576:fps=25 -quiet - 0415 */ 0416 0417 void KMPlayerTVSource::deactivate () { 0418 //if (m_player->view () && !m_app->view ()->controlPanel()->broadcastButton ()->isOn ()) 0419 // m_app->view ()->controlPanel()->broadcastButton ()->hide (); 0420 reset (); 0421 } 0422 0423 void KMPlayerTVSource::play (KMPlayer::Mrl *mrl) { 0424 if (mrl && mrl->id == id_node_tv_document) { 0425 readXML (); 0426 } else { 0427 m_current = mrl; 0428 for (KMPlayer::Node *e = mrl; e; e = e->parentNode ()) { 0429 if (e->id == id_node_tv_device) { 0430 m_cur_tvdevice = e; 0431 break; 0432 } else if (e->id == id_node_tv_input) 0433 m_cur_tvinput = e; 0434 } 0435 if (m_player->source () != this) 0436 m_player->setSource (this); 0437 else 0438 KMPlayer::Source::play (mrl); 0439 /*else if (m_player->process ()->playing ()) { 0440 //m_back_request = m_current; 0441 m_player->process ()->stop (); 0442 } else { 0443 buildArguments (); 0444 if (m_app->broadcasting ()) 0445 QTimer::singleShot (0, m_app->broadcastConfig (), SLOT (startFeed ())); 0446 else 0447 KMPlayer::Source::play (mrl); 0448 }*/ 0449 } 0450 } 0451 0452 KMPlayer::NodePtr KMPlayerTVSource::root () { 0453 return m_cur_tvinput; 0454 } 0455 0456 void KMPlayerTVSource::setCurrent (KMPlayer::Mrl *mrl) { 0457 TVChannel * channel = nullptr; 0458 TVInput * input = nullptr; 0459 m_current = mrl; 0460 KMPlayer::NodePtr elm = m_current; 0461 if (elm && elm->id == id_node_tv_channel) { 0462 channel = KMPlayer::convertNode <TVChannel> (elm); 0463 elm = elm->parentNode (); 0464 } 0465 if (elm && elm->id == id_node_tv_input) 0466 input = KMPlayer::convertNode <TVInput> (elm); 0467 if (!(channel || (input && input->getAttribute ("tuner").isEmpty ()))) 0468 return; 0469 m_cur_tvinput = input; 0470 m_cur_tvdevice = input->parentNode (); 0471 m_player->playModel()->updateTree(0, m_cur_tvinput, m_current, true, false); 0472 if (m_cur_tvdevice->id != id_node_tv_device) { 0473 return; 0474 } 0475 TVDevice * tvdevice = KMPlayer::convertNode <TVDevice> (m_cur_tvdevice); 0476 m_identified = true; 0477 m_audiodevice = tvdevice->getAttribute ("audio"); 0478 m_videodevice = tvdevice->src; 0479 m_videonorm = input->getAttribute ("norm"); 0480 m_tuner = input->getAttribute (KMPlayer::Ids::attr_name); 0481 QString xvport = tvdevice->getAttribute ("xvport"); 0482 if (!xvport.isEmpty ()) 0483 m_xvport = xvport.toInt (); 0484 QString xvenc = input->getAttribute ("xvenc"); 0485 if (!xvenc.isEmpty ()) 0486 m_xvencoding = xvenc.toInt (); 0487 QString command = QString::asprintf ("device=%s:input=%s", 0488 tvdevice->src.toLatin1 ().data (), 0489 input->getAttribute (KMPlayer::Ids::attr_id).toLatin1 ().data ()); 0490 if (channel) { 0491 QString freq = channel->getAttribute ("frequency"); 0492 m_frequency = (int)(1000 * freq.toDouble ()); 0493 command += QString (":freq=%1").arg (freq); 0494 } else 0495 m_frequency = 0; 0496 if (!m_videonorm.isEmpty ()) 0497 command += QString (":norm=%1").arg (m_videonorm); 0498 m_app->setCaption (i18n ("TV: ") + (channel ? channel->mrl ()->title : input->mrl ()->title), false); 0499 setDimensions (m_cur_tvdevice, 0500 tvdevice->getAttribute (KMPlayer::Ids::attr_width).toInt (), 0501 tvdevice->getAttribute (KMPlayer::Ids::attr_height).toInt ()); 0502 m_options = QString::asprintf ("-tv noaudio:driver=%s:%s:width=%d:height=%d -slave -nocache -quiet", tvdriver.toLatin1 ().data (), command.toLatin1 ().data (), width (), height ()); 0503 m_recordcmd = QString::asprintf ("-tv %s:driver=%s:%s:width=%d:height=%d", m_audiodevice.isEmpty () ? "noaudio" : QString(QLatin1String ("forceaudio:adevice=") + m_audiodevice).toLatin1 ().data(), tvdriver.toLatin1 ().data (), command.toLatin1 ().data (), width (), height ()); 0504 } 0505 0506 void KMPlayerTVSource::menuClicked (int id) { 0507 KMPlayer::Node *elm = m_document->firstChild (); 0508 for (; id > 0; --id, elm = elm->nextSibling ()) 0509 ; 0510 m_cur_tvdevice = elm; 0511 m_cur_tvinput = elm->firstChild (); // FIXME 0512 m_current = nullptr; 0513 m_player->setSource (this); 0514 } 0515 0516 QString KMPlayerTVSource::filterOptions () { 0517 if (! m_player->settings ()->disableppauto) 0518 return KMPlayer::Source::filterOptions (); 0519 return QString ("-vf pp=lb"); 0520 } 0521 0522 bool KMPlayerTVSource::hasLength () { 0523 return false; 0524 } 0525 0526 bool KMPlayerTVSource::isSeekable () { 0527 return true; 0528 } 0529 0530 QString KMPlayerTVSource::prettyName () { 0531 QString name (i18n ("TV")); 0532 //if (m_tvsource) 0533 // name += ' ' + m_tvsource->title; 0534 return name; 0535 } 0536 0537 void KMPlayerTVSource::write (KSharedConfigPtr m_config) { 0538 if (!config_read) return; 0539 KConfigGroup (m_config, strTV).writeEntry (strTVDriver, tvdriver); 0540 static_cast <TVDocument *> (m_document.ptr ())->writeToFile 0541 (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml"); 0542 qCDebug(LOG_KMPLAYER_APP) << "KMPlayerTVSource::write XML"; 0543 } 0544 0545 void KMPlayerTVSource::readXML () { 0546 if (config_read) return; 0547 config_read = true; 0548 qCDebug(LOG_KMPLAYER_APP) << "KMPlayerTVSource::readXML"; 0549 m_document->defer (); 0550 m_player->playModel()->updateTree (tree_id, m_document, nullptr, false, false); 0551 sync (false); 0552 } 0553 0554 void KMPlayerTVSource::read (KSharedConfigPtr m_config) { 0555 tvdriver = KConfigGroup (m_config, strTV).readEntry ( 0556 strTVDriver, QString ("v4l2")); 0557 } 0558 0559 void KMPlayerTVSource::sync (bool fromUI) { 0560 if (!m_configpage) return; 0561 if (m_document && m_document->hasChildNodes ()) 0562 m_app->showBroadcastConfig (); 0563 else 0564 m_app->hideBroadcastConfig (); 0565 if (fromUI) { 0566 tvdriver = m_configpage->driver->text (); 0567 for (KMPlayer::Node *d=m_document->firstChild();d; d=d->nextSibling()) 0568 if (d->id == id_node_tv_device) 0569 static_cast <TVDevice *> (d)->updateDevicePage (); 0570 m_player->playModel()->updateTree(tree_id, m_document, nullptr, false, false); 0571 } else { 0572 m_configpage->driver->setText (tvdriver); 0573 for (KMPlayer::Node *dp = m_document->firstChild (); dp; dp = dp->nextSibling ()) 0574 if (dp->id == id_node_tv_device) 0575 addTVDevicePage (KMPlayer::convertNode <TVDevice> (dp)); 0576 } 0577 } 0578 0579 void KMPlayerTVSource::prefLocation (QString & item, QString & icon, QString & tab) { 0580 item = i18n ("Source"); 0581 icon = QString ("source"); 0582 tab = i18n ("TV"); 0583 } 0584 0585 QFrame * KMPlayerTVSource::prefPage (QWidget * parent) { 0586 if (!m_configpage) { 0587 m_configpage = new KMPlayerPrefSourcePageTV (parent, this); 0588 scanner = new TVDeviceScannerSource (this); 0589 connect (m_configpage->scan, &QPushButton::clicked, this, &KMPlayerTVSource::slotScan); 0590 } 0591 return m_configpage; 0592 } 0593 0594 static bool hasTVDevice (KMPlayer::NodePtr doc, const QString & devstr) { 0595 for (KMPlayer::Node *e = doc->firstChild (); e; e = e->nextSibling ()) 0596 if (e->id == id_node_tv_device && 0597 static_cast <TVDevice *> (e)->src == devstr) 0598 return true; 0599 return false; 0600 } 0601 0602 void KMPlayerTVSource::slotScan () { 0603 QString devstr = m_configpage->device->lineEdit()->text (); 0604 if (!hasTVDevice(m_document, devstr)) { 0605 scanner->scan (devstr, m_configpage->driver->text()); 0606 connect (scanner, &TVDeviceScannerSource::scanFinished, 0607 this, &KMPlayerTVSource::slotScanFinished); 0608 } else 0609 KMessageBox::error (m_configpage, i18n ("Device already present."), 0610 i18n ("Error")); 0611 } 0612 0613 void KMPlayerTVSource::slotScanFinished (TVDevice * tvdevice) { 0614 disconnect (scanner, &TVDeviceScannerSource::scanFinished, 0615 this, &KMPlayerTVSource::slotScanFinished); 0616 if (tvdevice) { 0617 tvdevice->zombie = false; 0618 addTVDevicePage (tvdevice, true); 0619 m_player->playModel()->updateTree(tree_id, m_document, nullptr, false, false); 0620 } else 0621 KMessageBox::error(m_configpage,i18n("No device found."),i18n("Error")); 0622 } 0623 0624 void KMPlayerTVSource::addTVDevicePage(TVDevice *dev, bool show) { 0625 if (dev->device_page) 0626 dev->device_page->deleteLater (); 0627 dev->device_page = new TVDevicePage (m_configpage->notebook, dev); 0628 m_configpage->notebook->addTab(dev->device_page, dev->title); 0629 connect (dev->device_page, &TVDevicePage::deleted, 0630 this, &KMPlayerTVSource::slotDeviceDeleted); 0631 if (show) 0632 m_configpage->notebook->setCurrentIndex(m_configpage->notebook->count()-1); 0633 } 0634 0635 void KMPlayerTVSource::slotDeviceDeleted (TVDevicePage *devpage) { 0636 m_document->removeChild (devpage->device_doc); 0637 m_configpage->notebook->setCurrentIndex(0); 0638 m_player->playModel()->updateTree (tree_id, m_document, nullptr, false, false); 0639 } 0640 0641 //----------------------------------------------------------------------------- 0642 0643 TVDeviceScannerSource::TVDeviceScannerSource (KMPlayerTVSource * src) 0644 : KMPlayer::Source (i18n ("TVScanner"), src->player (), "tvscanner"), 0645 m_tvsource (src), 0646 m_tvdevice (nullptr), 0647 m_process (nullptr), 0648 m_viewer (nullptr) { 0649 } 0650 0651 void TVDeviceScannerSource::init () { 0652 } 0653 0654 bool TVDeviceScannerSource::processOutput (const QString & line) { 0655 if (m_nameRegExp.indexIn(line) > -1) { 0656 m_tvdevice->title = m_nameRegExp.cap (1); 0657 m_tvdevice->setAttribute(KMPlayer::Ids::attr_name,m_tvdevice->title); 0658 qCDebug(LOG_KMPLAYER_APP) << "Name " << m_tvdevice->title; 0659 } else if (m_sizesRegExp.indexIn(line) > -1) { 0660 m_tvdevice->setAttribute (KMPlayer::Ids::attr_width, 0661 m_sizesRegExp.cap(1)); 0662 m_tvdevice->setAttribute (KMPlayer::Ids::attr_height, 0663 m_sizesRegExp.cap(2)); 0664 m_tvdevice->setAttribute ("minwidth", m_sizesRegExp.cap (1)); 0665 m_tvdevice->setAttribute ("minheight", m_sizesRegExp.cap (2)); 0666 m_tvdevice->setAttribute ("maxwidth", m_sizesRegExp.cap (3)); 0667 m_tvdevice->setAttribute ("maxheight", m_sizesRegExp.cap (4)); 0668 } else if (m_inputRegExp.indexIn(line) > -1) { 0669 KMPlayer::NodePtr doc = m_tvsource->document (); 0670 TVInput * input = new TVInput (doc, m_inputRegExp.cap(2).trimmed(), 0671 m_inputRegExp.cap (1).toInt ()); 0672 if (m_inputRegExp.cap (3).toInt () == 1) 0673 input->setAttribute ("tuner", "1"); 0674 m_tvdevice->appendChild (input); 0675 qCDebug(LOG_KMPLAYER_APP) << "Input " << input->mrl ()->title; 0676 } else if (m_inputRegExpV4l2.indexIn(line) > -1) { 0677 KMPlayer::NodePtr doc = m_tvsource->document (); 0678 QStringList sl = m_inputRegExpV4l2.cap(1).split (QChar (';')); 0679 const QStringList::iterator e = sl.end (); 0680 for (QStringList::iterator i = sl.begin (); i != e; ++i) { 0681 int pos = (*i).indexOf (QChar ('=')); 0682 if (pos > 0) { 0683 int id = (*i).left (pos).trimmed ().toInt (); 0684 TVInput *input = new TVInput(doc,(*i).mid(pos+1).trimmed(), id); 0685 if (!id && m_caps.indexOf ("tuner") > -1) 0686 input->setAttribute ("tuner", "1"); 0687 m_tvdevice->appendChild (input); 0688 } 0689 } 0690 } else { 0691 int pos = line.indexOf ("Capabilites:"); 0692 if (pos > 0) 0693 m_caps = line.mid (pos + 12); 0694 return false; 0695 } 0696 return true; 0697 } 0698 0699 QString TVDeviceScannerSource::filterOptions () { 0700 return QString (""); 0701 } 0702 0703 bool TVDeviceScannerSource::hasLength () { 0704 return false; 0705 } 0706 0707 bool TVDeviceScannerSource::isSeekable () { 0708 return false; 0709 } 0710 0711 bool TVDeviceScannerSource::scan (const QString & dev, const QString & dri) { 0712 if (m_tvdevice) 0713 return false; 0714 setUrl ("tv://"); 0715 KMPlayer::NodePtr doc = m_tvsource->document (); 0716 m_tvdevice = new TVDevice (doc, dev); 0717 m_tvsource->document ()->appendChild (m_tvdevice); 0718 m_tvdevice->zombie = true; // not for real yet 0719 m_driver = dri; 0720 m_old_source = m_tvsource->player ()->source (); 0721 m_tvsource->player ()->setSource (this); 0722 m_identified = true; 0723 play (m_tvdevice); 0724 return true; 0725 } 0726 0727 void TVDeviceScannerSource::activate () { 0728 m_nameRegExp.setPattern ("Selected device:\\s*([^\\s].*)"); 0729 m_sizesRegExp.setPattern ("Supported sizes:\\s*([0-9]+)x([0-9]+) => ([0-9]+)x([0-9]+)"); 0730 m_inputRegExp.setPattern ("\\s*([0-9]+):\\s*([^:]+):[^\\(]*\\(tuner:([01]),\\s*norm:([^\\)]+)\\)"); 0731 m_inputRegExpV4l2.setPattern ("inputs:((?:\\s*[0-9]+\\s*=\\s*[^;]+;)+)"); 0732 } 0733 0734 void TVDeviceScannerSource::deactivate () { 0735 qCDebug(LOG_KMPLAYER_APP) << "TVDeviceScannerSource::deactivate"; 0736 if (m_tvdevice) { 0737 if (m_tvdevice->parentNode ()) 0738 m_tvdevice->parentNode ()->removeChild (m_tvdevice); 0739 m_tvdevice = nullptr; 0740 delete m_process; 0741 Q_EMIT scanFinished (m_tvdevice); 0742 } 0743 } 0744 0745 void TVDeviceScannerSource::play (KMPlayer::Mrl *) { 0746 if (!m_tvdevice) 0747 return; 0748 m_options = QString::asprintf ("tv:// -tv driver=%s:device=%s -identify -frames 0", m_driver.toLatin1 ().data (), m_tvdevice->src.toLatin1 ().data ()); 0749 m_tvsource->player ()->stop (); 0750 KMPlayer::Node *n = new KMPlayer::SourceDocument (this, QString ()); 0751 setDocument (n, n); 0752 m_process = m_player->mediaManager()->processInfos()["mplayer"]->create (m_player, this); 0753 m_viewer = m_player->viewWidget ()->viewArea ()->createVideoWidget (); 0754 m_process->ready (); 0755 } 0756 0757 void TVDeviceScannerSource::scanningFinished () { 0758 TVDevice * dev = nullptr; 0759 delete m_process; 0760 qCDebug(LOG_KMPLAYER_APP) << "scanning done " << m_tvdevice->hasChildNodes (); 0761 if (!m_tvdevice->hasChildNodes ()) { 0762 m_tvsource->document ()->removeChild (m_tvdevice); 0763 } else { 0764 dev = m_tvdevice; 0765 if (width () > 0 && height () > 0) { 0766 m_tvdevice->setAttribute (KMPlayer::Ids::attr_width, 0767 QString::number (width ())); 0768 m_tvdevice->setAttribute (KMPlayer::Ids::attr_height, 0769 QString::number (height ())); 0770 } 0771 } 0772 m_tvdevice = nullptr; 0773 m_player->setSource (m_old_source); 0774 Q_EMIT scanFinished (dev); 0775 } 0776 0777 void TVDeviceScannerSource::stateChange (KMPlayer::IProcess *, 0778 KMPlayer::IProcess::State os, KMPlayer::IProcess::State ns) { 0779 if (KMPlayer::IProcess::Ready == ns) { 0780 if (os > KMPlayer::IProcess::Ready) 0781 QTimer::singleShot (0, this, &TVDeviceScannerSource::scanningFinished); 0782 else if (m_process && os < KMPlayer::IProcess::Ready) 0783 m_process->play (); 0784 } 0785 } 0786 0787 void TVDeviceScannerSource::processDestroyed (KMPlayer::IProcess *) { 0788 m_process = nullptr; 0789 KMPlayer::View *view = m_player->viewWidget (); 0790 if (view) 0791 view->viewArea ()->destroyVideoWidget (m_viewer); 0792 m_viewer = nullptr; 0793 } 0794 0795 KMPlayer::IViewer *TVDeviceScannerSource::viewer () { 0796 return m_viewer; 0797 } 0798 0799 KMPlayer::Mrl *TVDeviceScannerSource::getMrl () { 0800 return document ()->mrl (); 0801 } 0802 0803 #include "moc_kmplayertvsource.cpp"