Ticket #1704: patch-freebox

File patch-freebox, 38.9 KB (added by mythtv@…, 14 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