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); |
---|