1 /* This file is part of the KMPlayer application
2 Copyright (C) 2003 Koos Vriezen <koos.vriezen@xs4all.nl>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include <qlayout.h>
21 #include <qlabel.h>
22 #include <qtimer.h>
23 #include <qpushbutton.h>
24 #include <qcheckbox.h>
25 #include <QTableWidget>
26 #include <qstringlist.h>
27 #include <qcombobox.h>
28 #include <qlineedit.h>
29 #include <qgroupbox.h>
30 #include <qwhatsthis.h>
31 #include <qtabwidget.h>
32 #include <qmessagebox.h>
33 #include <QHeaderView>
34 #include <QMenu>
35 #include <QStandardPaths>
36 #include <qfontmetrics.h>
37
38 #include <klocale.h>
39 #include <kdebug.h>
40 #include <kmessagebox.h>
41 #include <klineedit.h>
42 #include <kurlrequester.h>
43 #include <kcombobox.h>
44 #include <kconfig.h>
45 #include <kconfiggroup.h>
46
47 #include "kmplayerpartbase.h"
48 #include "kmplayerprocess.h"
49 #include "kmplayerconfig.h"
50 #include "kmplayertvsource.h"
51 #include "playmodel.h"
52 #include "playlistview.h"
53 #include "viewarea.h"
54 #include "kmplayer.h"
55 #include "kmplayercontrolpanel.h"
56
57 static const char * strTV = "TV";
58 static const char * strTVDriver = "Driver";
59
60
TVDevicePage(QWidget * parent,KMPlayer::NodePtr dev)61 KDE_NO_CDTOR_EXPORT TVDevicePage::TVDevicePage (QWidget *parent, KMPlayer::NodePtr dev)
62 : QFrame (parent), device_doc (dev) {
63 setObjectName("PageTVDevice");
64 TVDevice * device = KMPlayer::convertNode <TVDevice> (device_doc);
65 QLabel* deviceLabel = new QLabel(i18n("Video device:") + device->src);
66 QLabel* audioLabel = new QLabel(i18n("Audio device:"));
67 audiodevice = new KUrlRequester (KUrl (device->getAttribute ("audio")));
68 QLabel* nameLabel = new QLabel(i18n("Name:"));
69 name = new QLineEdit(device->title);
70 QLabel *sizewidthLabel = new QLabel(i18n("Width:"));
71 sizewidth = new QLineEdit(device->getAttribute(KMPlayer::Ids::attr_width));
72 QLabel* sizeheightLabel = new QLabel (i18n ("Height:"));
73 sizeheight = new QLineEdit(device->getAttribute(KMPlayer::Ids::attr_height));
74 noplayback = new QCheckBox(i18n("Do not immediately play"));
75 noplayback->setChecked (!device->getAttribute ("playback").toInt ());
76 noplayback->setWhatsThis(i18n("Only start playing after clicking the play button"));
77 inputsTab = new QTabWidget;
78 for (KMPlayer::Node *ip = device->firstChild (); ip; ip = ip->nextSibling ()) {
79 if (ip->id != id_node_tv_input)
80 continue;
81 TVInput * input = KMPlayer::convertNode <TVInput> (ip);
82 QWidget* widget = new QWidget;
83 QHBoxLayout* tablayout = new QHBoxLayout;
84 if (!input->getAttribute ("tuner").isEmpty ()) {
85 QHBoxLayout* horzlayout = new QHBoxLayout;
86 QVBoxLayout* vertlayout = new QVBoxLayout;
87 horzlayout->addWidget(new QLabel(i18n("Norm:")));
88 QComboBox* norms = new QComboBox;
89 norms->setObjectName("PageTVNorm");
90 norms->addItem(QString("NTSC"));
91 norms->addItem(QString("PAL"));
92 norms->addItem(QString("SECAM"));
93 norms->setCurrentIndex(norms->findText(input->getAttribute ("norm")));
94 horzlayout->addWidget (norms);
95 vertlayout->addLayout (horzlayout);
96 vertlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
97 QTableWidget* table = new QTableWidget(90, 2);
98 table->setObjectName("PageTVChannels");
99 table->setContentsMargins(0, 0, 0, 0);
100 QFontMetrics metrics (table->font ());
101 QStringList labels = QStringList() << i18n("Channel") << i18n("Frequency (MHz)");
102 table->setHorizontalHeaderLabels(labels);
103 int index = 0;
104 int first_column_width = QFontMetrics(table->horizontalHeader()->font()).boundingRect(labels[0]).width() + 20;
105 for (KMPlayer::Node *c=input->firstChild();c;c=c->nextSibling()) {
106 if (c->id != id_node_tv_channel)
107 continue;
108 int strwid = metrics.boundingRect (c->mrl ()->title).width ();
109 if (strwid > first_column_width)
110 first_column_width = strwid + 4;
111 table->setItem(index, 0, new QTableWidgetItem(c->mrl()->title));
112 table->setItem(index++, 1, new QTableWidgetItem(KMPlayer::convertNode<TVChannel>(c)->getAttribute("frequency")));
113 }
114 table->setColumnWidth (0, first_column_width);
115 table->horizontalHeader()->setStretchLastSection(true);
116 tablayout->addWidget (table);
117 tablayout->addLayout (vertlayout);
118 }
119 widget->setLayout(tablayout);
120 inputsTab->addTab (widget, input->mrl ()->title);
121 }
122 QPushButton* delButton = new QPushButton(i18n("Delete"));
123 connect (delButton, SIGNAL (clicked ()), this, SLOT (slotDelete ()));
124 QGridLayout* gridlayout = new QGridLayout;
125 gridlayout->addWidget (audioLabel, 0, 0);
126 gridlayout->addWidget (audiodevice, 0, 0, 1, 3);
127 gridlayout->addWidget (nameLabel, 1, 0);
128 gridlayout->addWidget (name, 1, 1, 1, 3);
129 gridlayout->addWidget (sizewidthLabel, 2, 0);
130 gridlayout->addWidget (sizewidth, 2, 1);
131 gridlayout->addWidget (sizeheightLabel, 2, 2);
132 gridlayout->addWidget (sizeheight, 2, 3);
133 QVBoxLayout* layout = new QVBoxLayout;
134 layout->addWidget(deviceLabel);
135 layout->addLayout(gridlayout);
136 layout->addWidget (inputsTab);
137 layout->addSpacing (5);
138 layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum));
139 QHBoxLayout *buttonlayout = new QHBoxLayout ();
140 buttonlayout->addWidget (noplayback);
141 buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
142 buttonlayout->addWidget (delButton);
143 layout->addLayout (buttonlayout);
144 setLayout(layout);
145 }
146
slotDelete()147 KDE_NO_EXPORT void TVDevicePage::slotDelete () {
148 if (KMessageBox::warningYesNo (this, i18n ("You are about to remove this device from the Source menu.\nContinue?"), i18n ("Confirm")) == KMessageBox::Yes)
149 emit deleted (this);
150 }
151
152 //-----------------------------------------------------------------------------
153
KMPlayerPrefSourcePageTV(QWidget * parent,KMPlayerTVSource * tvsource)154 KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageTV::KMPlayerPrefSourcePageTV (QWidget *parent, KMPlayerTVSource * tvsource)
155 : QFrame (parent), m_tvsource (tvsource) {
156 notebook = new QTabWidget;
157 notebook->setTabPosition (QTabWidget::South);
158 QWidget * general = new QWidget (notebook);
159 QLabel* driverLabel = new QLabel(i18n("Driver:"));
160 driver = new QLineEdit;
161 driver->setWhatsThis(i18n("dummy, v4l or bsdbt848"));
162 QLabel *deviceLabel = new QLabel(i18n("Device:"));
163 device = new KUrlRequester(KUrl("/dev/video"));
164 device->setWhatsThis(i18n("Path to your video device, eg. /dev/video0"));
165 scan = new QPushButton(i18n("Scan..."));
166 QGridLayout *gridlayout = new QGridLayout;
167 gridlayout->addWidget (driverLabel, 0, 0);
168 gridlayout->addWidget (driver, 0, 1);
169 gridlayout->addWidget (deviceLabel, 1, 0);
170 gridlayout->addWidget (device, 1, 1);
171 QHBoxLayout *buttonlayout = new QHBoxLayout;
172 buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum));
173 buttonlayout->addWidget (scan);
174 QVBoxLayout *layout = new QVBoxLayout;
175 layout->addLayout(gridlayout);
176 layout->addLayout (buttonlayout);
177 layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
178 general->setLayout(layout);
179 notebook->addTab(general, i18n("General"));
180 QVBoxLayout* mainlayout = new QVBoxLayout;
181 mainlayout->addWidget(notebook);
182 setLayout(mainlayout);
183 }
184
showEvent(QShowEvent *)185 KDE_NO_EXPORT void KMPlayerPrefSourcePageTV::showEvent (QShowEvent *) {
186 m_tvsource->readXML ();
187 }
188
189 //-----------------------------------------------------------------------------
190
TVNode(KMPlayer::NodePtr & d,const QString & s,const char * t,short id,const QString & n)191 KDE_NO_CDTOR_EXPORT TVNode::TVNode (KMPlayer::NodePtr &d, const QString & s, const char * t, short id, const QString & n) : KMPlayer::GenericMrl (d, s, n, t) {
192 this->id = id;
193 editable = true;
194 }
195
setNodeName(const QString & nn)196 KDE_NO_EXPORT void TVNode::setNodeName (const QString & nn) {
197 title = nn;
198 setAttribute (KMPlayer::Ids::attr_name, nn);
199 }
200
201 //-----------------------------------------------------------------------------
202
TVChannel(KMPlayer::NodePtr & d,const QString & n,double freq)203 KDE_NO_CDTOR_EXPORT TVChannel::TVChannel (KMPlayer::NodePtr & d, const QString & n, double freq) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel, n) {
204 setAttribute (KMPlayer::Ids::attr_name, n);
205 setAttribute ("frequency", QString::number (freq, 'f', 2));
206 }
207
TVChannel(KMPlayer::NodePtr & d)208 KDE_NO_CDTOR_EXPORT TVChannel::TVChannel (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel) {
209 }
210
closed()211 KDE_NO_EXPORT void TVChannel::closed () {
212 title = getAttribute (KMPlayer::Ids::attr_name);
213 Mrl::closed ();
214 }
215
216 //-----------------------------------------------------------------------------
217
TVInput(KMPlayer::NodePtr & d,const QString & n,int id)218 TVInput::TVInput (KMPlayer::NodePtr & d, const QString & n, int id)
219 : TVNode (d, QString ("tv://"), "input", id_node_tv_input, n) {
220 setAttribute (KMPlayer::Ids::attr_name, n);
221 setAttribute (KMPlayer::Ids::attr_id, QString::number (id));
222 }
223
TVInput(KMPlayer::NodePtr & d)224 KDE_NO_CDTOR_EXPORT TVInput::TVInput (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "input", id_node_tv_input) {
225 }
226
childFromTag(const QString & tag)227 KDE_NO_EXPORT KMPlayer::Node *TVInput::childFromTag (const QString & tag) {
228 // kDebug () << nodeName () << " childFromTag " << tag;
229 if (tag == QString::fromLatin1 ("channel")) {
230 return new TVChannel (m_doc);
231 } else
232 return 0L;
233 }
234
closed()235 KDE_NO_EXPORT void TVInput::closed () {
236 //title = getAttribute (KMPlayer::Ids::attr_name);
237 Mrl::closed ();
238 }
239
setNodeName(const QString & name)240 KDE_NO_EXPORT void TVInput::setNodeName (const QString & name) {
241 Node *p = parentNode ();
242 QString nm (name);
243 if (p && p->id == id_node_tv_device) {
244 int pos = name.indexOf (QString (" - ") + p->mrl ()->title);
245 if (pos > -1)
246 nm.truncate (pos);
247 }
248 title = nm + QString (" - ") + title;
249 TVNode::setNodeName (nm);
250 }
251
252 //-----------------------------------------------------------------------------
253
TVDevice(KMPlayer::NodePtr & doc,const QString & d)254 KDE_NO_CDTOR_EXPORT TVDevice::TVDevice (KMPlayer::NodePtr & doc, const QString & d) : TVNode (doc, d, "device", id_node_tv_device), zombie (false) {
255 setAttribute ("path", d);
256 }
257
TVDevice(KMPlayer::NodePtr & doc)258 KDE_NO_CDTOR_EXPORT TVDevice::TVDevice (KMPlayer::NodePtr & doc)
259 : TVNode (doc, i18n ("tv device"), "device", id_node_tv_device), zombie (false) {
260 }
261
~TVDevice()262 KDE_NO_CDTOR_EXPORT TVDevice::~TVDevice () {
263 if (device_page)
264 device_page->deleteLater ();
265 }
266
childFromTag(const QString & tag)267 KDE_NO_EXPORT KMPlayer::Node *TVDevice::childFromTag (const QString & tag) {
268 // kDebug () << nodeName () << " childFromTag " << tag;
269 if (tag == QString::fromLatin1 ("input"))
270 return new TVInput (m_doc);
271 return 0L;
272 }
273
closed()274 KDE_NO_EXPORT void TVDevice::closed () {
275 updateNodeName ();
276 Mrl::closed ();
277 }
278
message(KMPlayer::MessageType msg,void * data)279 KDE_NO_EXPORT void TVDevice::message (KMPlayer::MessageType msg, void *data) {
280 if (KMPlayer::MsgChildFinished == msg)
281 finish ();
282 else
283 TVNode::message (msg, data);
284 }
285
role(KMPlayer::RoleType msg,void * content)286 void *TVDevice::role (KMPlayer::RoleType msg, void *content)
287 {
288 if (KMPlayer::RolePlaylist == msg)
289 return NULL;
290 return TVNode::role (msg, content);
291 }
292
setNodeName(const QString & name)293 KDE_NO_EXPORT void TVDevice::setNodeName (const QString & name) {
294 TVNode::setNodeName (name);
295 updateNodeName ();
296 }
297
updateNodeName()298 KDE_NO_EXPORT void TVDevice::updateNodeName () {
299 title = getAttribute (KMPlayer::Ids::attr_name);
300 src = getAttribute ("path");
301 for (KMPlayer::Node *c = firstChild (); c; c = c->nextSibling ())
302 if (c->id == id_node_tv_input) {
303 TVInput * i = static_cast <TVInput *> (c);
304 i->title = i->getAttribute (KMPlayer::Ids::attr_name) +
305 QString (" - ") + title;
306 }
307 }
308
updateDevicePage()309 KDE_NO_EXPORT void TVDevice::updateDevicePage () {
310 if (!device_page)
311 return;
312 title = device_page->name->text ();
313 setAttribute (KMPlayer::Ids::attr_name, title);
314 setAttribute ("audio", device_page->audiodevice->lineEdit()->text ());
315 setAttribute ("playback", device_page->noplayback->isChecked() ? "0" : "1");
316 setAttribute (KMPlayer::Ids::attr_width, device_page->sizewidth->text ());
317 setAttribute (KMPlayer::Ids::attr_height, device_page->sizeheight->text ());
318 int i = 0;
319 for (KMPlayer::Node *ip = firstChild(); ip; ip=ip->nextSibling(),++i) {
320 if (ip->id != id_node_tv_input)
321 continue;
322 TVInput * input = KMPlayer::convertNode <TVInput> (ip);
323 bool ok;
324 if (input->getAttribute ("tuner").toInt (&ok) && ok) {
325 QWidget* widget = device_page->inputsTab->widget(i);
326 QTableWidget* table = static_cast<QTableWidget*>(widget->findChild<QTableWidget*>("PageTVChannels"));
327 if (table) {
328 input->clearChildren ();
329 for (int j = 0; j<table->rowCount() && table->item (j, 1); ++j) {
330 input->appendChild (new TVChannel (m_doc, table->item (j, 0)->text (), table->item (j, 1)->text ().toDouble ()));
331 }
332 }
333 QComboBox* norms = static_cast<QComboBox*>(widget->findChild<QComboBox*>("PageTVNorm"));
334 if (norms) {
335 input->setAttribute ("norm", norms->currentText ());
336 }
337 }
338 }
339 }
340
341 //-----------------------------------------------------------------------------
342
343 KDE_NO_CDTOR_EXPORT
TVDocument(KMPlayerTVSource * source)344 TVDocument::TVDocument (KMPlayerTVSource * source)
345 : FileDocument (id_node_tv_document, "tv://", source), m_source (source) {
346 title = i18n ("Television");
347 bookmarkable = false;
348 }
349
childFromTag(const QString & tag)350 KDE_NO_EXPORT KMPlayer::Node *TVDocument::childFromTag (const QString & tag) {
351 // kDebug () << nodeName () << " childFromTag " << tag;
352 if (tag == QString::fromLatin1 ("device"))
353 return new TVDevice (m_doc);
354 return FileDocument::childFromTag (tag);
355 }
356
message(KMPlayer::MessageType msg,void * data)357 KDE_NO_EXPORT void TVDocument::message (KMPlayer::MessageType msg, void *data) {
358 if (KMPlayer::MsgChildFinished == msg)
359 finish ();
360 else
361 FileDocument::message (msg, data);
362 }
363
defer()364 KDE_NO_EXPORT void TVDocument::defer () {
365 if (!resolved) {
366 resolved = true;
367 readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml");
368 }
369 }
370
371 //-----------------------------------------------------------------------------
372
KMPlayerTVSource(KMPlayerApp * a)373 KDE_NO_CDTOR_EXPORT KMPlayerTVSource::KMPlayerTVSource(KMPlayerApp* a)
374 : KMPlayer::Source (i18n ("TV"), a->player(), "tvsource"), m_app(a), m_configpage(0L), scanner(0L), config_read(false) {
375 m_url = "tv://";
376 m_document = new TVDocument (this);
377 m_player->settings ()->addPage (this);
378 tree_id = m_player->playModel()->addTree (m_document, "tvsource", "video-television", KMPlayer::PlayModel::TreeEdit | KMPlayer::PlayModel::Moveable | KMPlayer::PlayModel::Deleteable);
379 }
380
~KMPlayerTVSource()381 KDE_NO_CDTOR_EXPORT KMPlayerTVSource::~KMPlayerTVSource () {
382 static_cast <TVDocument *> (m_document.ptr ())->sync
383 (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml");
384 }
385
activate()386 KDE_NO_EXPORT void KMPlayerTVSource::activate () {
387 m_identified = true;
388 //if (m_player->settings ()->showbroadcastbutton)
389 // m_app->view()->controlPanel()->broadcastButton ()->show ();
390 if (m_cur_tvdevice && !m_current) {
391 for (KMPlayer::Node *i = m_cur_tvdevice->firstChild(); i && !m_current; i=i->nextSibling())
392 if (i->id == id_node_tv_input) {
393 TVInput * input = KMPlayer::convertNode <TVInput> (i);
394 bool ok;
395 m_cur_tvinput = i;
396 if (input->getAttribute ("tuner").toInt (&ok) && ok) {
397 for (KMPlayer::Node *c = i->firstChild (); c; c = c->nextSibling ())
398 if (c->id == id_node_tv_channel) {
399 setCurrent (c->mrl ());
400 break;
401 }
402 } else
403 m_current = i;
404 }
405 } else if (!m_cur_tvdevice)
406 KMPlayer::Source::reset ();
407 if (m_cur_tvdevice) {
408 QString playback = static_cast <KMPlayer::Element *> (m_cur_tvdevice.ptr ())->getAttribute (QString::fromLatin1 ("playback"));
409 if (playback.isEmpty () || playback.toInt ())
410 QTimer::singleShot (0, m_player, SLOT (play ()));
411 }
412 }
413 /* TODO: playback by
414 * ffmpeg -vd /dev/video0 -r 25 -s 768x576 -f rawvideo - |mplayer -nocache -ao arts -rawvideo on:w=768:h=576:fps=25 -quiet -
415 */
416
deactivate()417 KDE_NO_EXPORT void KMPlayerTVSource::deactivate () {
418 //if (m_player->view () && !m_app->view ()->controlPanel()->broadcastButton ()->isOn ())
419 // m_app->view ()->controlPanel()->broadcastButton ()->hide ();
420 reset ();
421 }
422
play(KMPlayer::Mrl * mrl)423 void KMPlayerTVSource::play (KMPlayer::Mrl *mrl) {
424 if (mrl && mrl->id == id_node_tv_document) {
425 readXML ();
426 } else {
427 m_current = mrl;
428 for (KMPlayer::Node *e = mrl; e; e = e->parentNode ()) {
429 if (e->id == id_node_tv_device) {
430 m_cur_tvdevice = e;
431 break;
432 } else if (e->id == id_node_tv_input)
433 m_cur_tvinput = e;
434 }
435 if (m_player->source () != this)
436 m_player->setSource (this);
437 else
438 KMPlayer::Source::play (mrl);
439 /*else if (m_player->process ()->playing ()) {
440 //m_back_request = m_current;
441 m_player->process ()->stop ();
442 } else {
443 buildArguments ();
444 if (m_app->broadcasting ())
445 QTimer::singleShot (0, m_app->broadcastConfig (), SLOT (startFeed ()));
446 else
447 KMPlayer::Source::play (mrl);
448 }*/
449 }
450 }
451
root()452 KDE_NO_EXPORT KMPlayer::NodePtr KMPlayerTVSource::root () {
453 return m_cur_tvinput;
454 }
455
setCurrent(KMPlayer::Mrl * mrl)456 KDE_NO_EXPORT void KMPlayerTVSource::setCurrent (KMPlayer::Mrl *mrl) {
457 TVChannel * channel = 0L;
458 TVInput * input = 0L;
459 m_current = mrl;
460 KMPlayer::NodePtr elm = m_current;
461 if (elm && elm->id == id_node_tv_channel) {
462 channel = KMPlayer::convertNode <TVChannel> (elm);
463 elm = elm->parentNode ();
464 }
465 if (elm && elm->id == id_node_tv_input)
466 input = KMPlayer::convertNode <TVInput> (elm);
467 if (!(channel || (input && input->getAttribute ("tuner").isEmpty ())))
468 return;
469 m_cur_tvinput = input;
470 m_cur_tvdevice = input->parentNode ();
471 m_player->playModel()->updateTree(0, m_cur_tvinput, m_current, true, false);
472 if (m_cur_tvdevice->id != id_node_tv_device) {
473 return;
474 }
475 TVDevice * tvdevice = KMPlayer::convertNode <TVDevice> (m_cur_tvdevice);
476 m_identified = true;
477 m_audiodevice = tvdevice->getAttribute ("audio");
478 m_videodevice = tvdevice->src;
479 m_videonorm = input->getAttribute ("norm");
480 m_tuner = input->getAttribute (KMPlayer::Ids::attr_name);
481 QString xvport = tvdevice->getAttribute ("xvport");
482 if (!xvport.isEmpty ())
483 m_xvport = xvport.toInt ();
484 QString xvenc = input->getAttribute ("xvenc");
485 if (!xvenc.isEmpty ())
486 m_xvencoding = xvenc.toInt ();
487 QString command;
488 command.sprintf ("device=%s:input=%s",
489 tvdevice->src.toAscii ().data (),
490 input->getAttribute (KMPlayer::Ids::attr_id).toAscii ().data ());
491 if (channel) {
492 QString freq = channel->getAttribute ("frequency");
493 m_frequency = (int)(1000 * freq.toDouble ());
494 command += QString (":freq=%1").arg (freq);
495 } else
496 m_frequency = 0;
497 if (!m_videonorm.isEmpty ())
498 command += QString (":norm=%1").arg (m_videonorm);
499 m_app->setCaption (i18n ("TV: ") + (channel ? channel->mrl ()->title : input->mrl ()->title), false);
500 setDimensions (m_cur_tvdevice,
501 tvdevice->getAttribute (KMPlayer::Ids::attr_width).toInt (),
502 tvdevice->getAttribute (KMPlayer::Ids::attr_height).toInt ());
503 m_options.sprintf ("-tv noaudio:driver=%s:%s:width=%d:height=%d -slave -nocache -quiet", tvdriver.toAscii ().data (), command.toAscii ().data (), width (), height ());
504 m_recordcmd.sprintf ("-tv %s:driver=%s:%s:width=%d:height=%d", m_audiodevice.isEmpty () ? "noaudio" : QString(QLatin1String ("forceaudio:adevice=") + m_audiodevice).toAscii ().data(), tvdriver.toAscii ().data (), command.toAscii ().data (), width (), height ());
505 }
506
menuClicked(int id)507 KDE_NO_EXPORT void KMPlayerTVSource::menuClicked (int id) {
508 KMPlayer::Node *elm = m_document->firstChild ();
509 for (; id > 0; --id, elm = elm->nextSibling ())
510 ;
511 m_cur_tvdevice = elm;
512 m_cur_tvinput = elm->firstChild (); // FIXME
513 m_current = 0L;
514 m_player->setSource (this);
515 }
516
filterOptions()517 KDE_NO_EXPORT QString KMPlayerTVSource::filterOptions () {
518 if (! m_player->settings ()->disableppauto)
519 return KMPlayer::Source::filterOptions ();
520 return QString ("-vf pp=lb");
521 }
522
hasLength()523 KDE_NO_EXPORT bool KMPlayerTVSource::hasLength () {
524 return false;
525 }
526
isSeekable()527 KDE_NO_EXPORT bool KMPlayerTVSource::isSeekable () {
528 return true;
529 }
530
prettyName()531 KDE_NO_EXPORT QString KMPlayerTVSource::prettyName () {
532 QString name (i18n ("TV"));
533 //if (m_tvsource)
534 // name += ' ' + m_tvsource->title;
535 return name;
536 }
537
write(KSharedConfigPtr m_config)538 KDE_NO_EXPORT void KMPlayerTVSource::write (KSharedConfigPtr m_config) {
539 if (!config_read) return;
540 KConfigGroup (m_config, strTV).writeEntry (strTVDriver, tvdriver);
541 static_cast <TVDocument *> (m_document.ptr ())->writeToFile
542 (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml");
543 kDebug () << "KMPlayerTVSource::write XML";
544 }
545
readXML()546 KDE_NO_EXPORT void KMPlayerTVSource::readXML () {
547 if (config_read) return;
548 config_read = true;
549 kDebug () << "KMPlayerTVSource::readXML";
550 m_document->defer ();
551 m_player->playModel()->updateTree (tree_id, m_document, 0, false, false);
552 sync (false);
553 }
554
read(KSharedConfigPtr m_config)555 KDE_NO_EXPORT void KMPlayerTVSource::read (KSharedConfigPtr m_config) {
556 tvdriver = KConfigGroup (m_config, strTV).readEntry (
557 strTVDriver, QString ("v4l2"));
558 }
559
sync(bool fromUI)560 KDE_NO_EXPORT void KMPlayerTVSource::sync (bool fromUI) {
561 if (!m_configpage) return;
562 if (m_document && m_document->hasChildNodes ())
563 m_app->showBroadcastConfig ();
564 else
565 m_app->hideBroadcastConfig ();
566 if (fromUI) {
567 tvdriver = m_configpage->driver->text ();
568 for (KMPlayer::Node *d=m_document->firstChild();d; d=d->nextSibling())
569 if (d->id == id_node_tv_device)
570 static_cast <TVDevice *> (d)->updateDevicePage ();
571 m_player->playModel()->updateTree(tree_id, m_document, 0, false, false);
572 } else {
573 m_configpage->driver->setText (tvdriver);
574 for (KMPlayer::Node *dp = m_document->firstChild (); dp; dp = dp->nextSibling ())
575 if (dp->id == id_node_tv_device)
576 addTVDevicePage (KMPlayer::convertNode <TVDevice> (dp));
577 }
578 }
579
prefLocation(QString & item,QString & icon,QString & tab)580 KDE_NO_EXPORT void KMPlayerTVSource::prefLocation (QString & item, QString & icon, QString & tab) {
581 item = i18n ("Source");
582 icon = QString ("source");
583 tab = i18n ("TV");
584 }
585
prefPage(QWidget * parent)586 KDE_NO_EXPORT QFrame * KMPlayerTVSource::prefPage (QWidget * parent) {
587 if (!m_configpage) {
588 m_configpage = new KMPlayerPrefSourcePageTV (parent, this);
589 scanner = new TVDeviceScannerSource (this);
590 connect (m_configpage->scan, SIGNAL(clicked()), this, SLOT(slotScan()));
591 }
592 return m_configpage;
593 }
594
hasTVDevice(KMPlayer::NodePtr doc,const QString & devstr)595 static bool hasTVDevice (KMPlayer::NodePtr doc, const QString & devstr) {
596 for (KMPlayer::Node *e = doc->firstChild (); e; e = e->nextSibling ())
597 if (e->id == id_node_tv_device &&
598 static_cast <TVDevice *> (e)->src == devstr)
599 return true;
600 return false;
601 }
602
slotScan()603 KDE_NO_EXPORT void KMPlayerTVSource::slotScan () {
604 QString devstr = m_configpage->device->lineEdit()->text ();
605 if (!hasTVDevice(m_document, devstr)) {
606 scanner->scan (devstr, m_configpage->driver->text());
607 connect (scanner, SIGNAL (scanFinished (TVDevice *)),
608 this, SLOT (slotScanFinished (TVDevice *)));
609 } else
610 KMessageBox::error (m_configpage, i18n ("Device already present."),
611 i18n ("Error"));
612 }
613
slotScanFinished(TVDevice * tvdevice)614 KDE_NO_EXPORT void KMPlayerTVSource::slotScanFinished (TVDevice * tvdevice) {
615 disconnect (scanner, SIGNAL (scanFinished (TVDevice *)),
616 this, SLOT (slotScanFinished (TVDevice *)));
617 if (tvdevice) {
618 tvdevice->zombie = false;
619 addTVDevicePage (tvdevice, true);
620 m_player->playModel()->updateTree(tree_id, m_document, 0, false, false);
621 } else
622 KMessageBox::error(m_configpage,i18n("No device found."),i18n("Error"));
623 }
624
addTVDevicePage(TVDevice * dev,bool show)625 KDE_NO_EXPORT void KMPlayerTVSource::addTVDevicePage(TVDevice *dev, bool show) {
626 if (dev->device_page)
627 dev->device_page->deleteLater ();
628 dev->device_page = new TVDevicePage (m_configpage->notebook, dev);
629 m_configpage->notebook->addTab(dev->device_page, dev->title);
630 connect (dev->device_page, SIGNAL (deleted (TVDevicePage *)),
631 this, SLOT (slotDeviceDeleted (TVDevicePage *)));
632 if (show)
633 m_configpage->notebook->setCurrentIndex(m_configpage->notebook->count()-1);
634 }
635
slotDeviceDeleted(TVDevicePage * devpage)636 KDE_NO_EXPORT void KMPlayerTVSource::slotDeviceDeleted (TVDevicePage *devpage) {
637 m_document->removeChild (devpage->device_doc);
638 m_configpage->notebook->setCurrentIndex(0);
639 m_player->playModel()->updateTree (tree_id, m_document, 0, false, false);
640 }
641
642 //-----------------------------------------------------------------------------
643
TVDeviceScannerSource(KMPlayerTVSource * src)644 KDE_NO_CDTOR_EXPORT TVDeviceScannerSource::TVDeviceScannerSource (KMPlayerTVSource * src)
645 : KMPlayer::Source (i18n ("TVScanner"), src->player (), "tvscanner"),
646 m_tvsource (src),
647 m_tvdevice (0L),
648 m_process (NULL),
649 m_viewer (NULL) {
650 }
651
init()652 KDE_NO_EXPORT void TVDeviceScannerSource::init () {
653 }
654
processOutput(const QString & line)655 KDE_NO_EXPORT bool TVDeviceScannerSource::processOutput (const QString & line) {
656 if (m_nameRegExp.indexIn(line) > -1) {
657 m_tvdevice->title = m_nameRegExp.cap (1);
658 m_tvdevice->setAttribute(KMPlayer::Ids::attr_name,m_tvdevice->title);
659 kDebug() << "Name " << m_tvdevice->title;
660 } else if (m_sizesRegExp.indexIn(line) > -1) {
661 m_tvdevice->setAttribute (KMPlayer::Ids::attr_width,
662 m_sizesRegExp.cap(1));
663 m_tvdevice->setAttribute (KMPlayer::Ids::attr_height,
664 m_sizesRegExp.cap(2));
665 m_tvdevice->setAttribute ("minwidth", m_sizesRegExp.cap (1));
666 m_tvdevice->setAttribute ("minheight", m_sizesRegExp.cap (2));
667 m_tvdevice->setAttribute ("maxwidth", m_sizesRegExp.cap (3));
668 m_tvdevice->setAttribute ("maxheight", m_sizesRegExp.cap (4));
669 } else if (m_inputRegExp.indexIn(line) > -1) {
670 KMPlayer::NodePtr doc = m_tvsource->document ();
671 TVInput * input = new TVInput (doc, m_inputRegExp.cap(2).trimmed(),
672 m_inputRegExp.cap (1).toInt ());
673 if (m_inputRegExp.cap (3).toInt () == 1)
674 input->setAttribute ("tuner", "1");
675 m_tvdevice->appendChild (input);
676 kDebug() << "Input " << input->mrl ()->title;
677 } else if (m_inputRegExpV4l2.indexIn(line) > -1) {
678 KMPlayer::NodePtr doc = m_tvsource->document ();
679 QStringList sl = m_inputRegExpV4l2.cap(1).split (QChar (';'));
680 const QStringList::iterator e = sl.end ();
681 for (QStringList::iterator i = sl.begin (); i != e; ++i) {
682 int pos = (*i).indexOf (QChar ('='));
683 if (pos > 0) {
684 int id = (*i).left (pos).trimmed ().toInt ();
685 TVInput *input = new TVInput(doc,(*i).mid(pos+1).trimmed(), id);
686 if (!id && m_caps.indexOf ("tuner") > -1)
687 input->setAttribute ("tuner", "1");
688 m_tvdevice->appendChild (input);
689 }
690 }
691 } else {
692 int pos = line.indexOf ("Capabilites:");
693 if (pos > 0)
694 m_caps = line.mid (pos + 12);
695 return false;
696 }
697 return true;
698 }
699
filterOptions()700 KDE_NO_EXPORT QString TVDeviceScannerSource::filterOptions () {
701 return QString ("");
702 }
703
hasLength()704 KDE_NO_EXPORT bool TVDeviceScannerSource::hasLength () {
705 return false;
706 }
707
isSeekable()708 KDE_NO_EXPORT bool TVDeviceScannerSource::isSeekable () {
709 return false;
710 }
711
scan(const QString & dev,const QString & dri)712 KDE_NO_EXPORT bool TVDeviceScannerSource::scan (const QString & dev, const QString & dri) {
713 if (m_tvdevice)
714 return false;
715 setUrl ("tv://");
716 KMPlayer::NodePtr doc = m_tvsource->document ();
717 m_tvdevice = new TVDevice (doc, dev);
718 m_tvsource->document ()->appendChild (m_tvdevice);
719 m_tvdevice->zombie = true; // not for real yet
720 m_driver = dri;
721 m_old_source = m_tvsource->player ()->source ();
722 m_tvsource->player ()->setSource (this);
723 m_identified = true;
724 play (m_tvdevice);
725 return true;
726 }
727
activate()728 KDE_NO_EXPORT void TVDeviceScannerSource::activate () {
729 m_nameRegExp.setPattern ("Selected device:\\s*([^\\s].*)");
730 m_sizesRegExp.setPattern ("Supported sizes:\\s*([0-9]+)x([0-9]+) => ([0-9]+)x([0-9]+)");
731 m_inputRegExp.setPattern ("\\s*([0-9]+):\\s*([^:]+):[^\\(]*\\(tuner:([01]),\\s*norm:([^\\)]+)\\)");
732 m_inputRegExpV4l2.setPattern ("inputs:((?:\\s*[0-9]+\\s*=\\s*[^;]+;)+)");
733 }
734
deactivate()735 KDE_NO_EXPORT void TVDeviceScannerSource::deactivate () {
736 kDebug () << "TVDeviceScannerSource::deactivate";
737 if (m_tvdevice) {
738 if (m_tvdevice->parentNode ())
739 m_tvdevice->parentNode ()->removeChild (m_tvdevice);
740 m_tvdevice = 0L;
741 delete m_process;
742 emit scanFinished (m_tvdevice);
743 }
744 }
745
play(KMPlayer::Mrl *)746 KDE_NO_EXPORT void TVDeviceScannerSource::play (KMPlayer::Mrl *) {
747 if (!m_tvdevice)
748 return;
749 m_options.sprintf ("tv:// -tv driver=%s:device=%s -identify -frames 0", m_driver.toAscii ().data (), m_tvdevice->src.toAscii ().data ());
750 m_tvsource->player ()->stop ();
751 KMPlayer::Node *n = new KMPlayer::SourceDocument (this, QString ());
752 setDocument (n, n);
753 m_process = m_player->mediaManager()->processInfos()["mplayer"]->create (m_player, this);
754 m_viewer = m_player->viewWidget ()->viewArea ()->createVideoWidget ();
755 m_process->ready ();
756 }
757
scanningFinished()758 KDE_NO_EXPORT void TVDeviceScannerSource::scanningFinished () {
759 TVDevice * dev = 0L;
760 delete m_process;
761 kDebug () << "scanning done " << m_tvdevice->hasChildNodes ();
762 if (!m_tvdevice->hasChildNodes ()) {
763 m_tvsource->document ()->removeChild (m_tvdevice);
764 } else {
765 dev = m_tvdevice;
766 if (width () > 0 && height () > 0) {
767 m_tvdevice->setAttribute (KMPlayer::Ids::attr_width,
768 QString::number (width ()));
769 m_tvdevice->setAttribute (KMPlayer::Ids::attr_height,
770 QString::number (height ()));
771 }
772 }
773 m_tvdevice = 0L;
774 m_player->setSource (m_old_source);
775 emit scanFinished (dev);
776 }
777
stateChange(KMPlayer::IProcess *,KMPlayer::IProcess::State os,KMPlayer::IProcess::State ns)778 void TVDeviceScannerSource::stateChange (KMPlayer::IProcess *,
779 KMPlayer::IProcess::State os, KMPlayer::IProcess::State ns) {
780 if (KMPlayer::IProcess::Ready == ns) {
781 if (os > KMPlayer::IProcess::Ready)
782 QTimer::singleShot (0, this, SLOT (scanningFinished()));
783 else if (m_process && os < KMPlayer::IProcess::Ready)
784 m_process->play ();
785 }
786 }
787
processDestroyed(KMPlayer::IProcess *)788 void TVDeviceScannerSource::processDestroyed (KMPlayer::IProcess *) {
789 m_process = NULL;
790 KMPlayer::View *view = m_player->viewWidget ();
791 if (view)
792 view->viewArea ()->destroyVideoWidget (m_viewer);
793 m_viewer = NULL;
794 }
795
viewer()796 KMPlayer::IViewer *TVDeviceScannerSource::viewer () {
797 return m_viewer;
798 }
799
getMrl()800 KMPlayer::Mrl *TVDeviceScannerSource::getMrl () {
801 return document ()->mrl ();
802 }
803
804
805 #include "kmplayertvsource.moc"
806