Ticket #1704: patch-freebox

File patch-freebox, 38.9 KB (added by mythtv@…, 20 years ago)

FreeBox support patch

Line 
1diff -u -r -N mythtv-SVN.orig/configure mythtv-SVN/configure
2--- mythtv-SVN.orig/configure 2006-04-18 09:06:57.000000000 +0200
3+++ mythtv-SVN/configure 2006-04-18 09:08:41.000000000 +0200
4@@ -54,6 +54,7 @@
5 lirc="yes"
6 joystick_menu="yes"
7 firewire_cable_box="yes"
8+freebox_box="no"
9 dbox2_dvb_box="yes"
10 hdhomerun_box="yes"
11 x11_include_path="/usr/X11R6/include"
12@@ -173,6 +174,9 @@
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 " --enable-freebox enable support for Freebox"
17+echo " --livelibdir=DIR location of Live streaming library"
18+echo " --liveincludedir=DIR location of Live streaming include files"
19 echo " --disable-dbox2 disable support for Nokia DBOX2 DVB boxes (or compatibles)"
20 echo " --disable-hdhomerun disable support for HDHomeRun boxes"
21 echo " --disable-v4l disable Video4Linux support"
22@@ -810,6 +814,14 @@
23 ;;
24 --disable-dbox2) dbox2_dvb_box="no"
25 ;;
26+ --enable-freebox) freebox_box="yes"
27+ ;;
28+ --disable-freebox) freebox_box="no"
29+ ;;
30+ --livelibdir=*) live_lib_dir=`echo $opt | cut -d '=' -f 2`
31+ ;;
32+ --liveincludedir=*) live_include_dir=`echo $opt | cut -d '=' -f 2`
33+ ;;
34 --enable-hdhomerun) hdhomerun_box="yes"
35 ;;
36 --disable-hdhomerun) hdhomerun_box="no"
37@@ -2243,6 +2255,7 @@
38 echo "FireWire support $firewire_cable_box"
39 echo "DVB support $dvb [$dvb_path]"
40 echo "DBox2 support $dbox2_dvb_box"
41+ echo "freebox support $freebox_box"
42 echo "HDHomeRun sup. $hdhomerun_box"
43 fi
44
45@@ -2885,6 +2898,46 @@
46 CCONFIG="$CCONFIG using_dbox2"
47 fi
48
49+if test x"$freebox_box" = x"yes" ; then
50+ if test "x$live_lib_dir" = "x"; then
51+ if has_library libliveMedia; then
52+ CONFIG_LIVE_LIBS="-lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment"
53+ else
54+ echo "Unable to find Live Media library."
55+ exit 1;
56+ fi
57+ else
58+ if test ! -f "$live_lib_dir/liveMedia/libliveMedia.a"; then
59+ echo "Unable to find Live Media library."
60+ exit 1;
61+ fi
62+ CONFIG_LIVE_LIBS="-L$live_lib_dir/liveMedia -L$live_lib_dir/UsageEnvironment -L$live_lib_dir/BasicUsageEnvironment -L$live_lib_dir/groupsock -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment"
63+ fi
64+ if test "x$live_include_dir" = "x"; then
65+ if has_header liveMedia.hh; then
66+ true
67+ else
68+ echo "Unable to find Live Media headers."
69+ exit 1;
70+ fi
71+ else
72+ if test -f "$live_include_dir/liveMedia/include/liveMedia.hh"; then
73+ LIVE_INCLUDES="$live_include_dir/liveMedia/include $live_include_dir/UsageEnvironment/include $live_include_dir/BasicUsageEnvironment/include $live_include_dir/groupsock/include"
74+ else
75+ if test -f "$live_include_dir/liveMedia/liveMedia.hh"; then
76+ LIVE_INCLUDES="$live_include_dir/liveMedia $live_include_dir/UsageEnvironment $live_include_dir/BasicUsageEnvironment $live_include_dir/groupsock"
77+ else
78+ echo "Unable to find Live Media headers."
79+ exit 1;
80+ fi
81+ fi
82+ fi
83+ CCONFIG="$CCONFIG using_freebox"
84+ CONFIG_DEFINES="$CONFIG_DEFINES USING_FREEBOX"
85+ echo "CONFIG_LIVE_LIBS=$CONFIG_LIVE_LIBS" >> $MYTH_CONFIG_MAK
86+ CONFIG_INCLUDEPATH="$CONFIG_INCLUDEPATH $LIVE_INCLUDES"
87+fi
88+
89 if test x"$hdhomerun_box" = x"yes" ; then
90 CCONFIG="$CCONFIG using_hdhr"
91 fi
92diff -u -r -N mythtv-SVN.orig/libs/libmythtv/cardutil.cpp mythtv-SVN/libs/libmythtv/cardutil.cpp
93--- mythtv-SVN.orig/libs/libmythtv/cardutil.cpp 2006-04-18 09:07:01.000000000 +0200
94+++ mythtv-SVN/libs/libmythtv/cardutil.cpp 2006-04-18 09:11:04.000000000 +0200
95@@ -517,6 +517,7 @@
96
97 if (("FIREWIRE" == cardtype) ||
98 ("DBOX2" == cardtype) ||
99+ ("FREEBOX" == cardtype) ||
100 ("HDHOMERUN" == cardtype))
101 {
102 ret += "MPEG2TS";
103@@ -709,6 +710,10 @@
104 .arg(query.value(1).toString())
105 .arg(query.value(2).toString());
106 }
107+ else if (cardtype == "FREEBOX")
108+ {
109+ label = QString("[ FREEBOX : HOST mafreebox.freebox.fr ]");
110+ }
111 else if (cardtype == "HDHOMERUN")
112 {
113 MSqlQuery query(MSqlQuery::InitCon());
114@@ -745,6 +750,7 @@
115
116 if (("FIREWIRE" == cardtype) ||
117 ("DBOX2" == cardtype) ||
118+ ("FREEBOX" == cardtype) ||
119 ("HDHOMERUN" == cardtype))
120 {
121 inputs += "MPEG2TS";
122diff -u -r -N mythtv-SVN.orig/libs/libmythtv/dbcheck.cpp mythtv-SVN/libs/libmythtv/dbcheck.cpp
123--- mythtv-SVN.orig/libs/libmythtv/dbcheck.cpp 2006-04-18 09:07:00.000000000 +0200
124+++ mythtv-SVN/libs/libmythtv/dbcheck.cpp 2006-04-18 09:20:03.000000000 +0200
125@@ -10,7 +10,7 @@
126 #include "mythdbcon.h"
127
128 /// This is the DB schema version expected by the running MythTV instance.
129-const QString currentDatabaseVersion = "1137";
130+const QString currentDatabaseVersion = "1138";
131
132 static bool UpdateDBVersionNumber(const QString &newnumber);
133 static bool performActualUpdate(const QString updates[], QString version,
134@@ -2176,7 +2176,7 @@
135 ""
136 };
137
138- if (!performActualUpdate(updates, "1135", dbver))
139+ if (!performActualUpdate(updates, "1135", dbver))
140 return false;
141 }
142
143@@ -2187,7 +2187,7 @@
144 "",
145 };
146
147- if (!performActualUpdate(updates, "1136", dbver))
148+ if (!performActualUpdate(updates, "1136", dbver))
149 return false;
150 }
151
152@@ -2198,7 +2198,7 @@
153 "",
154 };
155
156- if (!performActualUpdate(updates, "1137", dbver))
157+ if (!performActualUpdate(updates, "1137", dbver))
158 return false;
159 }
160
161@@ -2206,6 +2206,18 @@
162 //"ALTER TABLE capturecard DROP COLUMN dvb_hw_decoder;" in 0.21
163 //"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22
164
165+ if (dbver == "1137")
166+ {
167+ const QString updates[] = {
168+"INSERT INTO profilegroups (name, cardtype, is_default) "
169+" VALUES('Freebox Input', 'Freebox', 1);",
170+""
171+};
172+
173+ if (!performActualUpdate(updates, "1138", dbver))
174+ return false;
175+ }
176+
177 return true;
178 }
179
180@@ -2832,6 +2844,7 @@
181 "INSERT INTO profilegroups VALUES (8,"
182 " 'USB Mpeg-4 Encoder (Plextor ConvertX, etc)','GO7007',1,NULL);",
183 "INSERT INTO profilegroups VALUES (9,'DBOX2 Input','DBOX2',1,NULL);",
184+"INSERT INTO profilegroups VALUES (10,'Freebox Input','Freebox',1,NULL);",
185 "INSERT INTO recordingprofiles VALUES (1,'Default',NULL,NULL,1);",
186 "INSERT INTO recordingprofiles VALUES (2,'Live TV',NULL,NULL,1);",
187 "INSERT INTO recordingprofiles VALUES (3,'High Quality',NULL,NULL,1);",
188diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxchannel.cpp mythtv-SVN/libs/libmythtv/freeboxchannel.cpp
189--- mythtv-SVN.orig/libs/libmythtv/freeboxchannel.cpp 1970-01-01 01:00:00.000000000 +0100
190+++ mythtv-SVN/libs/libmythtv/freeboxchannel.cpp 2006-04-17 19:34:09.000000000 +0200
191@@ -0,0 +1,327 @@
192+/**
193+ * FreeboxChannel
194+ * Copyright (c) 2005 by Levent Gündogdu
195+ * Distributed as part of MythTV under GPL v2 and later.
196+ */
197+
198+#include <iostream>
199+#include <qsqldatabase.h>
200+#include "mythdbcon.h"
201+#include "mythcontext.h"
202+#include "freeboxchannel.h"
203+
204+FreeboxChannel::FreeboxChannel(TVRec *parent,
205+ int cardid)
206+ : QObject(NULL, "FreeboxChannel"),
207+ ChannelBase(parent),
208+ http(new QHttp()),
209+ m_freeboxchannelcount(0),
210+ m_channelListReady(false),
211+ m_requestChannel(""),
212+ m_lastChannel("1"),
213+ m_cardid(cardid)
214+{
215+ connect(http, SIGNAL(done(bool)),
216+ this, SLOT (HttpRequestDone(bool)));
217+
218+ LoadChannels();
219+}
220+
221+
222+bool FreeboxChannel::SwitchToInput(const QString &inputname,
223+ const QString &chan)
224+{
225+ int inputNum = GetInputByName(inputname);
226+ if (inputNum < 0)
227+ return false;
228+
229+ return SetChannelByString(chan);
230+}
231+
232+
233+bool FreeboxChannel::SetChannelByString(const QString &newChan)
234+{
235+ // Delay set channel when list has not yet been retrieved
236+ if (!m_channelListReady)
237+ {
238+ VERBOSE(VB_IMPORTANT,QString("Freebox # Channel list not received yet. Will switch to channel %1 later...").arg(newChan));
239+ m_requestChannel = newChan;
240+ return true;
241+ }
242+
243+ QString chan = newChan;
244+ // If chan is empty, use DefautChannel
245+ if (chan == "")
246+ {
247+ VERBOSE(VB_IMPORTANT,QString("Freebox # Empty channel name has been provided. Getting default name."));
248+ chan = GetDefaultChannel();
249+ }
250+
251+ // update current chanel
252+ if (m_lastChannel != curchannelname)
253+ m_lastChannel = curchannelname;
254+
255+ curchannelname = chan;
256+ m_currenturl = GetChannelUrlFromNumber(curchannelname);
257+
258+ // emit signal to recorder
259+ emit ChannelChanged();
260+
261+ return true;
262+}
263+
264+
265+QString FreeboxChannel::GetCurrentChannelUrl()
266+{
267+ if(m_currenturl == "")
268+ m_currenturl = QString("rtsp://mafreebox.freebox.fr/freeboxtv/201");
269+ return m_currenturl;
270+}
271+
272+
273+bool FreeboxChannel::IsOpen(void) const
274+{
275+ return true;
276+}
277+
278+
279+bool FreeboxChannel::Open(void)
280+{
281+ if (!InitializeInputs())
282+ return false;
283+
284+ return true;
285+}
286+
287+
288+void FreeboxChannel::Close(void)
289+{
290+}
291+
292+
293+/*
294+ * Channel loading
295+ */
296+
297+void FreeboxChannel::LoadChannels()
298+{
299+ // Request Channel list via http. Signal will be emmitted when list is ready.
300+ QHttpRequestHeader header("GET", "/freeboxtv/playlist.m3u");
301+ header.setValue("Host", "mafreebox.freebox.fr");
302+ http->setHost("mafreebox.freebox.fr", 80);
303+ http->request(header);
304+}
305+
306+
307+QString FreeboxChannel::normalize(QString channelName)
308+{
309+ // Normalize Channel name so we can try to automap channel return by freebox to channel coming from tv_grab_fr
310+ QString res;
311+ for (unsigned int i=0;i<channelName.length();i++)
312+ {
313+ QChar c = channelName[i];
314+ if (c.isSpace()) continue;
315+ c=c.lower();
316+ if (c=='é' || c=='ê' || c=='ê') c='e';
317+ if (c=='à') c='a';
318+ if (c=='i' || c=='î') c=='i';
319+ if (c=='ô') c=='o';
320+
321+ res += c;
322+ }
323+
324+ return res;
325+}
326+
327+
328+/*
329+ * Receive response to channel list request
330+ */
331+
332+void FreeboxChannel::HttpRequestDone(bool error)
333+{
334+ if (error)
335+ {
336+ VERBOSE(VB_IMPORTANT,QString("Freebox # Reading channel list failed!"));
337+ return;
338+ }
339+
340+ QString buffer=http->readAll();
341+ m_freeboxchannelcount = 0;
342+
343+ int sepCount = 0;
344+
345+ QString header = buffer.section("\n", sepCount, sepCount);
346+ sepCount++;
347+
348+ // Verify header is ok
349+ if (header != "#EXTM3U")
350+ {
351+ VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
352+ return;
353+ }
354+
355+ while (true)
356+ {
357+ QString line1 = buffer.section("\n", sepCount, sepCount);
358+ if (line1 == "")
359+ break;
360+
361+ sepCount++;
362+
363+ QString line2 = buffer.section("\n", sepCount, sepCount);
364+ if (line2 == "")
365+ break;
366+
367+ sepCount++;
368+
369+ // each line contains ://
370+ // header:extension,channelNum - channelName rtsp://channelUrl
371+ //#EXTINF:0,2 - France 2 rtsp://mafreebox.freebox.fr/freeboxtv/201
372+
373+ QString lineHead;
374+ QString extension;
375+ QString channelNum;
376+ QString channelName;
377+
378+ int pos = 0;
379+ int oldPos = 0;
380+
381+ pos = line1.find(":", oldPos);
382+ if (pos<0)
383+ {
384+ VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
385+ return;
386+ }
387+ lineHead = line1.mid(0, pos);
388+
389+ if (lineHead != "#EXTINF")
390+ {
391+ VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
392+ return;
393+ }
394+
395+ oldPos = pos + 1;
396+ pos = line1.find(",", oldPos);
397+ if (pos<0)
398+ {
399+ VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
400+ return;
401+ }
402+ extension = line1.mid(oldPos, pos - oldPos);
403+
404+ oldPos = pos + 1;
405+ pos = line1.find(" ", oldPos);
406+ if (pos<0)
407+ {
408+ VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
409+ return;
410+ }
411+ channelNum = line1.mid(oldPos, pos - oldPos);
412+
413+ oldPos = pos + 1;
414+ pos = line1.find("- ", oldPos);
415+ if (pos<0)
416+ {
417+ VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
418+ return;
419+ }
420+ channelName = line1.mid(pos + 2, line1.length());
421+
422+ QString channelUrl = line2;
423+
424+ // save all this information in map for quick access
425+ bool ok;
426+ int channelNumI = channelNum.toInt( &ok, 10 );
427+
428+ QString channelNameN = normalize(channelName);
429+
430+ m_freeboxchannelIds[channelNumI] = m_freeboxchannelcount;
431+ m_freeboxchannelUrl[m_freeboxchannelcount] = channelUrl;
432+ m_freeboxchannelNames[m_freeboxchannelcount] = channelName;
433+ m_freeboxchannelNamesN[m_freeboxchannelcount] = channelNameN;
434+
435+ m_freeboxchannelcount++;
436+ }
437+
438+ // Channel list is ready.
439+ m_channelListReady = true;
440+
441+ // Change channel if delayed request is available
442+ if (m_requestChannel != "")
443+ {
444+ SetChannelByString(m_requestChannel);
445+ m_requestChannel = "";
446+ }
447+}
448+
449+
450+/*
451+ * Map a channel number to the corresponding rtsp URL
452+ */
453+
454+QString FreeboxChannel::GetChannelUrlFromNumber(const QString& channelnumber)
455+{
456+ MSqlQuery query(MSqlQuery::InitCon());
457+
458+ query.prepare("SELECT name,freqid "
459+ "FROM channel,cardinput "
460+ "WHERE "
461+ "channel.sourceid = cardinput.sourceid AND "
462+ "cardinput.cardid = :CARDID AND "
463+ "channel.channum = :CHANNUM");
464+
465+ query.bindValue(":CARDID", m_cardid);
466+ query.bindValue(":CHANNUM", channelnumber);
467+
468+ if (query.exec() && query.isActive() && query.size() > 0)
469+ {
470+ query.next();
471+ QString chanName = query.value(0).toString();
472+
473+ // if we have a FreqID in the table, use this as the real freebox channel number
474+ int mFreqId = query.value(1).toInt();
475+ if (mFreqId!=0)
476+ {
477+ int channelI = m_freeboxchannelIds[mFreqId];
478+ return m_freeboxchannelUrl[channelI];
479+ }
480+
481+ // if no freqID, try to map the chanName to an existing channel name
482+ for (int i=0;i<m_freeboxchannelcount;i++)
483+ {
484+ if (m_freeboxchannelNamesN[i] == chanName)
485+ {
486+ return m_freeboxchannelUrl[i];
487+ }
488+ }
489+
490+ return "";
491+ }
492+ return "";
493+}
494+
495+
496+/*
497+ * Search for default channel
498+ */
499+
500+QString FreeboxChannel::GetDefaultChannel()
501+{
502+ MSqlQuery query(MSqlQuery::InitCon());
503+ query.prepare("SELECT channum "
504+ "FROM channel,cardinput "
505+ "WHERE "
506+ "channel.sourceid = cardinput.sourceid AND "
507+ "cardinput.cardid = :CARDID "
508+ "ORDER BY channum limit 1");
509+
510+ query.bindValue(":CARDID", m_cardid);
511+
512+ if (query.exec() && query.isActive() && query.size() > 0)
513+ {
514+ query.next();
515+ return query.value(0).toString();
516+ }
517+ return "";
518+}
519diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxchannel.h mythtv-SVN/libs/libmythtv/freeboxchannel.h
520--- mythtv-SVN.orig/libs/libmythtv/freeboxchannel.h 1970-01-01 01:00:00.000000000 +0100
521+++ mythtv-SVN/libs/libmythtv/freeboxchannel.h 2006-04-16 19:04:23.000000000 +0200
522@@ -0,0 +1,85 @@
523+#ifndef FREEBOXCHANNEL_H
524+#define FREEBOXCHANNEL_H
525+
526+#include <qstring.h>
527+#include <qmap.h>
528+#include <qhttp.h>
529+#include <qobject.h>
530+#include <qthread.h>
531+
532+#ifdef HAVE_STDINT_H
533+#include <stdint.h>
534+#endif
535+
536+#include "tv_rec.h"
537+#include "channelbase.h"
538+#include "sitypes.h"
539+
540+
541+class FreeboxChannel:public QObject, public ChannelBase
542+{
543+ Q_OBJECT public:
544+ FreeboxChannel (TVRec * parent, int cardid);
545+ ~FreeboxChannel (void)
546+ {
547+ }
548+
549+
550+ bool Open ();
551+ void Close ();
552+ bool SwitchToInput (const QString & inputname, const QString & chan);
553+ bool SetChannelByString (const QString & chan);
554+ bool IsOpen (void) const;
555+
556+
557+ QString GetCurrentChannelUrl ();
558+
559+
560+ bool SwitchToInput (int newcapchannel, bool setstarting)
561+ {
562+ (void) newcapchannel;
563+ (void) setstarting;
564+ return false;
565+ }
566+
567+ QString GetChannelUrlFromNumber (const QString & channelnumber);
568+ QString GetDefaultChannel ();
569+
570+ signals:
571+ void ChannelChanged ();
572+
573+ public slots:void HttpRequestDone (bool error);
574+
575+ private:
576+ void LoadChannels ();
577+ QString normalize (QString channelName);
578+
579+ void Log (QString string);
580+
581+ QHttp *http;
582+
583+ bool m_channelListReady;
584+ QString m_requestChannel;
585+ QString m_lastChannel;
586+ int m_cardid;
587+
588+ // the rtsp url for the current channel
589+ QString m_currenturl;
590+
591+ // number of channel support by freebox
592+ int m_freeboxchannelcount;
593+
594+ // map channelNum to channel index in table
595+ QMap < int, int >m_freeboxchannelIds;
596+
597+ // map channel index to channel url
598+ QMap < int, QString > m_freeboxchannelUrl;
599+
600+ // map channel index to channel name
601+ QMap < int, QString > m_freeboxchannelNames;
602+
603+ // map channel index to channel normalize name
604+ QMap < int, QString > m_freeboxchannelNamesN;
605+};
606+
607+#endif
608diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.cpp mythtv-SVN/libs/libmythtv/freeboxrecorder.cpp
609--- mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.cpp 1970-01-01 01:00:00.000000000 +0100
610+++ mythtv-SVN/libs/libmythtv/freeboxrecorder.cpp 2006-04-16 19:04:23.000000000 +0200
611@@ -0,0 +1,448 @@
612+/**
613+ * FreeboxRecorder
614+ * Copyright (c) 2005 by Levent G?u (mythtv@feature-it.com)
615+ * Distributed as part of MythTV under GPL v2 and later.
616+ */
617+
618+#include <iostream>
619+using namespace std;
620+
621+#include <pthread.h>
622+#include "RingBuffer.h"
623+#include "mythcontext.h"
624+#include "freeboxrecorder.h"
625+#include "freeboxchannel.h"
626+#include <qhttp.h>
627+#include <qobject.h>
628+#include <sys/select.h>
629+#include <sys/types.h>
630+#include <sys/socket.h>
631+#include <netdb.h>
632+#include <fcntl.h>
633+#include <unistd.h>
634+#include <netinet/in.h> // For sockaddr_in on OS X
635+
636+void subsessionAfterPlaying(void *clientData);
637+void subsessionByeHandler(void *clientData);
638+
639+FreeboxRecorder::FreeboxRecorder(TVRec *rec, FreeboxChannel *channel)
640+ : DTVRecorder(rec, "FreeboxRecorder"),
641+ m_channel(channel)
642+{
643+ // the var will be use to abort current rtsp session
644+ _abort_rtsp = new char();
645+
646+ connect (m_channel, SIGNAL(ChannelChanged()),
647+ this, SLOT( ChannelChanged()));
648+}
649+
650+
651+bool FreeboxRecorder::Open()
652+{
653+ // Start a new RTSP flow with current channel
654+ pthread_create(&start_thread, NULL, FreeboxRecorder::StartRtspS, this);
655+ return true;
656+}
657+
658+
659+void FreeboxRecorder::Close()
660+{
661+ // ask for RTSP shutdown setting abort_rstp=1, and wait effective shutdown on mutex
662+ waitShutdown = new QWaitCondition();
663+ *_abort_rtsp = 1;
664+ _request_recording = false;
665+ waitShutdown->wait();
666+
667+ if (session == NULL) return;
668+
669+ // Ensure RTSP cleanup, remove old RTSP session
670+ MediaSubsessionIterator iter(*session);
671+ MediaSubsession* subsession;
672+ while ((subsession = iter.next()) != NULL)
673+ {
674+ Medium::close(subsession->sink);
675+ subsession->sink = NULL;
676+ }
677+
678+ if (session == NULL) return;
679+
680+ rtspClient->teardownMediaSession(*session);
681+
682+ // Close all RTSP descriptor
683+ Medium::close(session);
684+ Medium::close(rtspClient);
685+}
686+
687+
688+void FreeboxRecorder::ChannelChanged()
689+{
690+ // Channel change, we need to close current RTSP flow, and open a new one
691+ Close();
692+ Open();
693+}
694+
695+
696+void FreeboxRecorder::SetOptionsFromProfile(RecordingProfile *profile,
697+ const QString &videodev,
698+ const QString &audiodev,
699+ const QString &vbidev)
700+{
701+ (void)videodev;
702+ (void)audiodev;
703+ (void)vbidev;
704+ (void)profile;
705+}
706+
707+
708+void FreeboxRecorder::StartRecording()
709+{
710+ // Open RTSP flow for current channel
711+ Open();
712+
713+ _request_recording = true;
714+ _recording = true;
715+ _request_abort = false;
716+
717+ // wait until recorder abot
718+ while(_request_recording)
719+ {
720+ if (_request_abort)
721+ break;
722+
723+ usleep(1000);
724+ }
725+}
726+
727+
728+void FreeboxRecorder::StopRecording(void)
729+{
730+ // Close the current RTSP flow
731+ Close();
732+}
733+
734+
735+void *FreeboxRecorder::StartRtspS(void *param)
736+{
737+ FreeboxRecorder *recorder = (FreeboxRecorder*)param;
738+ recorder->StartRtsp();
739+ return NULL;
740+}
741+
742+
743+/*
744+ * Start a new RTSP session for the current channel
745+ */
746+
747+void FreeboxRecorder::StartRtsp()
748+{
749+ // Retrieve the RTSP channel URL
750+ QString url = m_channel->GetCurrentChannelUrl();
751+
752+ VERBOSE(VB_IMPORTANT, QString("Freebox # URL: %1").arg(url));
753+ //
754+ // Begin by setting up our usage environment:
755+ TaskScheduler* scheduler = BasicTaskScheduler::createNew();
756+ env = BasicUsageEnvironment::createNew(*scheduler);
757+
758+ // Create our client object:
759+ rtspClient = RTSPClient::createNew(*env, 0, "myRTSP", 0);
760+ if (rtspClient == NULL)
761+ {
762+ VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create RTSP client: %1").arg(env->getResultMsg()));
763+ shutdown();
764+ }
765+
766+ // Setup URL for the current session
767+ char* sdpDescription = rtspClient->describeURL(url);
768+ rtspClient->describeStatus();
769+
770+ if (sdpDescription == NULL)
771+ {
772+ VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to get a SDP description from URL: %1 %2").arg(url).arg(env->getResultMsg()));
773+ shutdown();
774+ }
775+
776+ // Create a media session object from this SDP description:
777+ session = MediaSession::createNew(*env, sdpDescription);
778+ delete[] sdpDescription;
779+ if (session == NULL)
780+ {
781+ VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create a MediaSession object from the SDP description: %1").arg(env->getResultMsg()));
782+ shutdown();
783+ }
784+ else if (!session->hasSubsessions())
785+ {
786+ VERBOSE(VB_IMPORTANT, QString("Freebox # This session has no media subsessions"));
787+ shutdown();
788+ }
789+
790+ // Then, setup the "RTPSource"s for the session:
791+ MediaSubsessionIterator iter(*session);
792+ MediaSubsession *subsession;
793+ Boolean madeProgress = False;
794+ while ((subsession = iter.next()) != NULL)
795+ {
796+ if (!subsession->initiate(-1))
797+ {
798+ VERBOSE(VB_IMPORTANT, QString("Freebox # Unable to create receiver for: %1 / %2 subsession: %3").arg(subsession->mediumName()).arg(subsession->codecName()).arg(env->getResultMsg()));
799+ }
800+ else
801+ {
802+ madeProgress = True;
803+
804+ if (subsession->rtpSource() != NULL)
805+ {
806+ // 1 second
807+ unsigned const thresh = 1000000;
808+ subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
809+ }
810+ }
811+ }
812+
813+ if (!madeProgress) shutdown();
814+
815+ // Perform additional 'setup' on each subsession, before playing them:
816+ madeProgress = false;
817+ iter.reset();
818+ while ((subsession = iter.next()) != NULL)
819+ {
820+ // port # was not set
821+ if (subsession->clientPortNum() == 0) continue;
822+
823+ if (rtspClient->setupMediaSubsession(*subsession, False, false))
824+ {
825+ madeProgress = True;
826+ }
827+ else
828+ {
829+ VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to setup: %1 %2 : %3").arg(subsession->mediumName()).arg(subsession->codecName()).arg(env->getResultMsg()));
830+ }
831+ }
832+
833+ if (!madeProgress) shutdown();
834+
835+ // Create and start "FileSink"s for each subsession:
836+ // FileSink while receive Mpeg2 TS Data & will feed them to mythtv
837+ madeProgress = False;
838+ iter.reset();
839+ while ((subsession = iter.next()) != NULL)
840+ {
841+ // was not initiated
842+ if (subsession->readSource() == NULL) continue;
843+
844+ FreeboxSink* FreeboxSink = FreeboxSink::createNew(*env, this);
845+
846+ subsession->sink = FreeboxSink;
847+ if (subsession->sink == NULL)
848+ {
849+ VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create sink: %1").arg(env->getResultMsg()));
850+ }
851+
852+ subsession->sink->startPlaying(*(subsession->readSource()), subsessionAfterPlaying, new FreeboxData(this, subsession));
853+
854+ if (subsession->rtcpInstance() != NULL)
855+ {
856+ subsession->rtcpInstance()->setByeHandler(subsessionByeHandler, new FreeboxData(this, subsession));
857+ }
858+
859+ madeProgress = True;
860+ }
861+
862+ if (!madeProgress) shutdown();
863+
864+ // Setup player
865+ if (!(rtspClient->playMediaSession(*session)))
866+ {
867+ VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to start playing session: %1").arg(env->getResultMsg()));
868+ shutdown();
869+ }
870+
871+ request_pause = false;
872+ paused = false;
873+ _request_recording = true;
874+ _recording = true;
875+ *_abort_rtsp=0;
876+
877+ // Go into main RTSP loop, feeding data to mythtv
878+ // does not return
879+ env->taskScheduler().doEventLoop(_abort_rtsp);
880+
881+ // Event loop exists, the recording finish
882+ FinishRecording();
883+ _recording = false;
884+
885+ // wakeUp everibody
886+ waitShutdown->wakeAll();
887+}
888+
889+
890+/*
891+ * Find a TS Header in flow
892+ */
893+int FreeboxRecorder::findTSHeader(unsigned char *data, unsigned dataSize)
894+{
895+ unsigned int pos = 0;
896+
897+ while (pos < dataSize)
898+ {
899+ if (data[pos] == 0x47)
900+ return pos;
901+ pos++;
902+ }
903+ return -1;
904+}
905+
906+
907+/*
908+ * Feed date from RTSP flow to mythtv
909+ */
910+void FreeboxRecorder::addData(unsigned char* data, unsigned dataSize, struct timeval )
911+{
912+ unsigned int readIndex = 0;
913+
914+ // data may be compose from more than one packet, loop to consume all data
915+ while (readIndex < dataSize)
916+ {
917+ // If recorder is pause, stop there
918+ if (PauseAndWait())
919+ {
920+ return;
921+ }
922+
923+ // Find the next TS Header in data
924+ int tsPos = findTSHeader(data + readIndex, dataSize);
925+
926+ // if no TS, something bad happens
927+ if (tsPos == -1)
928+ {
929+ VERBOSE(VB_IMPORTANT, QString("FREEBOX: No TS header."));
930+ break;
931+ }
932+
933+ // if TS Header not at start of data, we receive out of sync data
934+ if (tsPos > 0)
935+ {
936+ VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1, not in sync.").arg(tsPos));
937+ }
938+
939+ // Check if the next packet in buffer is complete : packet size is 188 bytes long
940+ if ((dataSize - tsPos) < 188)
941+ {
942+ VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1 but packet not yet complete.").arg(tsPos));
943+ break;
944+ }
945+
946+ // Cast current found TS Packet to TSPacket structure
947+ const void *newData = data + tsPos + readIndex;
948+ const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(newData);
949+
950+ // Feed current packet to myth
951+ _buffer_packets = !FindKeyframes(tspacket);
952+ BufferedWrite(*tspacket);
953+
954+ // follow to next packet
955+ readIndex += tsPos + TSPacket::SIZE;
956+
957+ }
958+}
959+
960+
961+void FreeboxRecorder::shutdown(int )
962+{
963+}
964+
965+
966+void subsessionAfterPlaying(void *clientData)
967+{
968+ FreeboxData *myData = (FreeboxData*)clientData;
969+ myData->freeboxRecorder->SubsessionAfterPlaying(myData->mediaSubSession);
970+}
971+
972+
973+void subsessionByeHandler(void *clientData)
974+{
975+ FreeboxData *myData = (FreeboxData*)clientData;
976+ myData->freeboxRecorder->SubsessionByeHandler(myData->mediaSubSession);
977+}
978+
979+
980+void FreeboxRecorder::SubsessionAfterPlaying(MediaSubsession* subsession)
981+{
982+ Medium::close(subsession->sink);
983+ subsession->sink = NULL;
984+
985+ MediaSession& session = subsession->parentSession();
986+ MediaSubsessionIterator iter(session);
987+ while ((subsession = iter.next()) != NULL)
988+ {
989+ if (subsession->sink != NULL) return;
990+ }
991+
992+ shutdown(0);
993+
994+}
995+
996+
997+void FreeboxRecorder::SubsessionByeHandler(MediaSubsession* subsession)
998+{
999+ subsessionAfterPlaying(subsession);
1000+}
1001+
1002+/*
1003+ * Helper class use to receive RTSP data from socket.
1004+ */
1005+
1006+FreeboxSink::FreeboxSink(UsageEnvironment& pEnv, FreeboxRecorder *pRecorder) : MediaSink(pEnv)
1007+{
1008+ recorder = pRecorder;
1009+ env = &pEnv;
1010+
1011+ // Setup the data buffer
1012+ fBufferSize = 20000;
1013+ fBuffer = new unsigned char[fBufferSize];
1014+}
1015+
1016+
1017+FreeboxSink::~FreeboxSink()
1018+{
1019+ // free the data buffer
1020+ delete[] fBuffer;
1021+}
1022+
1023+
1024+FreeboxSink* FreeboxSink::createNew(UsageEnvironment& env, FreeboxRecorder *pRecorder)
1025+{
1026+ FreeboxSink* newSink = new FreeboxSink(env, pRecorder);
1027+ return newSink;
1028+}
1029+
1030+
1031+Boolean FreeboxSink::continuePlaying()
1032+{
1033+ if (fSource == NULL) return False;
1034+
1035+ fSource->getNextFrame(fBuffer, fBufferSize, afterGettingFrame, this, onSourceClosure, this);
1036+
1037+ return True;
1038+}
1039+
1040+
1041+void FreeboxSink::afterGettingFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/,struct timeval presentationTime, unsigned /*durationInMicroseconds*/)
1042+{
1043+
1044+ FreeboxSink* sink = (FreeboxSink*)clientData;
1045+ sink->afterGettingFrame1(frameSize, presentationTime);
1046+}
1047+
1048+
1049+void FreeboxSink::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime)
1050+{
1051+ addData(fBuffer, frameSize, presentationTime);
1052+ continuePlaying();
1053+}
1054+
1055+
1056+void FreeboxSink::addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime)
1057+{
1058+ recorder->addData(data, dataSize, presentationTime);
1059+}
1060diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.h mythtv-SVN/libs/libmythtv/freeboxrecorder.h
1061--- mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.h 1970-01-01 01:00:00.000000000 +0100
1062+++ mythtv-SVN/libs/libmythtv/freeboxrecorder.h 2006-04-16 19:04:23.000000000 +0200
1063@@ -0,0 +1,148 @@
1064+/**
1065+ * DBOX2Recorder
1066+ * Copyright (c) 2005 by Levent Gündogdu
1067+ * Distributed as part of MythTV under GPL v2 and later.
1068+ */
1069+
1070+#ifndef FREEBOXRECORDER_H_
1071+#define FREEBOXRECORDER_H_
1072+
1073+#include "dtvrecorder.h"
1074+#include <time.h>
1075+#include "freeboxchannel.h"
1076+#include "sitypes.h"
1077+#include "qhttp.h"
1078+#include "mpeg/tspacket.h"
1079+
1080+
1081+#include "BasicUsageEnvironment.hh"
1082+#include "GroupsockHelper.hh"
1083+#include "liveMedia.hh"
1084+
1085+/**
1086+ * Constructs a FreeboxRecorder
1087+ */
1088+
1089+#if defined(__WIN32__) || defined(_WIN32)
1090+#define snprintf _snprintf
1091+#else
1092+#include <signal.h>
1093+#define USE_SIGNALS 1
1094+#endif
1095+
1096+
1097+
1098+class FreeboxRecorder:public DTVRecorder
1099+{
1100+ Q_OBJECT public:
1101+ FreeboxRecorder (TVRec * rec, FreeboxChannel * channel);
1102+ ~FreeboxRecorder ()
1103+ {
1104+ }
1105+
1106+
1107+ void StartRecording (void);
1108+ void StopRecording (void);
1109+ bool Open (void);
1110+ void Close ();
1111+
1112+ void SetOptionsFromProfile (RecordingProfile * profile,
1113+ const QString & videodev,
1114+ const QString & audiodev,
1115+ const QString & vbidev);
1116+
1117+ void SubsessionAfterPlaying (MediaSubsession * subsession);
1118+ void SubsessionByeHandler (MediaSubsession * subsession);
1119+
1120+ // Callback function to add MPEG2 TS data
1121+ void addData (unsigned char *data, unsigned dataSize,
1122+ struct timeval presentationTime);
1123+
1124+ // Look for TS Header in data
1125+ int findTSHeader (unsigned char *data, unsigned dataSize);
1126+
1127+
1128+ public slots:void ChannelChanged ();
1129+
1130+
1131+ private:
1132+ UsageEnvironment * env;
1133+ RTSPClient *rtspClient;
1134+ MediaSession *session;
1135+
1136+ // var to check if we need to abort current rtsp session
1137+ char *_abort_rtsp;
1138+
1139+ // request abort for StartRecording Thread
1140+ bool _request_abort;
1141+
1142+ // Call back function to start RTSP Flow
1143+ static void *StartRtspS (void *param);
1144+ void StartRtsp ();
1145+
1146+ void shutdown (int exitCode = 1);
1147+
1148+ // Current channel
1149+ FreeboxChannel *m_channel;
1150+
1151+ // Mutex : use to make sure that current RTSP thread as stop
1152+ QWaitCondition *waitShutdown;
1153+
1154+ // The current RTSP thread
1155+ pthread_t start_thread;
1156+};
1157+
1158+
1159+/*
1160+ * Helper class use for static Callback handler
1161+ */
1162+class FreeboxData
1163+{
1164+ public:
1165+ FreeboxData (FreeboxRecorder * pFreeboxRecorder,
1166+ MediaSubsession * pMediaSubSession)
1167+ {
1168+ freeboxRecorder = pFreeboxRecorder;
1169+ mediaSubSession = pMediaSubSession;
1170+ }
1171+
1172+ FreeboxRecorder *freeboxRecorder;
1173+ MediaSubsession *mediaSubSession;
1174+};
1175+
1176+
1177+/*
1178+ * Helper class use to receive RTSP data from socket.
1179+ */
1180+class FreeboxSink:public MediaSink
1181+{
1182+ public:
1183+ static FreeboxSink *createNew (UsageEnvironment & env,
1184+ FreeboxRecorder * pRecorder);
1185+
1186+ // Callback function when rtsp data are ready
1187+ void addData (unsigned char *data, unsigned dataSize,
1188+ struct timeval presentationTime);
1189+
1190+ protected:
1191+ FreeboxSink (UsageEnvironment & env, FreeboxRecorder * pRecorder);
1192+ virtual ~ FreeboxSink ();
1193+
1194+ static void afterGettingFrame (void *clientData, unsigned frameSize,
1195+ unsigned numTruncatedBytes,
1196+ struct timeval presentationTime,
1197+ unsigned durationInMicroseconds);
1198+ virtual void afterGettingFrame1 (unsigned frameSize,
1199+ struct timeval presentationTime);
1200+
1201+ private:
1202+ virtual Boolean continuePlaying ();
1203+
1204+ unsigned char *fBuffer;
1205+ unsigned fBufferSize;
1206+ UsageEnvironment *env;
1207+ FreeboxRecorder *recorder;
1208+ int bufferIndex;
1209+
1210+};
1211+#endif
1212diff -u -r -N mythtv-SVN.orig/libs/libmythtv/libmythtv.pro mythtv-SVN/libs/libmythtv/libmythtv.pro
1213--- mythtv-SVN.orig/libs/libmythtv/libmythtv.pro 2006-04-18 09:06:59.000000000 +0200
1214+++ mythtv-SVN/libs/libmythtv/libmythtv.pro 2006-04-18 09:09:38.000000000 +0200
1215@@ -347,6 +347,10 @@
1216 using_dbox2:SOURCES += dbox2recorder.cpp dbox2channel.cpp dbox2epg.cpp
1217 using_dbox2:HEADERS += dbox2recorder.h dbox2channel.h dbox2epg.h
1218 using_dbox2:DEFINES += USING_DBOX2
1219+
1220+ # Support for FreeBox
1221+ using_freebox:SOURCES += freeboxrecorder.cpp freeboxchannel.cpp
1222+ using_freebox:HEADERS += freeboxrecorder.h freeboxchannel.h
1223
1224 # Support for HDHomeRun box
1225 using_hdhr {
1226diff -u -r -N mythtv-SVN.orig/libs/libmythtv/tv_rec.cpp mythtv-SVN/libs/libmythtv/tv_rec.cpp
1227--- mythtv-SVN.orig/libs/libmythtv/tv_rec.cpp 2006-04-18 09:07:02.000000000 +0200
1228+++ mythtv-SVN/libs/libmythtv/tv_rec.cpp 2006-04-18 09:36:41.000000000 +0200
1229@@ -73,6 +73,11 @@
1230 #include "dbox2channel.h"
1231 #endif
1232
1233+#ifdef USING_FREEBOX
1234+#include "freeboxrecorder.h"
1235+#include "freeboxchannel.h"
1236+#endif
1237+
1238 #ifdef USING_HDHOMERUN
1239 #include "hdhrrecorder.h"
1240 #include "hdhrchannel.h"
1241@@ -188,6 +193,16 @@
1242 init_run = true;
1243 #endif
1244 }
1245+ else if (genOpt.cardtype == "FREEBOX")
1246+ {
1247+#ifdef USING_FREEBOX
1248+ channel = new FreeboxChannel(this, cardid);
1249+ if(!channel->Open())
1250+ return false;
1251+ InitChannel(genOpt.defaultinput, startchannel);
1252+ init_run = true;
1253+#endif
1254+ }
1255 else if (genOpt.cardtype == "HDHOMERUN")
1256 {
1257 #ifdef USING_HDHOMERUN
1258@@ -310,6 +325,11 @@
1259 GetDBox2Channel()->deleteLater();
1260 else
1261 #endif // USING_DBOX2
1262+#ifdef USING_FREEBOX
1263+ if (GetFreeboxChannel())
1264+ GetFreeboxChannel()->deleteLater();
1265+ else
1266+#endif // USING_FREEBOX
1267 if (channel)
1268 delete channel;
1269 channel = NULL;
1270@@ -870,6 +890,12 @@
1271 recorder->SetOption("httpport", dboxOpt.httpport);
1272 #endif // USING_DBOX2
1273 }
1274+ else if (genOpt.cardtype == "FREEBOX")
1275+ {
1276+#ifdef USING_FREEBOX
1277+ recorder = new FreeboxRecorder(this, GetFreeboxChannel());
1278+#endif // USING_FREEBOX
1279+ }
1280 else if (genOpt.cardtype == "HDHOMERUN")
1281 {
1282 #ifdef USING_HDHOMERUN
1283@@ -1094,6 +1120,15 @@
1284 #endif // USING_DBOX2
1285 }
1286
1287+FreeboxChannel *TVRec::GetFreeboxChannel(void)
1288+{
1289+#ifdef USING_FREEBOX
1290+ return dynamic_cast<FreeboxChannel*>(channel);
1291+#else
1292+ return NULL;
1293+#endif // USING_FREEBOX
1294+}
1295+
1296 HDHRChannel *TVRec::GetHDHRChannel(void)
1297 {
1298 #ifdef USING_HDHOMERUN
1299diff -u -r -N mythtv-SVN.orig/libs/libmythtv/tv_rec.h mythtv-SVN/libs/libmythtv/tv_rec.h
1300--- mythtv-SVN.orig/libs/libmythtv/tv_rec.h 2006-04-18 09:07:02.000000000 +0200
1301+++ mythtv-SVN/libs/libmythtv/tv_rec.h 2006-04-18 09:15:58.000000000 +0200
1302@@ -36,6 +36,7 @@
1303
1304 class ChannelBase;
1305 class DBox2Channel;
1306+class FreeboxChannel;
1307 class HDHRChannel;
1308 class DVBChannel;
1309 class Channel;
1310@@ -287,10 +288,11 @@
1311 bool CreateChannel(const QString &startChanNum);
1312 void InitChannel(const QString &inputname, const QString &startchannel);
1313 void CloseChannel(void);
1314- DBox2Channel *GetDBox2Channel(void);
1315- HDHRChannel *GetHDHRChannel(void);
1316- DVBChannel *GetDVBChannel(void);
1317- Channel *GetV4LChannel(void);
1318+ DBox2Channel *GetDBox2Channel(void);
1319+ HDHRChannel *GetHDHRChannel(void);
1320+ DVBChannel *GetDVBChannel(void);
1321+ FreeboxChannel *GetFreeboxChannel(void);
1322+ Channel *GetV4LChannel(void);
1323
1324 void SetupSignalMonitor(bool enable_table_monitoring, bool notify);
1325 bool SetupDTVSignalMonitor(void);
1326diff -u -r -N mythtv-SVN.orig/libs/libmythtv/videosource.cpp mythtv-SVN/libs/libmythtv/videosource.cpp
1327--- mythtv-SVN.orig/libs/libmythtv/videosource.cpp 2006-04-18 09:07:01.000000000 +0200
1328+++ mythtv-SVN/libs/libmythtv/videosource.cpp 2006-04-18 09:36:02.000000000 +0200
1329@@ -914,6 +914,19 @@
1330 CaptureCard &parent;
1331 };
1332
1333+class FreeboxConfigurationGroup: public VerticalConfigurationGroup {
1334+ public:
1335+ FreeboxConfigurationGroup(CaptureCard& a_parent):
1336+ ConfigurationGroup(false, true, false, false),
1337+ VerticalConfigurationGroup(false, true, false, false),
1338+ parent(a_parent)
1339+ {
1340+ setUseLabel(false);
1341+ };
1342+ private:
1343+ CaptureCard& parent;
1344+};
1345+
1346 class HDHomeRunDeviceID: public LineEditSetting, public CCSetting
1347 {
1348 public:
1349@@ -927,6 +940,7 @@
1350 }
1351 };
1352
1353+
1354 class HDHomeRunTunerIndex: public ComboBoxSetting, public CCSetting
1355 {
1356 public:
1357@@ -1076,6 +1090,10 @@
1358 #ifdef USING_HDHOMERUN
1359 addTarget("HDHOMERUN", new HDHomeRunConfigurationGroup(parent));
1360 #endif // USING_HDHOMERUN
1361+
1362+#ifdef USING_FREEBOX
1363+ addTarget("FREEBOX", new FreeboxConfigurationGroup(parent));
1364+#endif // USING_FREEBOX
1365 }
1366
1367 void CaptureCardGroup::triggerChanged(const QString& value)
1368@@ -1190,6 +1208,11 @@
1369 QObject::tr("DBox2 TCP/IP cable box"), "DBOX2");
1370 #endif // USING_DBOX2
1371
1372+#ifdef USING_FREEBOX
1373+ setting->addSelection(
1374+ QObject::tr("Freebox"), "FREEBOX");
1375+#endif // USING_FREEBOX
1376+
1377 #ifdef USING_HDHOMERUN
1378 setting->addSelection(
1379 QObject::tr("HDHomeRun DTV tuner box"), "HDHOMERUN");
1380diff -u -r -N mythtv-SVN.orig/settings.pro mythtv-SVN/settings.pro
1381--- mythtv-SVN.orig/settings.pro 2006-04-18 09:07:07.000000000 +0200
1382+++ mythtv-SVN/settings.pro 2006-04-16 19:05:43.000000000 +0200
1383@@ -79,6 +79,7 @@
1384 EXTRA_LIBS += $$CONFIG_AUDIO_JACK_LIBS
1385 EXTRA_LIBS += $$CONFIG_FIREWIRE_LIBS
1386 EXTRA_LIBS += $$CONFIG_DIRECTFB_LIBS
1387+EXTRA_LIBS += $$CONFIG_LIVE_LIBS
1388
1389 EXTRA_LIBS += $$LOCAL_LIBDIR_OGL
1390 EXTRA_LIBS += $$LOCAL_LIBDIR_X11