1 | diff -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
|
---|
43 | diff -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 -->
|
---|
84 | diff -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 |
|
---|
117 | diff -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 | +}
|
---|
456 | diff -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
|
---|
541 | diff -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 | +
|
---|
792 | diff -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
|
---|
856 | diff -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 | +
|
---|
1527 | diff -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
|
---|
1638 | diff -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
|
---|
1652 | diff -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 | */
|
---|
1664 | diff -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') "
|
---|
1768 | diff -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;
|
---|
1809 | diff -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);
|
---|