Ticket #192: mythtv-dbox2-200508022011.patch.text

File mythtv-dbox2-200508022011.patch.text, 68.7 KB (added by mythtv@…, 20 years ago)

[mythtv] [PATCH] DBOX2 Feed Implementation 2005-08-02 (including missing files)

Line 
1diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/configure mythtv-current-dbox2/configure
2--- mythtv-current/configure 2005-08-02 20:05:21.000000000 +0200
3+++ mythtv-current-dbox2/configure 2005-08-02 15:54:33.000000000 +0200
4@@ -47,6 +47,7 @@
5 lirc="yes"
6 joystick_menu="yes"
7 firewire_cable_box="yes"
8+dbox2_dvb_box="yes"
9 x11="yes"
10 xrandr="yes"
11 xv="yes"
12@@ -163,6 +164,7 @@
13 echo " --disable-lirc disable lirc support (Infrared Remotes)"
14 echo " --disable-joystick-menu disable joystick menu"
15 echo " --disable-firewire disable support for FireWire cable boxes"
16+echo " --disable-dbox2 disable support for Nokia DBOX2 DVB boxes (or compatibles)"
17 echo " --disable-v4l disable Video4Linux support"
18 echo " --disable-ivtv disable ivtv support (PVR-x50) req. v4l support"
19 #echo " --enable-ivtv-sys-header use ivtv system headers instead of myth headers"
20@@ -724,6 +726,10 @@
21 ;;
22 --disable-firewire) firewire_cable_box="no"
23 ;;
24+ --enable-dbox2) dbox2_dvb_box="yes"
25+ ;;
26+ --disable-dbox2) dbox2_dvb_box="no"
27+ ;;
28 --enable-dvb) dvb="yes"
29 ;;
30 --disable-dvb) dvb="no"
31@@ -2540,6 +2546,11 @@
32 echo "CONFIG_FIREWIRE_LIBS=-lraw1394 -liec61883 -lavc1394" >> $MYTH_CONFIG_MAK
33 fi
34
35+if test x"$dbox2_dvb_box" = x"yes" ; then
36+ CCONFIG="$CCONFIG using_dbox2"
37+ CONFIG_DEFINES="$CONFIG_DEFINES USING_DBOX2"
38+fi
39+
40 if test x"$lirc" = x"yes" ; then
41 CCONFIG="$CCONFIG using_lirc"
42 echo "CONFIG_LIRC_LIBS=-llirc_client" >> $MYTH_CONFIG_MAK
43diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/docs/mythtv-HOWTO.sgml mythtv-current-dbox2/docs/mythtv-HOWTO.sgml
44--- mythtv-current/docs/mythtv-HOWTO.sgml 2005-07-29 16:05:29.000000000 +0200
45+++ mythtv-current-dbox2/docs/mythtv-HOWTO.sgml 2005-07-29 16:06:15.000000000 +0200
46@@ -471,6 +471,10 @@
47 <sect3>Firewire.
48 <p>You may use the Firewire output of the DCT6200 or the SA3250.
49
50+<sect3>DBoxII or other devices running Neutrino
51+<p>You may use the Ethernet port of an DBoxII or a similar device to capture
52+MPEG2. Your set top box has to be running the Neutrino GUI.
53+
54 <sect3>USB Capture Devices.
55 <p>The Plextor ConvertX PVR devices are supported through Linux drivers
56 available from <url
57@@ -6467,6 +6471,26 @@
58
59 <tt>growisofs -Z /dev/scd0 -dvd-video DVD</tt>
60
61+<sect1>Using the DBoxII within MythTV
62+<p>The configuration of the DBoxII for use within MythTV is tricky
63+(as of May 16 2005), that's why it's covered here. Your DBoxII has to be
64+running linux and the Neutrino GUI instead of the stock BetaNova firmware.
65+For further information, please refer to <url url="http://www.tuxbox.org" name="http://www.tuxbox.org">. Additionally, you need to enable the SPTS mode in
66+Neutrino.
67+
68+1.) Add a new "Capture Card" in the setup. The "Card type" is "DBOX2 Input",
69+the other values have to be adjusted according to your setup.
70+The default values, except for the "DBOX2 host ip", should work fine.
71+2.) Define a new video source. It doesn't need to be configured,
72+you just need to define it. MythTV grabs the EPG from the DBoxII.
73+3.) Connect the DBoxII to the newly defined input source in "input connections".
74+4.) Since channel scanning is not implemented yet, you need to define channels
75+in the "Channel Editor". Make sure that you use the same value for
76+"Channel Name" as on the DBoxII. You can get a list of available
77+channels from the web interface of Neutrino at http://ip-of-your-box:80/.
78+Associate the channel with your new video source and repeat when needed.
79+
80+You may leave the Setup now and proceed as usual.
81
82 <sect1>Migrating from XMLTV to DataDirect <label id="MigratingtoDD">
83 <!-- Mostly from a post by Bruce Markey -->
84diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbcheck.cpp mythtv-current-dbox2/libs/libmythtv/dbcheck.cpp
85--- mythtv-current/libs/libmythtv/dbcheck.cpp 2005-07-29 16:05:53.000000000 +0200
86+++ mythtv-current-dbox2/libs/libmythtv/dbcheck.cpp 2005-07-29 19:21:25.000000000 +0200
87@@ -10,7 +10,7 @@
88 #include "mythdbcon.h"
89
90 /// This is the DB schema version expected by the running MythTV instance.
91-const QString currentDatabaseVersion = "1089";
92+const QString currentDatabaseVersion = "1090";
93
94 static bool UpdateDBVersionNumber(const QString &newnumber);
95 static bool performActualUpdate(const QString updates[], QString version,
96@@ -1977,6 +1977,20 @@
97 return false;
98 }
99
100+ if (dbver == "1089")
101+ {
102+ const QString updates[] = {
103+ "INSERT INTO profilegroups SET name = 'DBOX2 Input', cardtype = 'DBOX2', is_default = 1;",
104+ "ALTER TABLE capturecard ADD COLUMN dbox2_port INT UNSIGNED NOT NULL DEFAULT 31338;",
105+ "ALTER TABLE capturecard ADD COLUMN dbox2_httpport INT UNSIGNED NOT NULL DEFAULT 80;",
106+ "ALTER TABLE capturecard ADD COLUMN dbox2_host varchar(32) NULL;",
107+ ""
108+ };
109+
110+ if (!performActualUpdate(updates, "1090", dbver))
111+ return false;
112+ }
113+
114 // Drop xvmc_buffer_settings at some point
115 // Drop dead DVB tables eventually, too
116
117diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbox2channel.cpp mythtv-current-dbox2/libs/libmythtv/dbox2channel.cpp
118--- mythtv-current/libs/libmythtv/dbox2channel.cpp 1970-01-01 01:00:00.000000000 +0100
119+++ mythtv-current-dbox2/libs/libmythtv/dbox2channel.cpp 2005-07-29 18:51:55.000000000 +0200
120@@ -0,0 +1,335 @@
121+/**
122+ * DBox2Channel
123+ * Copyright (c) 2005 by Levent GÃŒndogdu
124+ * Distributed as part of MythTV under GPL v2 and later.
125+ */
126+
127+
128+#include <iostream>
129+#include <qsqldatabase.h>
130+#include "mythdbcon.h"
131+#include "mythcontext.h"
132+#include "dbox2channel.h"
133+
134+//#define DBOX2_CHANNEL_DEBUG
135+
136+DBox2Channel::DBox2Channel(TVRec *parent, dbox2_options_t *dbox2_options, int cardid): ChannelBase(parent) {
137+ m_dbox2options = dbox2_options;
138+ m_cardid = cardid;
139+ m_dbox2channelcount = 0;
140+ m_lastChannel = "1";
141+ m_requestChannel = "";
142+ m_channelListReady = false;
143+ capchannels = 1;
144+ channelnames[0] = "DBOX2";
145+ // Create EPG
146+ m_epg = new DBox2EPG();
147+ m_recorderAlive = false;
148+ // Create http
149+ http = new QHttp();
150+ httpChanger = new QHttp();
151+ // Connect signals
152+ connect (http, SIGNAL(done(bool)), this, SLOT(HttpRequestDone(bool)));
153+ connect (httpChanger, SIGNAL(done(bool)), this, SLOT(HttpChannelChangeDone(bool)));
154+ connect (m_epg, SIGNAL(EPGFinished()), this, SLOT(EPGFinished()));
155+ // Load channel names and ids from the dbox
156+ LoadChannels();
157+}
158+
159+DBox2Channel::~DBox2Channel(void)
160+{
161+ // Shutdown EPG
162+ disconnect (m_epg, SIGNAL(EPGFinished()), this, SLOT(EPGFinished()));
163+ m_epg->Shutdown();
164+ delete m_epg;
165+ // Abort pending channel changes
166+ httpChanger->abort();
167+ httpChanger->closeConnection();
168+ disconnect (httpChanger, SIGNAL(done(bool)), this, SLOT(httpChannelChangeDone(bool)));
169+ // Abort pending channel list requests
170+ http->abort();
171+ http->closeConnection();
172+ disconnect (http, SIGNAL(done(bool)), this, SLOT(httpRequestDone(bool)));
173+ delete http;
174+}
175+
176+void DBox2Channel::SwitchToLastChannel()
177+{
178+ Log(QString("Switching to last channel %1.").arg(m_lastChannel));
179+ SetChannelByString(m_lastChannel);
180+}
181+
182+bool DBox2Channel::SetChannelByString(const QString &newChan) {
183+ // Delay set channel when list has not yet been retrieved
184+ if (!m_channelListReady)
185+ {
186+ Log(QString("Channel list not received yet. Will switch to channel %1 later...").arg(newChan));
187+ m_requestChannel = newChan;
188+ return true;
189+ }
190+ QString chan = newChan;
191+ if (chan == "")
192+ {
193+ Log(QString("Empty channel name has been provided. Getting default name."));
194+ chan = GetDefaultChannel();
195+ }
196+ Log(QString("Changing to %1.").arg(chan));
197+ if (m_lastChannel != curchannelname)
198+ m_lastChannel = curchannelname;
199+ curchannelname = chan;
200+
201+ // Zap DBox2 to requested channel
202+ // Find channel name from channel number
203+ QString channelName = GetChannelNameFromNumber(chan);
204+ if (channelName == "")
205+ {
206+ Log(QString("Changing to %1 failed. Channel not found!").arg(chan));
207+ QString defaultChannel = GetDefaultChannel();
208+ if (defaultChannel != chan)
209+ {
210+ Log(QString("Trying default channel %1").arg(defaultChannel));
211+ return SetChannelByString(defaultChannel);
212+ }
213+ return false;
214+ }
215+
216+ // Find dbox2 channel id from channel name
217+ QString channelID = GetChannelID(channelName);
218+ if (channelID == "")
219+ {
220+ Log(QString("Changing to %1 failed. DBox2 channel ID for name %2 not found!").arg(chan).arg(channelName));
221+ QString defaultChannel = GetDefaultChannel();
222+ if (defaultChannel != chan)
223+ {
224+ Log(QString("Trying default channel %1").arg(defaultChannel));
225+ return SetChannelByString(defaultChannel);
226+ }
227+ return false;
228+ }
229+
230+ Log(QString("Channel ID for %1 is %2.").arg(chan).arg(channelID));
231+
232+ // Request channel change
233+ ChannelChanging();
234+ RequestChannelChange(channelID);
235+ return true;
236+}
237+
238+bool DBox2Channel::Open() {
239+ Log(QString("Channel instantiated."));
240+ return true;
241+}
242+void DBox2Channel::Close() {
243+ Log(QString("Channel destructed."));
244+}
245+
246+void DBox2Channel::SwitchToInput(const QString &input, const QString &chan)
247+{
248+ currentcapchannel = 0;
249+ if (channelnames.empty())
250+ channelnames[currentcapchannel] = input;
251+
252+ SetChannelByString(chan);
253+}
254+
255+void DBox2Channel::LoadChannels() {
256+ Log(QString("Loading channels..."));
257+ Log(QString("Reading channel list from %1:%2")
258+ .arg(m_dbox2options->host)
259+ .arg(m_dbox2options->httpport));
260+
261+ // Request Channel list via http. Signal will be emmitted when list is ready.
262+ QHttpRequestHeader header("GET", "/control/channellist");
263+ header.setValue("Host", m_dbox2options->host);
264+ http->setHost(m_dbox2options->host, m_dbox2options->httpport);
265+ http->request(header);
266+}
267+
268+void DBox2Channel::HttpRequestDone(bool error)
269+{
270+ if (error)
271+ {
272+ Log(QString("Reading channel list failed!"));
273+ return;
274+ }
275+
276+ QString buffer=http->readAll();
277+ Log(QString("Reading channel list succeeded."));
278+ m_dbox2channelcount = 0;
279+ while (true)
280+ {
281+ QString line = buffer.section("\n", m_dbox2channelcount, m_dbox2channelcount);
282+ if (line == "")
283+ break;
284+ m_dbox2channelids[m_dbox2channelcount] = line.section(" ", 0, 0);
285+ m_dbox2channelnames[m_dbox2channelcount] = line.section(" ", 1, 5);
286+#ifdef DBOX2_CHANNEL_DEBUG
287+ Log(QString("Found Channel %1.").arg(m_dbox2channelnames[m_dbox2channelcount]));
288+#endif
289+ m_dbox2channelcount++;
290+ }
291+ Log(QString("Read %1 channels.").arg(m_dbox2channelcount));
292+
293+ // Initialize EPG
294+ m_epg->Init(m_dbox2options, m_cardid, this);
295+
296+ // Channel list is ready.
297+ m_channelListReady = true;
298+ // Change channel if request available
299+ if (m_requestChannel != "")
300+ {
301+ SetChannelByString(m_requestChannel);
302+ m_requestChannel = "";
303+ }
304+}
305+
306+void DBox2Channel::RequestChannelChange(QString channelID)
307+{
308+ // Prepare request
309+ QString requestString;
310+ requestString = QString("/control/zapto?%1").arg(channelID);
311+
312+ Log(QString("Changing channel on %1:%2 to channel id %3: %4")
313+ .arg(m_dbox2options->host)
314+ .arg(m_dbox2options->httpport)
315+ .arg(channelID)
316+ .arg(requestString));
317+
318+ // Request channel change via http. Signal will be emmited when request is done.
319+ QHttpRequestHeader header("GET", requestString);
320+ header.setValue("Host", m_dbox2options->host);
321+ httpChanger->setHost(m_dbox2options->host, m_dbox2options->httpport);
322+ httpChanger->request(header);
323+}
324+
325+void DBox2Channel::HttpChannelChangeDone(bool error)
326+{
327+ if (error)
328+ {
329+ Log(QString("Changing channel failed!"));
330+ return;
331+ }
332+
333+ QString buffer=httpChanger->readAll();
334+ QString line = buffer;
335+ if (line == "ok")
336+ {
337+ Log(QString("Changing channel succeeded..."));
338+ // Send signal to record that channel has changed.
339+ ChannelChanged();
340+ // Request EPG for this channel if recorder is not alive
341+ if (!m_recorderAlive)
342+ m_epg->ScheduleRequestEPG(curchannelname);
343+ return;
344+ }
345+
346+ Log(QString("Changing channel failed: %1.").arg(line));
347+ return;
348+}
349+
350+QString DBox2Channel::GetChannelID(const QString& name)
351+{
352+ for (int i = m_dbox2channelcount-1; i >= 0; i--)
353+ if (m_dbox2channelnames[i].upper() == name.upper())
354+ return m_dbox2channelids[i];
355+ return "";
356+}
357+
358+QString DBox2Channel::GetChannelNameFromNumber(const QString& channelnumber)
359+{
360+ MSqlQuery query(MSqlQuery::InitCon());
361+ query.prepare("SELECT name "
362+ "FROM channel,cardinput "
363+ "WHERE "
364+ "channel.sourceid = cardinput.sourceid AND "
365+ "cardinput.cardid = :CARDID AND "
366+ "channel.channum = :CHANNUM");
367+ query.bindValue(":CARDID", m_cardid);
368+ query.bindValue(":CHANNUM", channelnumber);
369+
370+ if (query.exec() && query.isActive() && query.size() > 0)
371+ {
372+ query.next();
373+ return query.value(0).toString();
374+ }
375+ return "";
376+}
377+
378+QString DBox2Channel::GetChannelNumberFromName(const QString& channelName)
379+{
380+ Log(QString("Getting channel number from channel %1.").arg(channelName));
381+
382+ MSqlQuery query(MSqlQuery::InitCon());
383+ query.prepare("SELECT channum "
384+ "FROM channel, cardinput "
385+ "WHERE "
386+ "channel.sourceid = cardinput.sourceid AND "
387+ "cardinput.cardid = :CARDID AND "
388+ "channel.name = :NAME");
389+ query.bindValue(":CARDID", m_cardid);
390+ query.bindValue(":NAME", channelName);
391+
392+ if (query.exec() && query.isActive() && query.size() > 0)
393+ {
394+ query.next();
395+ return query.value(0).toString();
396+ }
397+ Log(QString("Channel number from channel %1 is unknown.").arg(channelName));
398+ return "";
399+}
400+
401+QString DBox2Channel::GetDefaultChannel()
402+{
403+ MSqlQuery query(MSqlQuery::InitCon());
404+ query.prepare("SELECT channum "
405+ "FROM channel,cardinput "
406+ "WHERE "
407+ "channel.sourceid = cardinput.sourceid AND "
408+ "cardinput.cardid = :CARDID "
409+ "ORDER BY channum limit 1");
410+ query.bindValue(":CARDID", m_cardid);
411+
412+ if (query.exec() && query.isActive() && query.size() > 0)
413+ {
414+ query.next();
415+ return query.value(0).toString();
416+ }
417+ return "";
418+}
419+
420+void DBox2Channel::Log(QString string)
421+{
422+ VERBOSE(VB_IMPORTANT,QString("DBOX#%1: %2").arg(m_cardid).arg(string));
423+}
424+
425+void DBox2Channel::RecorderAlive(bool alive)
426+{
427+ if (m_recorderAlive == alive)
428+ return;
429+
430+ m_recorderAlive = alive;
431+ if (m_recorderAlive)
432+ Log("Recorder now online. Deactivating EPG scan");
433+ else
434+ {
435+ Log("Recorder now offline. Reactivating EPG scan");
436+ ScanNextEPG();
437+ }
438+}
439+
440+void DBox2Channel::EPGFinished()
441+{
442+ // Switch to next channel to retrieve EPG
443+ if (m_recorderAlive)
444+ Log("EPG finished. Recorder still online. Deactivating EPG scan");
445+ else
446+ {
447+ Log("EPG finished. Recorder still offline. Continuing EPG scan");
448+ ScanNextEPG();
449+ }
450+}
451+
452+void DBox2Channel::ScanNextEPG()
453+{
454+ SetChannelByDirection(CHANNEL_DIRECTION_UP);
455+}
456diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbox2channel.h mythtv-current-dbox2/libs/libmythtv/dbox2channel.h
457--- mythtv-current/libs/libmythtv/dbox2channel.h 1970-01-01 01:00:00.000000000 +0100
458+++ mythtv-current-dbox2/libs/libmythtv/dbox2channel.h 2005-07-29 18:51:48.000000000 +0200
459@@ -0,0 +1,81 @@
460+/**
461+ * Dbox2Channel
462+ * Copyright (c) 2005 by Levent GÃŒndogdu
463+ * Distributed as part of MythTV under GPL v2 and later.
464+ */
465+
466+
467+#ifndef DBOX2CHANNEL_H
468+#define DBOX2CHANNEL_H
469+
470+#include <qstring.h>
471+#include <stdint.h>
472+#include "tv_rec.h"
473+#include "channelbase.h"
474+#include "sitypes.h"
475+#include "dbox2epg.h"
476+
477+class DBox2EPG;
478+
479+typedef struct dbox2channel
480+{
481+ pthread_mutex_t lock;
482+} dbox2_channel_t;
483+
484+class DBox2Channel : public QObject, public ChannelBase
485+{
486+ Q_OBJECT
487+ public:
488+ DBox2Channel(TVRec *parent, dbox2_options_t *dbox2_options, int cardid);
489+ ~DBox2Channel(void);
490+
491+ bool SetChannelByString(const QString &chan);
492+ bool Open();
493+ bool IsOpen(void) const { return m_recorderAlive; }
494+ void Close();
495+ void SwitchToLastChannel();
496+ void SwitchToInput(const QString &inputname, const QString &chan);
497+ void SwitchToInput(int newcapchannel, bool setstarting)
498+ { (void)newcapchannel; (void)setstarting; }
499+
500+ QString GetChannelNameFromNumber(const QString&);
501+ QString GetChannelNumberFromName(const QString& channelName);
502+ QString GetChannelID(const QString&);
503+
504+ void RecorderAlive(bool);
505+
506+ int GetFd() { return -1; }
507+
508+ signals:
509+ void ChannelChanged();
510+ void ChannelChanging();
511+
512+ public slots:
513+ void HttpChannelChangeDone(bool error);
514+ void HttpRequestDone(bool error);
515+ void EPGFinished();
516+
517+ private:
518+ void Log(QString string);
519+ void LoadChannels();
520+ void RequestChannelChange(QString);
521+ void ScanNextEPG();
522+ QString GetDefaultChannel();
523+ dbox2_options_t *m_dbox2options;
524+ int m_cardid;
525+ bool m_channelListReady;
526+ QString m_lastChannel;
527+ QString m_requestChannel;
528+ DBox2EPG* m_epg;
529+ bool m_recorderAlive;
530+
531+ QHttp *http;
532+ QHttp *httpChanger;
533+
534+ int m_dbox2channelcount;
535+ map<int, QString> m_dbox2channelids;
536+ map<int, QString> m_dbox2channelnames;
537+
538+};
539+
540+#endif
541diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbox2epg.cpp mythtv-current-dbox2/libs/libmythtv/dbox2epg.cpp
542--- mythtv-current/libs/libmythtv/dbox2epg.cpp 1970-01-01 01:00:00.000000000 +0100
543+++ mythtv-current-dbox2/libs/libmythtv/dbox2epg.cpp 2005-07-29 16:06:15.000000000 +0200
544@@ -0,0 +1,247 @@
545+/**
546+ * DBox2EPG
547+ * Copyright (c) 2005 by Levent GÃŒndogdu (mythtv@feature-it.com)
548+ * Distributed as part of MythTV under GPL v2 and later.
549+ */
550+
551+#include <qdatetime.h>
552+#include "dbox2epg.h"
553+#include "mythdbcon.h"
554+
555+#define DEBUG_DBOX2EPG
556+//#define DEBUG_DBOX2EPG_SHOWS
557+//#define DEBUG_DBOX2EPG_PARSER
558+
559+DBox2EPG::DBox2EPG()
560+{
561+ http = new QHttp();
562+ connect (http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpRequestFinished(int,bool)));
563+ m_isRunning = true;
564+ m_dbox2channel = NULL;
565+}
566+
567+DBox2EPG::~DBox2EPG()
568+{
569+ // Abort any pending http operation
570+ http->abort();
571+ http->closeConnection();
572+ // Disconnect from http
573+ disconnect (http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpRequestFinished(int,bool)));
574+ // Delete http
575+ delete http;
576+}
577+
578+void DBox2EPG::Init(dbox2_options_t* dbox2_options, int cardid, DBox2Channel* channel)
579+{
580+ m_dbox2options = dbox2_options;
581+ http->setHost(m_dbox2options->host, m_dbox2options->httpport);
582+ m_dbox2channel = channel;
583+ m_cardid = cardid;
584+#ifdef DEBUG_DBOX2EPG
585+ VERBOSE(VB_IMPORTANT, QString("DBOXEPG#%1: Initing.").arg(m_cardid));
586+#endif
587+ start();
588+}
589+
590+void DBox2EPG::Shutdown()
591+{
592+ m_isRunning = false;
593+}
594+
595+void DBox2EPG::run()
596+{
597+#ifdef DEBUG_DBOX2EPG
598+ VERBOSE(VB_IMPORTANT, QString("DBOXEPG#%1: Starting Thread....").arg(m_cardid));
599+#endif
600+ long waitTime = 15 * 1000 * 1000;
601+
602+ // Process all channel ids and retrieve EPG
603+ while (m_isRunning)
604+ {
605+ usleep(1000);
606+
607+ // If operation is in progress, do not request epg
608+ if (!m_pendingRequest)
609+ continue;
610+
611+ // Wait before processing
612+ usleep(waitTime);
613+
614+ RequestEPG(m_requestedChannel);
615+ m_pendingRequest = false;
616+ }
617+#ifdef DEBUG_DBOX2EPG
618+ VERBOSE(VB_IMPORTANT, QString("DBOXEPG#%1: Exiting Thread....").arg(m_cardid));
619+#endif
620+}
621+
622+
623+void DBox2EPG::ScheduleRequestEPG(const QString& channelNumber)
624+{
625+ m_requestedChannel = channelNumber;
626+ m_pendingRequest = true;
627+}
628+
629+void DBox2EPG::RequestEPG(const QString& channelNumber)
630+{
631+ // Prepare request
632+ QString requestString;
633+ QString channelName = m_dbox2channel->GetChannelNameFromNumber(channelNumber);
634+ QString dbox2ChannelID = m_dbox2channel->GetChannelID(channelName);
635+ requestString = QString("/control/epg?id=%1").arg(dbox2ChannelID);
636+
637+ VERBOSE(VB_IMPORTANT, QString("DBOXEPG#%1: Requesting EPG for channel %2 (%3): %4%5")
638+ .arg(m_cardid)
639+ .arg(channelNumber)
640+ .arg(channelName)
641+ .arg(m_dbox2options->host)
642+ .arg(requestString));
643+
644+ // Request EPG via http. Signal will be emmited when request is done.
645+ QHttpRequestHeader header("GET", requestString);
646+ header.setValue("Host", m_dbox2options->host);
647+ m_currentEPGRequestChannel = channelNumber;
648+ m_currentEPGRequestID = http->request(header);
649+}
650+
651+
652+void DBox2EPG::UpdateDataBase(QString* chanID, QDateTime* startTime, QDateTime* endTime, QString* title, QString *description, QString *category)
653+{
654+ MSqlQuery query(MSqlQuery::InitCon());
655+
656+ // This used to be REPLACE INTO...
657+ // primary key of table program is chanid,starttime
658+ query.prepare("DELETE FROM program"
659+ " WHERE chanid = :CHANID"
660+ " AND starttime = :STARTTIME ;");
661+ query.bindValue(":CHANID", chanID->toInt());
662+ query.bindValue(":STARTTIME", startTime->toString("yyyyMMddhhmmss"));
663+ if (!query.exec())
664+ MythContext::DBError("Saving program",
665+ query);
666+
667+ query.prepare("INSERT INTO program (chanid,starttime,endtime,"
668+ " title,subtitle,description,category,airdate,"
669+ " stars) VALUES (:CHANID,:STARTTIME,:ENDTIME,:TITLE,"
670+ " :SUBTITLE,:DESCRIPTION,:CATEGORY,:AIRDATE,:STARS);");
671+ query.bindValue(":CHANID", chanID->toInt());
672+ query.bindValue(":STARTTIME", startTime->toString("yyyyMMddhhmmss"));
673+ query.bindValue(":ENDTIME", endTime->toString("yyyyMMddhhmmss"));
674+ query.bindValue(":TITLE", title->utf8());
675+ query.bindValue(":SUBTITLE", "");
676+ query.bindValue(":DESCRIPTION", description->utf8());
677+ query.bindValue(":CATEGORY", category->utf8());
678+ query.bindValue(":AIRDATE", "0");
679+ query.bindValue(":STARS", "0");
680+
681+ if (!query.exec())
682+ MythContext::DBError("Saving program",
683+ query);
684+}
685+
686+/**
687+ *
688+ * Reads the results and updates the database accordingly.
689+ * Will be called by the HTTP Object once a request has been finished.
690+ *
691+ */
692+
693+void DBox2EPG::httpRequestFinished(int requestID, bool error)
694+{
695+ if (error)
696+ {
697+ VERBOSE(VB_IMPORTANT, QString("DBOXEPG#%1: Reading EPG failed.").arg(m_cardid));
698+ EPGFinished();
699+ return;
700+ }
701+
702+ if (requestID != m_currentEPGRequestID)
703+ {
704+#ifdef DEBUG_DBOX2EPG
705+ VERBOSE(VB_IMPORTANT, QString("DBOXEPG#%1: Got EPG for old channel. Ignoring").arg(m_cardid));
706+#endif
707+ return;
708+ }
709+
710+ QByteArray buffer=http->readAll();
711+#ifdef DEBUG_DBOX2EPG
712+ VERBOSE(VB_GENERAL,QString("DBOXEPG#%1: EPG received. Parsing %2 bytes...").arg(m_cardid).arg(buffer.size()));
713+#endif
714+
715+ QString channelID = GetChannelID(m_currentEPGRequestChannel);
716+
717+ // Parse
718+ int showCount = 0;
719+ int index = 0;
720+ int size = buffer.size();
721+ while (index < size)
722+ {
723+ // Next section must not start with an empty line
724+ QString line = ParseNextLine(buffer, &index, size);
725+ if (line == "")
726+ continue;
727+ QString epgID = line.section(" ", 0, 0);
728+ QDateTime startTime;
729+ startTime.setTime_t(line.section(" ", 1, 1).toInt());
730+ QDateTime endTime;
731+ endTime = startTime.addSecs(line.section(" ", 2, 2).toInt());
732+ QString title = ParseNextLine(buffer, &index, size);
733+ QString category = ParseNextLine(buffer, &index, size);
734+ QString description = ParseNextLine(buffer, &index, size);
735+ // Update database
736+#ifdef DEBUG_DBOX2EPG_SHOWS
737+ VERBOSE(VB_GENERAL,QString("DBOXEPG#%1: Found show. Start Time: %1, End Time: %2, Title: %3, Description: %4.")
738+ .arg(m_cardid)
739+ .arg(startTime.toString())
740+ .arg(endTime.toString())
741+ .arg(title)
742+ .arg(description));
743+#endif
744+ UpdateDataBase(&channelID, &startTime, &endTime, &title, &description, &category);
745+ showCount++;
746+
747+ // Read until empty line (next empty line indicates end of section).
748+ while (index < size && (line = ParseNextLine(buffer, &index, size)) != "");
749+ }
750+
751+ VERBOSE(VB_GENERAL,QString("DBOXEPG#%1: EPG parsing done. Got %2 shows for channel %3.").arg(m_cardid).arg(showCount).arg(m_currentEPGRequestChannel));
752+ EPGFinished();
753+}
754+
755+QString DBox2EPG::ParseNextLine(QByteArray buffer, int* index, int size)
756+{
757+#ifdef DEBUG_DBOX2EPG_PARSER
758+ VERBOSE(VB_GENERAL,QString("DBOXEPG#%1: Parsing buffer at %2.").arg(m_cardid).arg(*index));
759+#endif
760+ QString string;
761+ while (*index < size)
762+ {
763+ char current = buffer[*index];
764+ *index = *index + 1;
765+ if (current == '\n')
766+ break;
767+ string += current;
768+ }
769+#ifdef DEBUG_DBOX2EPG_PARSER
770+ VERBOSE(VB_GENERAL,QString("DBOXEPG#%1: Returning %2.").arg(m_cardid).arg(string));
771+#endif
772+ return string;
773+}
774+
775+QString DBox2EPG::GetChannelID(const QString& channelnumber)
776+{
777+ MSqlQuery query(MSqlQuery::InitCon());
778+ query.prepare("SELECT chanid "
779+ "FROM channel "
780+ "WHERE "
781+ "channel.channum = :CHANNUM");
782+ query.bindValue(":CHANNUM", channelnumber);
783+
784+ if (query.exec() && query.isActive() && query.size() > 0)
785+ {
786+ query.next();
787+ return query.value(0).toString();
788+ }
789+ return "";
790+}
791+
792diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbox2epg.h mythtv-current-dbox2/libs/libmythtv/dbox2epg.h
793--- mythtv-current/libs/libmythtv/dbox2epg.h 1970-01-01 01:00:00.000000000 +0100
794+++ mythtv-current-dbox2/libs/libmythtv/dbox2epg.h 2005-07-29 16:06:15.000000000 +0200
795@@ -0,0 +1,60 @@
796+/**
797+ * DBox2EPG
798+ * Copyright (c) 2005 by Levent GÃŒndogdu (mythtv@feature-it.com)
799+ * Distributed as part of MythTV under GPL v2 and later.
800+ */
801+
802+#ifndef DBOX2EPG_H_
803+#define DBOX2EPG_H_
804+
805+#include "qhttp.h"
806+#include <qobject.h>
807+#include <qthread.h>
808+#include "mythcontext.h"
809+#include "tv_rec.h"
810+#include "dbox2channel.h"
811+
812+class DBox2Channel;
813+
814+class DBox2EPG : public QObject, public QThread
815+{
816+ Q_OBJECT
817+ public:
818+ DBox2EPG();
819+ ~DBox2EPG();
820+ void Init(dbox2_options_t* dbox2_options, int cardid, DBox2Channel* channel);
821+ void RequestEPG(const QString& channelNumber);
822+ void ScheduleRequestEPG(const QString& channelNumber);
823+ void Shutdown();
824+
825+ public slots:
826+ void httpRequestFinished(int requestID, bool error);
827+
828+ signals:
829+ void EPGFinished();
830+
831+ private:
832+ bool ReadChannels(int cardid);
833+ void UpdateDataBase(QString* chanID, QDateTime* startTime, QDateTime* endTime, QString* title, QString *description, QString *category);
834+ QString DBox2EPG::ParseNextLine(QByteArray buffer, int* index, int size);
835+ QString GetChannelID(const QString& channelnumber) ;
836+ void run();
837+
838+ QHttp* http;
839+ dbox2_options_t* m_dbox2options;
840+ DBox2Channel* m_dbox2channel;
841+ int m_cardid;
842+ int m_channelCount;
843+ int m_channelIndex;
844+ map<int, QString> m_channelnumbers;
845+ bool m_isRunning;
846+ bool m_inProgress;
847+ bool m_pendingRequest;
848+ QString m_requestedChannel;
849+ QString m_currentEPGRequestChannel;
850+ int m_currentEPGRequestID;
851+
852+};
853+
854+
855+#endif
856diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbox2recorder.cpp mythtv-current-dbox2/libs/libmythtv/dbox2recorder.cpp
857--- mythtv-current/libs/libmythtv/dbox2recorder.cpp 1970-01-01 01:00:00.000000000 +0100
858+++ mythtv-current-dbox2/libs/libmythtv/dbox2recorder.cpp 2005-07-29 16:06:15.000000000 +0200
859@@ -0,0 +1,667 @@
860+/**
861+ * Dbox2Recorder
862+ * Copyright (c) 2005 by Levent GÃŒndogdu (mythtv@feature-it.com)
863+ * Distributed as part of MythTV under GPL v2 and later.
864+ */
865+
866+#include <iostream>
867+using namespace std;
868+
869+#include <pthread.h>
870+#include "RingBuffer.h"
871+#include "mythcontext.h"
872+#include "dbox2recorder.h"
873+#include <qhttp.h>
874+#include <qobject.h>
875+#include <sys/select.h>
876+#include <sys/types.h>
877+#include <netdb.h>
878+#include <fcntl.h>
879+
880+#define DEBUG_DBOX2_TS
881+//#define DEBUG_DBOX2_PMT
882+//#define DEBUG_DBOX2_PID
883+
884+int socketConnect(int socket, sockaddr* addr, int len) {
885+ return connect(socket, addr, len);
886+}
887+
888+static const uint32_t crc_table[256] = {
889+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
890+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
891+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
892+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
893+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
894+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
895+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
896+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
897+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
898+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
899+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
900+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
901+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
902+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
903+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
904+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
905+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
906+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
907+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
908+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
909+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
910+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
911+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
912+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
913+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
914+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
915+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
916+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
917+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
918+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
919+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
920+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
921+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
922+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
923+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
924+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
925+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
926+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
927+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
928+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
929+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
930+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
931+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
932+};
933+
934+unsigned int mpegts_crc32(const uint8_t *data, int len)
935+{
936+ register int i;
937+ unsigned int crc = 0xffffffff;
938+
939+ for (i=0; i<len; i++)
940+ crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff];
941+
942+ return crc;
943+}
944+
945+typedef struct ts_packet_{
946+ uint8_t pid[2];
947+ uint8_t flags;
948+ uint8_t count;
949+ uint8_t data[184];
950+ uint8_t adapt_length;
951+ uint8_t adapt_flags;
952+ uint8_t pcr[6];
953+ uint8_t opcr[6];
954+ uint8_t splice_count;
955+ uint8_t priv_dat_len;
956+ uint8_t *priv_dat;
957+ uint8_t adapt_ext_len;
958+ uint8_t adapt_eflags;
959+ uint8_t ltw[2];
960+ uint8_t piece_rate[3];
961+ uint8_t dts[5];
962+ int rest;
963+ uint8_t stuffing;
964+} ts_packet;
965+
966+/**
967+ *
968+ * Constructs a DBox2Recorder
969+ *
970+ */
971+
972+DBox2Recorder::DBox2Recorder(DBox2Channel* channel, int cardid)
973+{
974+ m_cardid = cardid;
975+ m_channel = channel;
976+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Instantiating recorder.").arg(m_cardid));
977+ // Initialize DBOX2 connection relevant members
978+ httpPort = -1;
979+ ip = "";
980+ port = -1;
981+ // Initialize buffers to 1MB
982+ bufferSize = 1024 * 1024;
983+ initStream(&transportStream);
984+ // Status relevant members
985+ isOpen = false;
986+ // Instantiate HTTP
987+ http = new QHttp();
988+ m_lastPIDRequestID = -1;
989+ m_lastInfoRequestID = -1;
990+ // Initialize members for injecting PAT and PMT
991+ m_pidPAT = 0x00;
992+ m_patPacket = new uint8_t[188];
993+ m_pidCount = 0;
994+ pat_cc = 0x00;
995+ m_sectionID = -1;
996+ // Inter-object signalling
997+ connect (http, SIGNAL(requestFinished(int,bool)), this, SLOT(httpRequestFinished(int,bool)));
998+ connect (m_channel, SIGNAL(ChannelChanged()), this, SLOT(ChannelChanged()));
999+ connect (m_channel, SIGNAL(ChannelChanging()), this, SLOT(ChannelChanging()));
1000+ m_channel->RecorderAlive(true);
1001+}
1002+
1003+DBox2Recorder::~DBox2Recorder()
1004+{
1005+ m_channel->RecorderAlive(false);
1006+ // Abort any pending http operation
1007+ http->abort();
1008+ http->closeConnection();
1009+ // Disconnect signals
1010+ disconnect (m_channel, SIGNAL(ChannelChanging()), this, SLOT(ChannelChanging()));
1011+ disconnect (m_channel, SIGNAL(ChannelChanged()), this, SLOT(ChannelChanged()));
1012+ disconnect (http, SIGNAL(requestFinished(int,bool)), this, SLOT(httpRequestFinished(int,bool)));
1013+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Shutting down recorder.").arg(m_cardid));
1014+ Close();
1015+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Freeing buffers...").arg(m_cardid));
1016+ free(transportStream.buffer);
1017+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Done.").arg(m_cardid));
1018+ delete http;
1019+}
1020+
1021+void DBox2Recorder::Close()
1022+{
1023+ if (!isOpen)
1024+ return;
1025+
1026+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Closing all connections...").arg(m_cardid));
1027+ // Close all sockets
1028+ if (transportStream.socket > 0)
1029+ close(transportStream.socket);
1030+ transportStream.socket = -1;
1031+ isOpen = false;
1032+}
1033+
1034+
1035+bool DBox2Recorder::Open()
1036+{
1037+
1038+ if (isOpen)
1039+ Close();
1040+
1041+ m_channel->RecorderAlive(true);
1042+ return RequestStream();
1043+}
1044+
1045+bool DBox2Recorder::RequestStream()
1046+{
1047+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Initializing Host: %2, Streaming-Port: %3, Http-Port: %4")
1048+ .arg(m_cardid)
1049+ .arg(ip)
1050+ .arg(port)
1051+ .arg(httpPort));
1052+
1053+ // Request PIDs via http. Signal will be emmitted when PIDs are ready. Streaming will be activated afterwards
1054+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Retrieving PIDs from %2:%3...").arg(m_cardid).arg(ip).arg(httpPort));
1055+ QHttpRequestHeader header( "GET", "/control/zapto?getallpids" );
1056+ header.setValue("Host", ip);
1057+ http->setHost(ip, httpPort);
1058+ m_lastPIDRequestID = http->request(header);
1059+ return true;
1060+}
1061+
1062+bool DBox2Recorder::RequestInfo()
1063+{
1064+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Requesting stream info on Host: %2, Streaming-Port: %3, Http-Port: %4")
1065+ .arg(m_cardid)
1066+ .arg(ip)
1067+ .arg(port)
1068+ .arg(httpPort));
1069+
1070+ // Request Stream info via http. Signal will be emmitted when Info is ready. PIDS will be retrieved afterwards
1071+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Retrieving Info from %2:%3...").arg(m_cardid).arg(ip).arg(httpPort));
1072+ QHttpRequestHeader header( "GET", "/control/info?streaminfo" );
1073+ header.setValue("Host", ip);
1074+ http->setHost(ip, httpPort);
1075+ m_lastInfoRequestID = http->request(header);
1076+ return true;
1077+}
1078+
1079+int DBox2Recorder::OpenStream()
1080+{
1081+ QString message = QString("DBOX#%1: Opening pids ").arg(m_cardid);
1082+ for (int i = 0; i < m_pidCount; i++)
1083+ {
1084+ message += QString("%1").arg(m_pids[i]);
1085+ message += " (0x" + QString("%1").arg(m_pids[i], 0, 16) + ") ";
1086+ }
1087+
1088+ VERBOSE(VB_GENERAL,message);
1089+
1090+ struct hostent * hp = gethostbyname(ip);
1091+ struct sockaddr_in adr;
1092+ memset ((char *)&adr, 0, sizeof(struct sockaddr_in));
1093+
1094+ adr.sin_family = AF_INET;
1095+ adr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
1096+ port = 31339;
1097+
1098+ adr.sin_port = htons(port);
1099+
1100+ if (adr.sin_addr.s_addr == 0)
1101+ {
1102+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Error opening TS. Unable to look up hostname.").arg(m_cardid));
1103+ return -1;
1104+ }
1105+
1106+ // Open socket
1107+ int newSocket = socket(AF_INET, SOCK_STREAM, 0);
1108+
1109+ if (-1 == socketConnect(newSocket, (sockaddr*)&adr, sizeof(struct sockaddr_in)))
1110+ {
1111+ perror("connect");
1112+ close(newSocket);
1113+ return -1;
1114+ }
1115+
1116+ // Request TS
1117+ QString request = "GET /";
1118+ // Add PIDs
1119+ for (int i = 0; i < m_pidCount; i++) {
1120+ request += QString("%1").arg(m_pids[i], 0, 16);
1121+ if (i+1 < m_pidCount)
1122+ request += ",";
1123+ }
1124+ request += " HTTP/1.0";
1125+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Sending Request '%2'").arg(m_cardid).arg(request));
1126+ request += "\r\n\r\n";
1127+ write(newSocket, request, strlen(request));
1128+ return newSocket;
1129+}
1130+
1131+void DBox2Recorder::StartRecording(void) {
1132+
1133+ struct timeval tv;
1134+
1135+ VERBOSE(VB_RECORD, QString("StartRecording"));
1136+
1137+ if (!Open()) {
1138+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Error starting recording. Aborting.").arg(m_cardid));
1139+ _error = true;
1140+ return;
1141+ }
1142+
1143+ _request_recording = true;
1144+ _recording = true;
1145+ _request_abort = false;
1146+
1147+ lastpacket = time(NULL);
1148+ long lastShown = time(NULL);
1149+
1150+ while(_request_recording)
1151+ {
1152+ if(_request_abort)
1153+ break;
1154+ else if(_request_pause)
1155+ {
1156+ if(!_paused)
1157+ _paused = true;
1158+ pauseWait.wakeAll();
1159+ usleep(2000);
1160+ continue;
1161+ }
1162+ else if(!_request_pause && _paused)
1163+ {
1164+ _paused = false;
1165+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Starting input...").arg(m_cardid));
1166+ lastpacket = time(NULL);
1167+ }
1168+ if (m_lastPIDRequestID >= 0 || m_lastInfoRequestID >= 0)
1169+ {
1170+ if (time(NULL) - lastShown >= 1)
1171+ {
1172+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Waiting for request to finish...").arg(m_cardid));
1173+ lastShown = time(NULL);
1174+ lastpacket = time(NULL);
1175+ }
1176+ usleep(1000);
1177+ }
1178+ else if(time(NULL) - lastpacket > DBOX2_TIMEOUT)
1179+ {
1180+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: No Input in %2 seconds.").arg(m_cardid).arg(DBOX2_TIMEOUT));
1181+ _error = true;
1182+ return;
1183+ }
1184+
1185+ tv.tv_sec = DBOX2_TIMEOUT;
1186+ tv.tv_usec = 0;
1187+
1188+ // Process transport stream data if open
1189+ if (isOpen)
1190+ processStream(&transportStream);
1191+ else
1192+ // Don't process this loop too fast
1193+ usleep(1000);
1194+ }
1195+
1196+ FinishRecording();
1197+ _recording = false;
1198+}
1199+
1200+void DBox2Recorder::SetOptionsFromProfile(RecordingProfile *profile,
1201+ const QString &videodev,
1202+ const QString &audiodev,
1203+ const QString &vbidev, int ispip)
1204+{
1205+ (void)videodev;
1206+ (void)audiodev;
1207+ (void)vbidev;
1208+ (void)profile;
1209+ (void)ispip;
1210+}
1211+
1212+void DBox2Recorder::SetOption(const QString &name, const QString &value)
1213+{
1214+ if(name == "ip") {
1215+ ip = value;
1216+ }
1217+ if(name == "host") {
1218+ ip = value;
1219+ }
1220+}
1221+
1222+void DBox2Recorder::SetOption(const QString &name, int value)
1223+{
1224+ if(name == "port")
1225+ port = value;
1226+ if(name == "httpport")
1227+ httpPort = value;
1228+}
1229+
1230+void DBox2Recorder::httpRequestFinished ( int id, bool error )
1231+{
1232+ if (error) {
1233+ VERBOSE(VB_GENERAL,QString("DBOX#%1: HTTP Request failed!").arg(m_cardid));
1234+ return;
1235+ }
1236+
1237+ QString buffer=http->readAll();
1238+
1239+ if (id == m_lastPIDRequestID)
1240+ {
1241+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Retrieving PIDs succeeded. Parsing...").arg(m_cardid));
1242+ m_pidCount = 0;
1243+ m_pmtPID = -1;
1244+ m_ac3PID = -1;
1245+ for (int i = 0; i < 10; i ++)
1246+ {
1247+ QString pidString = buffer.section("\n", i, i);
1248+ if (pidString != "")
1249+ {
1250+ int pid = pidString.section(" ", 0, 0).toInt();
1251+ if (pid == 0)
1252+ {
1253+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Warning. Got 0 PID!!!.").arg(m_cardid));
1254+ continue;
1255+ }
1256+ m_pids[m_pidCount] = pid;
1257+ QString pidType = pidString.section(" ", 1).upper();
1258+ if (pidType == "PMT")
1259+ {
1260+ m_pmtPID = m_pids[m_pidCount];
1261+#ifdef DEBUG_DBOX2_PMT
1262+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Found PMT with PID %2.").arg(m_cardid).arg(m_pmtPID));
1263+#endif
1264+ }
1265+ else
1266+ if ((pidType.contains("DOLBY DIGITAL") > 0) || (pidType.contains("AC3") > 0))
1267+ {
1268+ m_ac3PID = m_pids[m_pidCount];
1269+#ifdef DEBUG_DBOX2_PMT
1270+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Found AC3 stream with PID %2.").arg(m_cardid).arg(m_ac3PID));
1271+#endif
1272+ }
1273+ m_pidCount++;
1274+#ifdef DEBUG_DBOX2_PID
1275+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Found PID %2.").arg(m_cardid).arg(m_pids[i]));
1276+#endif
1277+ }
1278+ }
1279+
1280+ if (m_pidCount == 0)
1281+ {
1282+ VERBOSE(VB_GENERAL,QString("DBOX#%1: No usable PIDS found. Cannot continue.").arg(m_cardid));
1283+ // Try channel change to last channel
1284+ m_channel->SwitchToLastChannel();
1285+ return;
1286+ }
1287+
1288+ // Open transport stream
1289+ transportStream.bufferIndex = 0;
1290+ transportStream.socket = OpenStream();
1291+ if (transportStream.socket == -1)
1292+ return;
1293+
1294+ // Schedule PAT and PMT creation
1295+ pkts_until_pat = 0;
1296+ m_sectionID = 1;
1297+ CreatePAT(m_patPacket);
1298+ // Set recorder state to open
1299+ isOpen = true;
1300+ m_lastPIDRequestID = -1;
1301+ return;
1302+ }
1303+
1304+ if (id == m_lastInfoRequestID)
1305+ {
1306+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Retrieving info succeeded. Parsing...").arg(m_cardid));
1307+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Got: %2.").arg(m_cardid).arg(buffer));
1308+ m_videoWidth = buffer.section("\n", 0, 0).toInt();
1309+ m_videoHeight = buffer.section("\n", 1, 1).toInt();
1310+ m_videoFormat = buffer.section("\n", 3, 3);
1311+ VERBOSE(VB_GENERAL,QString("DBOX#%1: Video is %2x%3 (Format %4).").arg(m_cardid).arg(m_videoWidth).arg(m_videoHeight).arg(m_videoFormat));
1312+ m_lastInfoRequestID = -1;
1313+ RequestStream();
1314+ }
1315+
1316+}
1317+
1318+/*
1319+ *
1320+ */
1321+
1322+void DBox2Recorder::initStream(stream_meta* stream) {
1323+ stream->socket = -1;
1324+ stream->buffer = (uint8_t*) malloc(bufferSize);
1325+ stream->bufferIndex = 0;
1326+}
1327+
1328+/*
1329+ *
1330+ */
1331+
1332+int DBox2Recorder::processStream(stream_meta* stream)
1333+{
1334+ // Read and parse
1335+ int bytesRead = read(stream->socket, stream->buffer + stream->bufferIndex, bufferSize - stream->bufferIndex);
1336+ if (bytesRead <= 0) {
1337+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Error reading data.").arg(m_cardid));
1338+ return 0;
1339+ }
1340+
1341+ stream->bufferIndex += bytesRead;
1342+
1343+ int readIndex = 0;
1344+ while (readIndex < stream->bufferIndex)
1345+ {
1346+ // Try to find next TS
1347+ int tsPos = findTSHeader(stream->buffer + readIndex, stream->bufferIndex);
1348+ if (tsPos == -1)
1349+ {
1350+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: No TS header.").arg(m_cardid));
1351+ break;
1352+ }
1353+
1354+ if (tsPos > 0)
1355+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: TS header at %2, not in sync.").arg(m_cardid).arg(tsPos));
1356+
1357+ // Check if enough data is available to process complete TS packet.
1358+ if ((stream->bufferIndex - readIndex - tsPos) < 188) {
1359+ // VERBOSE(VB_IMPORTANT, QString("DBOX#%1: TS header at %2 but packet not yet complete.").arg(m_cardid).arg(tsPos));
1360+ break;
1361+ }
1362+
1363+ updatePMTSectionID(stream->buffer+readIndex+tsPos, m_pmtPID);
1364+
1365+ // Inject PAT every 2000 TS packets.
1366+ if (pkts_until_pat == 0)
1367+ {
1368+ ringBuffer->Write(m_patPacket, 188);
1369+ pkts_until_pat = 2000;
1370+ }
1371+ else
1372+ pkts_until_pat--;
1373+
1374+ tpkt.InitHeader(stream->buffer+readIndex+tsPos);
1375+ tpkt.InitPayload(stream->buffer+readIndex+tsPos+4);
1376+ FindKeyframes(&tpkt);
1377+
1378+ ringBuffer->Write(stream->buffer+readIndex+tsPos, 188);
1379+ lastpacket = time(NULL);
1380+ readIndex += tsPos + 188;
1381+ }
1382+
1383+ memcpy(stream->buffer, stream->buffer + readIndex, bufferSize - readIndex);
1384+ stream->bufferIndex = stream->bufferIndex - readIndex;
1385+
1386+ if (stream->bufferIndex < 0)
1387+ {
1388+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: WARNING! Buffer index is %2. Resetting.").arg(m_cardid).arg(stream->bufferIndex));
1389+ stream->bufferIndex = 0;
1390+ }
1391+
1392+ return 0;
1393+}
1394+
1395+void DBox2Recorder::CreatePAT(uint8_t *ts_packet)
1396+{
1397+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Creating PAT for PMT pid %2.").arg(m_cardid).arg(m_pmtPID));
1398+
1399+ memset(ts_packet, 0xFF, 188);
1400+
1401+ ts_packet[0] = 0x47; // sync byte
1402+ ts_packet[1] = 0x40 | ((m_pidPAT >> 8) & 0x1F); // payload start & PID
1403+ ts_packet[2] = m_pidPAT & 0xFF; // PID
1404+ ts_packet[3] = 0x10 | pat_cc; // scrambling, adaptation & continuity counter
1405+ ts_packet[4] = 0x00; // pointer field
1406+
1407+ ++pat_cc &= 0x0F; // inc. continuity counter
1408+ uint8_t *pat = ts_packet + 5;
1409+ int p = 0;
1410+
1411+ pat[p++] = PAT_TID; // table ID
1412+ pat[p++] = 0xB0; // section syntax indicator
1413+ p++; // section length (set later)
1414+ pat[p++] = 0; // TSID
1415+ pat[p++] = 1; // TSID
1416+ pat[p++] = 0xC3; // Version + Current/Next
1417+ pat[p++] = 0; // Current Section
1418+ pat[p++] = 0; // Last Section
1419+ pat[p++] = (m_sectionID >> 8) & 0xFF;
1420+ pat[p++] = m_sectionID & 0xFF;
1421+ pat[p++] = (m_pmtPID >> 8) & 0x1F;
1422+ pat[p++] = m_pmtPID & 0xFF;
1423+
1424+ pat[2] = p + 4 - 3; // section length
1425+
1426+ unsigned int crc = mpegts_crc32(pat, p);
1427+ pat[p++] = (crc >> 24) & 0xFF;
1428+ pat[p++] = (crc >> 16) & 0xFF;
1429+ pat[p++] = (crc >> 8) & 0xFF;
1430+ pat[p++] = crc & 0xFF;
1431+}
1432+
1433+void DBox2Recorder::ChannelChanged()
1434+{
1435+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Channel changed. Requesting streams...").arg(m_cardid));
1436+ Open();
1437+}
1438+
1439+void DBox2Recorder::ChannelChanging()
1440+{
1441+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Channel changing. Closing current stream...").arg(m_cardid));
1442+ Close();
1443+}
1444+
1445+int DBox2Recorder::findTSHeader(uint8_t* buffer, int len)
1446+{
1447+ int pos = 0;
1448+ while (pos < len)
1449+ {
1450+ if (buffer[pos] == 0x47)
1451+ return pos;
1452+ pos++;
1453+ }
1454+ return -1;
1455+}
1456+
1457+int DBox2Recorder::getPMTSectionID(uint8_t* buffer, int pmtPID)
1458+{
1459+ int tempPID = ((buffer[1] & 0x1F) << 8) | (buffer[2] & 0xFF);
1460+ if (tempPID != pmtPID)
1461+ return -1;
1462+
1463+#ifdef DEBUG_DBOX2_PMT
1464+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Found PMT packet with PID %2.").arg(m_cardid).arg(tempPID));
1465+#endif
1466+ return (buffer[8] & 0xFF << 8) | (buffer[9] & 0xFF);
1467+}
1468+
1469+void DBox2Recorder::updatePMTSectionID(uint8_t* buffer, int pmtPID)
1470+{
1471+ int sectionID = getPMTSectionID(buffer, pmtPID);
1472+ if (sectionID == -1)
1473+ return;
1474+
1475+#ifdef DEBUG_DBOX2_PMT
1476+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Found PMT packet with PID %2 and section id %3. Updating...").arg(m_cardid).arg(pmtPID).arg(sectionID));
1477+#endif
1478+
1479+ uint8_t *pmt = buffer + 5;
1480+ // Set service ID to match PAT
1481+ pmt[3] = 0; // program number (ServiceID)
1482+ pmt[4] = 1; // program number (ServiceID)
1483+ if (m_ac3PID != -1)
1484+ {
1485+#ifdef DEBUG_DBOX2_PMT
1486+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Looking for AC3 PID in PMT packet...").arg(m_cardid));
1487+#endif
1488+ // AC3 PID is given, change the stream type
1489+ uint8_t p = 10;
1490+ // Advance by program info length + 2
1491+ p += (((pmt[p] & 0x0F) << 8) | (pmt[p+1] & 0xFF)) + 2;
1492+ for (int i = 0; i < m_pidCount; i++)
1493+ {
1494+ // Step over stream type
1495+ p++;
1496+ // Get pid
1497+ int pid = (pmt[p] & 0x0F) << 8;
1498+ pid = pid | (pmt[p+1] & 0xFF);
1499+#ifdef DEBUG_DBOX2_PMT
1500+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Looking for AC3 PID in PMT packet (Pid #%2 == %3)").arg(m_cardid).arg(i).arg(pid));
1501+#endif
1502+ if (pid == m_ac3PID)
1503+ {
1504+#ifdef DEBUG_DBOX2_PMT
1505+ VERBOSE(VB_IMPORTANT, QString("DBOX#%1: Found AC3 PID in PMT packet. Updating Stream Type...").arg(m_cardid));
1506+#endif
1507+ pmt[p-1] = STREAM_TYPE_AUDIO_AC3;
1508+ break;
1509+ }
1510+ // Advance by pid
1511+ p += 2;
1512+ // Advance by es info length + 2
1513+ p += ((pmt[p] & 0x0F) << 8) | (pmt[p+1] & 0xFF) + 2;
1514+ }
1515+ }
1516+ int len = pmt[2];
1517+ int crcOffset = len + 3 - 4;
1518+ // Recalculate CRC
1519+ unsigned long crc = mpegts_crc32(pmt, crcOffset);
1520+ pmt[crcOffset] = (crc >> 24) & 0xFF;
1521+ pmt[crcOffset+1] = (crc >> 16) & 0xFF;
1522+ pmt[crcOffset+2] = (crc >> 8) & 0xFF;
1523+ pmt[crcOffset+3] = crc & 0xFF;
1524+}
1525+
1526+
1527diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/dbox2recorder.h mythtv-current-dbox2/libs/libmythtv/dbox2recorder.h
1528--- mythtv-current/libs/libmythtv/dbox2recorder.h 1970-01-01 01:00:00.000000000 +0100
1529+++ mythtv-current-dbox2/libs/libmythtv/dbox2recorder.h 2005-07-29 16:06:15.000000000 +0200
1530@@ -0,0 +1,107 @@
1531+/**
1532+ * DBOX2Recorder
1533+ * Copyright (c) 2005 by Levent GÃŒndogdu
1534+ * Distributed as part of MythTV under GPL v2 and later.
1535+ */
1536+
1537+#ifndef DBOX2RECORDER_H_
1538+#define DBOX2RECORDER_H_
1539+
1540+#include "dtvrecorder.h"
1541+#include <time.h>
1542+#include "dbox2channel.h"
1543+#include "sitypes.h"
1544+#include "qhttp.h"
1545+#include "mpeg/tspacket.h"
1546+
1547+#define DBOX2_TIMEOUT 15
1548+#define PAT_TID 0x00
1549+#define PMT_TID 0x02
1550+#define STREAM_TYPE_VIDEO_MPEG1 0x01
1551+#define STREAM_TYPE_VIDEO_MPEG2 0x02
1552+#define STREAM_TYPE_AUDIO_MPEG1 0x03
1553+#define STREAM_TYPE_AUDIO_MPEG2 0x04
1554+#define STREAM_TYPE_PRIVATE_SECTION 0x05
1555+#define STREAM_TYPE_PRIVATE_DATA 0x06
1556+#define STREAM_TYPE_AUDIO_AAC 0x0f
1557+#define STREAM_TYPE_VIDEO_MPEG4 0x10
1558+#define STREAM_TYPE_VIDEO_H264 0x1b
1559+
1560+#define STREAM_TYPE_AUDIO_AC3 0x81
1561+#define STREAM_TYPE_AUDIO_DTS 0x8a
1562+
1563+typedef struct stream_meta_{
1564+ int socket;
1565+ uint8_t* buffer;
1566+ int bufferIndex;
1567+} stream_meta;
1568+
1569+
1570+class DBox2Recorder : public DTVRecorder
1571+{
1572+ Q_OBJECT
1573+ public:
1574+
1575+ DBox2Recorder(DBox2Channel *channel, int cardid);
1576+ ~DBox2Recorder();
1577+
1578+ void StartRecording(void);
1579+ bool Open(void);
1580+ void ProcessTSPacket(unsigned char *tspacket, int len);
1581+ void SetOptionsFromProfile(RecordingProfile *profile,
1582+ const QString &videodev,
1583+ const QString &audiodev,
1584+ const QString &vbidev, int ispip);
1585+
1586+ void SetOption(const QString &name, const QString &value);
1587+ void SetOption(const QString &name, int value);
1588+
1589+ public slots:
1590+ void httpRequestFinished ( int id, bool error );
1591+ void ChannelChanged();
1592+ void ChannelChanging();
1593+
1594+ private:
1595+ // Methods
1596+ void ChannelChanged(dbox2_channel_t& chan);
1597+ void CreatePAT(uint8_t *ts_packet);
1598+ int getPMTSectionID(uint8_t* buffer, int pmtPID);
1599+ void updatePMTSectionID(uint8_t* buffer, int pmtPID);
1600+ int processStream(stream_meta* stream);
1601+ void initStream(stream_meta* meta);
1602+ int OpenStream();
1603+ bool RequestStream();
1604+ bool RequestInfo();
1605+ int findTSHeader(uint8_t* buffer, int len);
1606+ void Close();
1607+ // Members for creating/handling PAT and PMT
1608+ int m_cardid;
1609+ uint8_t *m_patPacket;
1610+ int pat_cc;
1611+ int pkts_until_pat;
1612+ int m_pidPAT;
1613+ int m_pids[10];
1614+ int m_pidCount;
1615+ int m_pmtPID;
1616+ int m_ac3PID;
1617+ int m_sectionID;
1618+ DBox2Channel *m_channel;
1619+ // Connection relevant members
1620+ int port;
1621+ int httpPort;
1622+ QString ip;
1623+ bool isOpen;
1624+ QHttp* http;
1625+ int m_lastPIDRequestID;
1626+ int m_lastInfoRequestID;
1627+ time_t lastpacket;
1628+ int bufferSize;
1629+ stream_meta transportStream;
1630+ TSPacket tpkt;
1631+ int m_videoWidth;
1632+ int m_videoHeight;
1633+ QString m_videoFormat;
1634+ bool _request_abort;
1635+};
1636+
1637+#endif
1638diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/libmythtv.pro mythtv-current-dbox2/libs/libmythtv/libmythtv.pro
1639--- mythtv-current/libs/libmythtv/libmythtv.pro 2005-08-02 20:05:18.000000000 +0200
1640+++ mythtv-current-dbox2/libs/libmythtv/libmythtv.pro 2005-08-02 15:54:32.000000000 +0200
1641@@ -241,6 +241,10 @@
1642 using_firewire:SOURCES += firewirerecorder.cpp firewirechannel.cpp
1643 using_firewire:DEFINES += USING_FIREWIRE
1644
1645+ # Support for set top boxes (Nokia DBox2 etc.)
1646+ using_dbox2:SOURCES += dbox2recorder.cpp dbox2channel.cpp dbox2epg.cpp
1647+ using_dbox2:HEADERS += dbox2recorder.h dbox2channel.h dbox2epg.h
1648+
1649 # Support for PVR-150/250/350/500, etc. on Linux
1650 using_ivtv:HEADERS += mpegrecorder.h
1651 using_ivtv:SOURCES += mpegrecorder.cpp
1652diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/siparser.h mythtv-current-dbox2/libs/libmythtv/siparser.h
1653--- mythtv-current/libs/libmythtv/siparser.h 2005-07-29 16:05:54.000000000 +0200
1654+++ mythtv-current-dbox2/libs/libmythtv/siparser.h 2005-07-29 16:06:15.000000000 +0200
1655@@ -75,7 +75,7 @@
1656 * Argentenia has also has announced their Digital TV Standard will be
1657 * ATSC over DVB-T
1658 *
1659- * Impliemntation of OpenCable or other MPEG-TS based standards (DirecTV?)
1660+ * Implementation of OpenCable or other MPEG-TS based standards (DirecTV?)
1661 * is also possible with this class if their specs are ever known.
1662 *
1663 */
1664diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/tv_rec.cpp mythtv-current-dbox2/libs/libmythtv/tv_rec.cpp
1665--- mythtv-current/libs/libmythtv/tv_rec.cpp 2005-08-02 20:05:19.000000000 +0200
1666+++ mythtv-current-dbox2/libs/libmythtv/tv_rec.cpp 2005-08-02 15:54:32.000000000 +0200
1667@@ -53,6 +53,11 @@
1668 #include "firewirechannel.h"
1669 #endif
1670
1671+#ifdef USING_DBOX2
1672+#include "dbox2recorder.h"
1673+#include "dbox2channel.h"
1674+#endif
1675+
1676 const int TVRec::kRequestBufferSize = 256*1000;
1677
1678 /** \class TVRec
1679@@ -128,7 +133,7 @@
1680 GetDevices(m_capturecardnum, videodev, vbidev,
1681 audiodev, audiosamplerate,
1682 inputname, startchannel, cardtype, dvb_options,
1683- firewire_options, skip_btaudio);
1684+ firewire_options, dbox2_options, skip_btaudio);
1685
1686 if (cardtype == "DVB")
1687 {
1688@@ -173,6 +178,23 @@
1689 return false;
1690 #endif
1691 }
1692+ else if (cardtype == "DBOX2")
1693+ {
1694+#ifdef USING_DBOX2
1695+ channel = new DBox2Channel(this, &dbox2_options, m_capturecardnum);
1696+ channel->Open();
1697+ if (inputname.isEmpty())
1698+ channel->SetChannelByString(startchannel);
1699+ else
1700+ channel->SwitchToInput(inputname, startchannel);
1701+#else
1702+ VERBOSE(VB_IMPORTANT, "ERROR: DBOX2 Input configured, "
1703+ "but no DBOX2 support compiled in!");
1704+ VERBOSE(VB_IMPORTANT, "Remove the card from configuration, "
1705+ "or recompile MythTV.");
1706+ exit(-20);
1707+#endif
1708+ }
1709 else if ((cardtype == "MPEG") && (videodev.lower().left(5) == "file:"))
1710 {
1711 // No need to initialize channel..
1712@@ -834,6 +856,23 @@
1713 errored = true;
1714 #endif
1715 }
1716+ else if (cardtype == "DBOX2")
1717+ {
1718+#ifdef USING_DBOX2
1719+ VERBOSE(VB_GENERAL,QString("TVRec::SetupRecorder() Initializing DBOX2 on Host: %1, Streaming-Port: %2, Http-Port: %3")
1720+ .arg(dbox2_options.host)
1721+ .arg(dbox2_options.port)
1722+ .arg(dbox2_options.httpport));
1723+ recorder = new DBox2Recorder(dynamic_cast<DBox2Channel*>(channel), m_capturecardnum);
1724+ recorder->SetRingBuffer(rbuffer);
1725+ recorder->SetOptionsFromProfile(&profile, videodev, audiodev, vbidev, ispip);
1726+ recorder->SetOption("port", dbox2_options.port);
1727+ recorder->SetOption("host", dbox2_options.host);
1728+ recorder->SetOption("httpport", dbox2_options.httpport);
1729+ recorder->Initialize();
1730+#endif
1731+ return;
1732+ }
1733 else if (cardtype == "DVB")
1734 {
1735 #ifdef USING_DVB
1736@@ -1307,7 +1346,7 @@
1737 void TVRec::GetDevices(int cardnum, QString &video, QString &vbi,
1738 QString &audio, int &rate, QString &defaultinput,
1739 QString &startchan, QString &type,
1740- dvb_options_t &dvb_opts, firewire_options_t &firewire_opts,
1741+ dvb_options_t &dvb_opts, firewire_options_t &firewire_opts, dbox2_options_t &dbox2_opts,
1742 bool &skip_bt)
1743 {
1744 video = "";
1745@@ -1328,7 +1367,7 @@
1746 "dvb_wait_for_seqstart,dvb_dmx_buf_size,"
1747 "dvb_pkt_buf_size, skipbtaudio, dvb_on_demand,"
1748 "firewire_port, firewire_node, firewire_speed,"
1749- "firewire_model, firewire_connection "
1750+ "firewire_model, firewire_connection, dbox2_port, dbox2_host, dbox2_httpport "
1751 "FROM capturecard WHERE cardid = :CARDID ;");
1752 query.bindValue(":CARDID", cardnum);
1753
1754@@ -1377,6 +1416,13 @@
1755 if (test != QString::null)
1756 firewire_opts.model = QString::fromUtf8(test);
1757 firewire_opts.connection = query.value(17).toInt();
1758+
1759+ dbox2_opts.port = query.value(18).toInt();
1760+ dbox2_opts.httpport = query.value(20).toInt();
1761+ test = query.value(19).toString();
1762+ if (test != QString::null)
1763+ dbox2_opts.host = QString::fromUtf8(test);
1764+
1765 }
1766
1767 query.prepare("SELECT if(startchan!='', startchan, '3') "
1768diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/tv_rec.h mythtv-current-dbox2/libs/libmythtv/tv_rec.h
1769--- mythtv-current/libs/libmythtv/tv_rec.h 2005-07-29 16:05:54.000000000 +0200
1770+++ mythtv-current-dbox2/libs/libmythtv/tv_rec.h 2005-07-29 16:06:15.000000000 +0200
1771@@ -51,6 +51,13 @@
1772 QString model;
1773 } firewire_options_t;
1774
1775+typedef struct _dbox2_options_t
1776+{
1777+ int port;
1778+ int httpport;
1779+ QString host;
1780+} dbox2_options_t;
1781+
1782 class TVRec
1783 {
1784 public:
1785@@ -188,7 +195,8 @@
1786 void GetDevices(int cardnum, QString &video, QString &vbi, QString &audio,
1787 int &rate, QString &defaultinput, QString &startchannel,
1788 QString &type, dvb_options_t &dvb_opts,
1789- firewire_options_t &firewire_opts, bool &skip_bt);
1790+ firewire_options_t &firewire_opts, dbox2_options_t &dbox2_opts,
1791+ bool &skip_bt);
1792
1793 void SetupRecorder(class RecordingProfile& profile);
1794 void TeardownRecorder(bool killFile = false);
1795@@ -240,11 +248,12 @@
1796 QString liveTVRingBufLoc;
1797 QString recprefix;
1798
1799- // Configuration variables from setup rutines
1800+ // Configuration variables from setup routines
1801 int m_capturecardnum;
1802 bool ispip;
1803 dvb_options_t dvb_options;
1804 firewire_options_t firewire_options;
1805+ dbox2_options_t dbox2_options;
1806
1807 // State variables
1808 QMutex stateChangeLock;
1809diff -Nurb --exclude=CVS --exclude=.svn --exclude=doconfigure.sh --exclude=config.h --exclude=config.log --exclude=config.mak --exclude=Makefile --exclude=mpegts.c --exclude=settings.pro --exclude=mythtv.pro --exclude=mythconfig.h --exclude=mythconfig.mak --exclude=nohup.out --exclude='*.orig' --exclude='*.rej' --exclude='.#*' --exclude='*~' --exclude='moc_*.cpp' --exclude='*.o' --exclude='*.so' --exclude='*.so.*' --exclude='*.a' mythtv-current/libs/libmythtv/videosource.cpp mythtv-current-dbox2/libs/libmythtv/videosource.cpp
1810--- mythtv-current/libs/libmythtv/videosource.cpp 2005-07-29 16:05:53.000000000 +0200
1811+++ mythtv-current-dbox2/libs/libmythtv/videosource.cpp 2005-07-29 19:30:40.000000000 +0200
1812@@ -1188,6 +1188,51 @@
1813 CaptureCard& parent;
1814 };
1815
1816+class DBOX2Port: public LineEditSetting, public CCSetting {
1817+ public:
1818+ DBOX2Port(const CaptureCard& parent):
1819+ CCSetting(parent, "dbox2_port") {
1820+ setValue("31338");
1821+ setLabel(QObject::tr("DBOX2 Streaming Port"));
1822+ setHelpText(QObject::tr("DBOX2 streaming port on your DBOX2."));
1823+ }
1824+};
1825+
1826+class DBOX2HttpPort: public LineEditSetting, public CCSetting {
1827+ public:
1828+ DBOX2HttpPort(const CaptureCard& parent):
1829+ CCSetting(parent, "dbox2_httpport") {
1830+ setValue("80");
1831+ setLabel(QObject::tr("DBOX2 HTTP Port"));
1832+ setHelpText(QObject::tr("DBOX2 http port on your DBOX2."));
1833+ }
1834+};
1835+class DBOX2Host: public LineEditSetting, public CCSetting {
1836+ public:
1837+ DBOX2Host(const CaptureCard& parent):
1838+ CCSetting(parent, "dbox2_host") {
1839+ setValue("dbox");
1840+ setLabel(QObject::tr("DBOX2 Host IP"));
1841+ setHelpText(QObject::tr("DBOX2 Host IP is the remote device."));
1842+ }
1843+};
1844+
1845+class DBOX2ConfigurationGroup: public VerticalConfigurationGroup {
1846+public:
1847+ DBOX2ConfigurationGroup(CaptureCard& a_parent):
1848+ parent(a_parent) {
1849+ setUseLabel(false);
1850+ addChild(new DBOX2Port(parent));
1851+ addChild(new DBOX2HttpPort(parent));
1852+ addChild(new DBOX2Host(parent));
1853+ };
1854+ private:
1855+ CaptureCard& parent;
1856+ };
1857+
1858+
1859+
1860+
1861 class V4LConfigurationGroup: public VerticalConfigurationGroup
1862 {
1863 public:
1864@@ -1273,6 +1318,7 @@
1865 addTarget("HDTV", new pcHDTVConfigurationGroup(parent));
1866 addTarget("MPEG", new MPEGConfigurationGroup(parent));
1867 addTarget("FIREWIRE", new FirewireConfigurationGroup(parent));
1868+ addTarget("DBOX2", new DBOX2ConfigurationGroup(parent));
1869 }
1870
1871 void CaptureCardGroup::triggerChanged(const QString& value)
1872@@ -1296,7 +1342,7 @@
1873 {
1874 MSqlQuery query(MSqlQuery::InitCon());
1875 query.prepare("SELECT cardtype, videodevice, cardid, "
1876- " firewire_port, firewire_node "
1877+ " firewire_port, firewire_node, dbox2_port, dbox2_host, dbox2_httpport "
1878 " FROM capturecard WHERE hostname = :HOSTNAME ;");
1879 query.bindValue(":HOSTNAME", gContext->GetHostName());
1880
1881@@ -1313,6 +1359,13 @@
1882 query.value(4).toString() + "]",
1883 query.value(2).toString());
1884 }
1885+ else if(query.value(0).toString() == "DBOX2") {
1886+ setting->addSelection("[ " + query.value(0).toString() + " " +
1887+ "Host IP: " + query.value(6).toString() + ", " +
1888+ "Streaming-Port: " + query.value(5).toString() + ", " +
1889+ "Http-Port: " + query.value(7).toString() +
1890+ "] ", query.value(2).toString());
1891+ }
1892 else
1893 {
1894 setting->addSelection(
1895@@ -1353,6 +1406,7 @@
1896 setting->addSelection(QObject::tr("FireWire Input"),
1897 "FIREWIRE");
1898 setting->addSelection(QObject::tr("USB Mpeg-4 Encoder (Plextor ConvertX, etc)"), "GO7007");
1899+ setting->addSelection(QObject::tr("DBOX2 Input"), "DBOX2");
1900 }
1901
1902 class CardID: public SelectLabelSetting, public CISetting {
1903@@ -1903,7 +1957,7 @@
1904 MSqlQuery capturecards(MSqlQuery::InitCon());
1905
1906 capturecards.prepare("SELECT cardid, videodevice, cardtype, "
1907- " dvb_diseqc_type, firewire_port, firewire_node "
1908+ " dvb_diseqc_type, firewire_port, firewire_node, dbox2_port, dbox2_host, dbox2_httpport "
1909 "FROM capturecard "
1910 "WHERE hostname = :HOSTNAME");
1911 capturecards.bindValue(":HOSTNAME", gContext->GetHostName());
1912@@ -1962,6 +2016,29 @@
1913 addSelection(label, index);
1914 }
1915 }
1916+ else if(capturecards.value(2).toString() == "DBOX2")
1917+ {
1918+ inputs = QStringList("MPEG2TS");
1919+ for (QStringList::iterator i = inputs.begin();
1920+ i != inputs.end(); ++i)
1921+ {
1922+ CardInput* cardinput = new CardInput();
1923+ cardinput->loadByInput(cardid, *i);
1924+ cardinputs.push_back(cardinput);
1925+ QString index = QString::number(cardinputs.size()-1);
1926+
1927+ QString label;
1928+ label = QString("%1 (%2) -> %3")
1929+ .arg("[ " + capturecards.value(2).toString() +
1930+ "IP: " + capturecards.value(7).toString() +
1931+ ", Port: " + capturecards.value(6).toString() +
1932+ ", HttpPort: " + capturecards.value(8).toString() +
1933+ " ]")
1934+ .arg(*i)
1935+ .arg(cardinput->getSourceName());
1936+ addSelection(label, index);
1937+ }
1938+ }
1939 else
1940 {
1941 inputs = VideoDevice::probeInputs(videodevice);