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

File mythtv-dbox2-200508022011.patch.text, 68.7 KB (added by mythtv@…, 19 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);