diff -u -r -N mythtv-SVN.orig/configure mythtv-SVN/configure
--- mythtv-SVN.orig/configure	2006-04-18 09:06:57.000000000 +0200
+++ mythtv-SVN/configure	2006-04-18 09:08:41.000000000 +0200
@@ -54,6 +54,7 @@
 lirc="yes"
 joystick_menu="yes"
 firewire_cable_box="yes"
+freebox_box="no"
 dbox2_dvb_box="yes"
 hdhomerun_box="yes"
 x11_include_path="/usr/X11R6/include"
@@ -173,6 +174,9 @@
 echo "  --disable-lirc           disable lirc support (Infrared Remotes)"
 echo "  --disable-joystick-menu  disable joystick menu"
 echo "  --disable-firewire       disable support for FireWire cable boxes"
+echo "  --enable-freebox         enable support for Freebox"
+echo "  --livelibdir=DIR         location of Live streaming library"
+echo "  --liveincludedir=DIR     location of Live streaming include files"
 echo "  --disable-dbox2          disable support for Nokia DBOX2 DVB boxes (or compatibles)"
 echo "  --disable-hdhomerun      disable support for HDHomeRun boxes"
 echo "  --disable-v4l            disable Video4Linux support"
@@ -810,6 +814,14 @@
   ;;
   --disable-dbox2) dbox2_dvb_box="no"
   ;;
+  --enable-freebox) freebox_box="yes"
+  ;;
+  --disable-freebox) freebox_box="no"
+  ;;
+  --livelibdir=*) live_lib_dir=`echo $opt | cut -d '=' -f 2`
+  ;;
+  --liveincludedir=*) live_include_dir=`echo $opt | cut -d '=' -f 2`
+  ;;
   --enable-hdhomerun) hdhomerun_box="yes"
   ;;
   --disable-hdhomerun) hdhomerun_box="no"
@@ -2243,6 +2255,7 @@
   echo "FireWire support $firewire_cable_box"
   echo "DVB support      $dvb [$dvb_path]"
   echo "DBox2 support    $dbox2_dvb_box"
+  echo "freebox support  $freebox_box"
   echo "HDHomeRun sup.   $hdhomerun_box"
 fi
 
@@ -2885,6 +2898,46 @@
   CCONFIG="$CCONFIG using_dbox2"
 fi
 
+if test x"$freebox_box" = x"yes" ; then
+  if test "x$live_lib_dir" = "x"; then
+    if has_library libliveMedia; then
+      CONFIG_LIVE_LIBS="-lliveMedia -lgroupsock -lBasicUsageEnvironment  -lUsageEnvironment"
+    else
+      echo "Unable to find Live Media library."
+      exit 1;
+    fi
+  else
+    if test ! -f "$live_lib_dir/liveMedia/libliveMedia.a"; then
+      echo "Unable to find Live Media library."
+      exit 1;
+    fi
+    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"
+  fi
+  if test "x$live_include_dir" = "x"; then
+    if has_header liveMedia.hh; then
+      true
+    else
+      echo "Unable to find Live Media headers."
+      exit 1;
+    fi
+  else
+    if test -f "$live_include_dir/liveMedia/include/liveMedia.hh"; then
+      LIVE_INCLUDES="$live_include_dir/liveMedia/include $live_include_dir/UsageEnvironment/include $live_include_dir/BasicUsageEnvironment/include $live_include_dir/groupsock/include"
+    else
+      if test -f "$live_include_dir/liveMedia/liveMedia.hh"; then
+        LIVE_INCLUDES="$live_include_dir/liveMedia $live_include_dir/UsageEnvironment $live_include_dir/BasicUsageEnvironment $live_include_dir/groupsock"
+      else
+        echo "Unable to find Live Media headers."
+        exit 1;
+      fi
+    fi
+  fi
+  CCONFIG="$CCONFIG using_freebox"
+  CONFIG_DEFINES="$CONFIG_DEFINES USING_FREEBOX"
+  echo "CONFIG_LIVE_LIBS=$CONFIG_LIVE_LIBS" >> $MYTH_CONFIG_MAK
+  CONFIG_INCLUDEPATH="$CONFIG_INCLUDEPATH $LIVE_INCLUDES"
+fi
+
 if test x"$hdhomerun_box" = x"yes" ; then
   CCONFIG="$CCONFIG using_hdhr"
 fi
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/cardutil.cpp mythtv-SVN/libs/libmythtv/cardutil.cpp
--- mythtv-SVN.orig/libs/libmythtv/cardutil.cpp	2006-04-18 09:07:01.000000000 +0200
+++ mythtv-SVN/libs/libmythtv/cardutil.cpp	2006-04-18 09:11:04.000000000 +0200
@@ -517,6 +517,7 @@
 
     if (("FIREWIRE"  == cardtype) ||
         ("DBOX2"     == cardtype) ||
+        ("FREEBOX"   == cardtype) ||
         ("HDHOMERUN" == cardtype))
     {
         ret += "MPEG2TS";
@@ -709,6 +710,10 @@
                 .arg(query.value(1).toString())
                 .arg(query.value(2).toString());
     }
+    else if (cardtype == "FREEBOX")
+    {
+        label = QString("[ FREEBOX : HOST mafreebox.freebox.fr ]");
+    }
     else if (cardtype == "HDHOMERUN")
     {
         MSqlQuery query(MSqlQuery::InitCon());
@@ -745,6 +750,7 @@
 
     if (("FIREWIRE"  == cardtype) ||
         ("DBOX2"     == cardtype) ||
+        ("FREEBOX"   == cardtype) ||
         ("HDHOMERUN" == cardtype))
     {
         inputs += "MPEG2TS";
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/dbcheck.cpp mythtv-SVN/libs/libmythtv/dbcheck.cpp
--- mythtv-SVN.orig/libs/libmythtv/dbcheck.cpp	2006-04-18 09:07:00.000000000 +0200
+++ mythtv-SVN/libs/libmythtv/dbcheck.cpp	2006-04-18 09:20:03.000000000 +0200
@@ -10,7 +10,7 @@
 #include "mythdbcon.h"
 
 /// This is the DB schema version expected by the running MythTV instance.
-const QString currentDatabaseVersion = "1137";
+const QString currentDatabaseVersion = "1138";
 
 static bool UpdateDBVersionNumber(const QString &newnumber);
 static bool performActualUpdate(const QString updates[], QString version,
@@ -2176,7 +2176,7 @@
 ""
 };
 
-       if (!performActualUpdate(updates, "1135", dbver))
+        if (!performActualUpdate(updates, "1135", dbver))
             return false;
     }
 
@@ -2187,7 +2187,7 @@
 "",
 };
 
-       if (!performActualUpdate(updates, "1136", dbver))
+        if (!performActualUpdate(updates, "1136", dbver))
             return false;
     }
 
@@ -2198,7 +2198,7 @@
 "",
 };
 
-       if (!performActualUpdate(updates, "1137", dbver))
+        if (!performActualUpdate(updates, "1137", dbver))
             return false;
     }
 
@@ -2206,6 +2206,18 @@
 //"ALTER TABLE capturecard DROP COLUMN dvb_hw_decoder;" in 0.21
 //"ALTER TABLE cardinput DROP COLUMN  preference;" in 0.22
 
+    if (dbver == "1137")
+    {
+        const QString updates[] = {
+"INSERT INTO profilegroups (name, cardtype, is_default) "
+"            VALUES('Freebox Input', 'Freebox', 1);",
+""
+};
+
+        if (!performActualUpdate(updates, "1138", dbver))
+            return false;
+    }
+
     return true;
 }
 
@@ -2832,6 +2844,7 @@
 "INSERT INTO profilegroups VALUES (8,"
 " 'USB Mpeg-4 Encoder (Plextor ConvertX, etc)','GO7007',1,NULL);",
 "INSERT INTO profilegroups VALUES (9,'DBOX2 Input','DBOX2',1,NULL);",
+"INSERT INTO profilegroups VALUES (10,'Freebox Input','Freebox',1,NULL);",
 "INSERT INTO recordingprofiles VALUES (1,'Default',NULL,NULL,1);",
 "INSERT INTO recordingprofiles VALUES (2,'Live TV',NULL,NULL,1);",
 "INSERT INTO recordingprofiles VALUES (3,'High Quality',NULL,NULL,1);",
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxchannel.cpp mythtv-SVN/libs/libmythtv/freeboxchannel.cpp
--- mythtv-SVN.orig/libs/libmythtv/freeboxchannel.cpp	1970-01-01 01:00:00.000000000 +0100
+++ mythtv-SVN/libs/libmythtv/freeboxchannel.cpp	2006-04-17 19:34:09.000000000 +0200
@@ -0,0 +1,327 @@
+/**
+ *  FreeboxChannel
+ *  Copyright (c) 2005 by Levent Gndogdu
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#include <iostream>
+#include <qsqldatabase.h>
+#include "mythdbcon.h"
+#include "mythcontext.h"
+#include "freeboxchannel.h"
+
+FreeboxChannel::FreeboxChannel(TVRec *parent, 
+                               int cardid)
+              : QObject(NULL, "FreeboxChannel"),
+                ChannelBase(parent),
+                http(new QHttp()),
+                m_freeboxchannelcount(0),
+                m_channelListReady(false),
+                m_requestChannel(""),
+                m_lastChannel("1"),
+                m_cardid(cardid)
+{
+    connect(http, SIGNAL(done(bool)),
+            this, SLOT  (HttpRequestDone(bool)));
+
+    LoadChannels();
+}
+
+
+bool FreeboxChannel::SwitchToInput(const QString &inputname,
+                                   const QString &chan)
+{
+    int inputNum = GetInputByName(inputname);
+    if (inputNum < 0)
+        return false;
+
+    return SetChannelByString(chan);
+}
+
+
+bool FreeboxChannel::SetChannelByString(const QString &newChan)
+{
+    // Delay set channel when list has not yet been retrieved
+    if (!m_channelListReady)
+    {
+        VERBOSE(VB_IMPORTANT,QString("Freebox # Channel list not received yet. Will switch to channel %1 later...").arg(newChan));
+        m_requestChannel = newChan;
+        return true;
+    }
+
+    QString chan = newChan;
+    // If chan is empty, use DefautChannel
+    if (chan == "")
+    {
+        VERBOSE(VB_IMPORTANT,QString("Freebox # Empty channel name has been provided. Getting default name."));
+        chan = GetDefaultChannel();
+    }
+
+    // update current chanel
+    if (m_lastChannel != curchannelname)
+        m_lastChannel = curchannelname;
+
+    curchannelname = chan;
+    m_currenturl = GetChannelUrlFromNumber(curchannelname);
+
+    // emit signal to recorder
+    emit ChannelChanged();
+
+    return true;
+}
+
+
+QString FreeboxChannel::GetCurrentChannelUrl()
+{
+    if(m_currenturl == "")
+        m_currenturl = QString("rtsp://mafreebox.freebox.fr/freeboxtv/201");
+    return m_currenturl;
+}
+
+
+bool FreeboxChannel::IsOpen(void) const
+{
+    return true;
+}
+
+
+bool FreeboxChannel::Open(void)
+{
+    if (!InitializeInputs())
+        return false;
+
+    return true;
+}
+
+
+void FreeboxChannel::Close(void)
+{
+}
+
+
+/*
+ * Channel loading
+ */
+
+void FreeboxChannel::LoadChannels()
+{
+    // Request Channel list via http. Signal will be emmitted when list is ready.
+    QHttpRequestHeader header("GET", "/freeboxtv/playlist.m3u");
+    header.setValue("Host", "mafreebox.freebox.fr");
+    http->setHost("mafreebox.freebox.fr", 80);
+    http->request(header);
+}
+
+
+QString FreeboxChannel::normalize(QString channelName)
+{
+    // Normalize Channel name so we can try to automap channel return by freebox to channel coming from tv_grab_fr
+    QString res;
+    for (unsigned int i=0;i<channelName.length();i++)
+    {
+        QChar c = channelName[i];
+        if (c.isSpace()) continue;
+        c=c.lower();
+        if (c=='' || c=='' || c=='') c='e';
+        if (c=='') c='a';
+        if (c=='i' || c=='') c=='i';
+        if (c=='') c=='o';
+
+        res += c;
+    }
+
+    return res;
+}
+
+
+/*
+ * Receive response to channel list request
+ */
+
+void FreeboxChannel::HttpRequestDone(bool error)
+{
+    if (error)
+    {
+        VERBOSE(VB_IMPORTANT,QString("Freebox # Reading channel list failed!"));
+        return;
+    }
+
+    QString buffer=http->readAll();
+    m_freeboxchannelcount = 0;
+
+    int sepCount = 0;
+
+    QString header = buffer.section("\n", sepCount, sepCount);
+    sepCount++;
+
+    // Verify header is ok
+    if (header != "#EXTM3U")
+    {
+        VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
+        return;
+    }
+
+    while (true)
+    {
+        QString line1 = buffer.section("\n", sepCount, sepCount);
+        if (line1 == "")
+            break;
+
+        sepCount++;
+
+        QString line2 = buffer.section("\n", sepCount, sepCount);
+        if (line2 == "")
+            break;
+
+        sepCount++;
+
+        // each line contains ://
+        // header:extension,channelNum - channelName rtsp://channelUrl
+        //#EXTINF:0,2 - France 2 rtsp://mafreebox.freebox.fr/freeboxtv/201
+
+        QString lineHead;
+        QString extension;
+        QString channelNum;
+        QString channelName;
+
+        int pos = 0;
+        int oldPos = 0;
+
+        pos = line1.find(":", oldPos);
+        if (pos<0)
+        {
+            VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
+            return;
+        }
+        lineHead = line1.mid(0, pos);
+
+        if (lineHead != "#EXTINF")
+        {
+            VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
+            return;
+        }
+
+        oldPos = pos + 1;
+        pos = line1.find(",", oldPos);
+        if (pos<0)
+        {
+            VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
+            return;
+        }
+        extension = line1.mid(oldPos, pos - oldPos);
+
+        oldPos = pos + 1;
+        pos = line1.find(" ", oldPos);
+        if (pos<0)
+        {
+            VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
+            return;
+        }
+        channelNum = line1.mid(oldPos, pos - oldPos);
+
+        oldPos = pos + 1;
+        pos = line1.find("- ", oldPos);
+        if (pos<0)
+        {
+            VERBOSE(VB_IMPORTANT,QString("Freebox # Invalid header while retrieve channel list.!"));
+            return;
+        }
+        channelName = line1.mid(pos + 2, line1.length());
+
+        QString channelUrl = line2;
+
+        // save all this information in map for quick access
+        bool ok;
+        int channelNumI = channelNum.toInt( &ok, 10 );
+
+        QString channelNameN = normalize(channelName);
+
+        m_freeboxchannelIds[channelNumI] = m_freeboxchannelcount;
+        m_freeboxchannelUrl[m_freeboxchannelcount] = channelUrl;
+        m_freeboxchannelNames[m_freeboxchannelcount] = channelName;
+        m_freeboxchannelNamesN[m_freeboxchannelcount] = channelNameN;
+
+        m_freeboxchannelcount++;
+    }
+
+    // Channel list is ready.
+    m_channelListReady = true;
+
+    // Change channel if delayed request is available
+    if (m_requestChannel != "")
+    {
+        SetChannelByString(m_requestChannel);
+        m_requestChannel = "";
+    }
+}
+
+
+/*
+ * Map a channel number to the corresponding rtsp URL
+ */
+
+QString FreeboxChannel::GetChannelUrlFromNumber(const QString& channelnumber)
+{
+    MSqlQuery query(MSqlQuery::InitCon());
+
+    query.prepare("SELECT name,freqid "
+        "FROM channel,cardinput "
+        "WHERE "
+        "channel.sourceid = cardinput.sourceid AND "
+        "cardinput.cardid = :CARDID AND "
+        "channel.channum = :CHANNUM");
+
+    query.bindValue(":CARDID", m_cardid);
+    query.bindValue(":CHANNUM", channelnumber);
+
+    if (query.exec() && query.isActive() && query.size() > 0)
+    {
+        query.next();
+        QString chanName = query.value(0).toString();
+
+        // if we have a FreqID in the table, use this as the real freebox channel number
+        int mFreqId = query.value(1).toInt();
+        if (mFreqId!=0)
+        {
+            int channelI = m_freeboxchannelIds[mFreqId];
+            return m_freeboxchannelUrl[channelI];
+        }
+
+        // if no freqID, try to map the chanName to an existing channel name
+        for (int i=0;i<m_freeboxchannelcount;i++)
+        {
+            if (m_freeboxchannelNamesN[i] == chanName)
+            {
+                return m_freeboxchannelUrl[i];
+            }
+        }
+
+        return "";
+    }
+    return "";
+}
+
+
+/*
+ * Search for default channel
+ */
+
+QString FreeboxChannel::GetDefaultChannel()
+{
+    MSqlQuery query(MSqlQuery::InitCon());
+    query.prepare("SELECT channum "
+        "FROM channel,cardinput "
+        "WHERE "
+        "channel.sourceid = cardinput.sourceid AND "
+        "cardinput.cardid = :CARDID "
+        "ORDER BY channum limit 1");
+
+    query.bindValue(":CARDID", m_cardid);
+
+    if (query.exec() && query.isActive() && query.size() > 0)
+    {
+        query.next();
+        return query.value(0).toString();
+    }
+    return "";
+}
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxchannel.h mythtv-SVN/libs/libmythtv/freeboxchannel.h
--- mythtv-SVN.orig/libs/libmythtv/freeboxchannel.h	1970-01-01 01:00:00.000000000 +0100
+++ mythtv-SVN/libs/libmythtv/freeboxchannel.h	2006-04-16 19:04:23.000000000 +0200
@@ -0,0 +1,85 @@
+#ifndef FREEBOXCHANNEL_H
+#define FREEBOXCHANNEL_H
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qhttp.h>
+#include <qobject.h>
+#include <qthread.h>
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "tv_rec.h"
+#include "channelbase.h"
+#include "sitypes.h"
+
+
+class FreeboxChannel:public QObject, public ChannelBase
+{
+  Q_OBJECT public:
+    FreeboxChannel (TVRec * parent, int cardid);
+    ~FreeboxChannel (void)
+    {
+    }
+
+
+    bool Open ();
+    void Close ();
+    bool SwitchToInput (const QString & inputname, const QString & chan);
+    bool SetChannelByString (const QString & chan);
+    bool IsOpen (void) const;
+
+
+    QString GetCurrentChannelUrl ();
+
+
+    bool SwitchToInput (int newcapchannel, bool setstarting)
+    {
+      (void) newcapchannel;
+      (void) setstarting;
+      return false;
+    }
+
+    QString GetChannelUrlFromNumber (const QString & channelnumber);
+    QString GetDefaultChannel ();
+
+  signals:
+    void ChannelChanged ();
+
+    public slots:void HttpRequestDone (bool error);
+
+  private:
+    void LoadChannels ();
+    QString normalize (QString channelName);
+
+    void Log (QString string);
+
+    QHttp *http;
+
+    bool m_channelListReady;
+    QString m_requestChannel;
+    QString m_lastChannel;
+    int m_cardid;
+
+    // the rtsp url for the current channel
+    QString m_currenturl;
+
+    // number of channel support by freebox
+    int m_freeboxchannelcount;
+
+    // map channelNum to channel index in table
+    QMap < int, int >m_freeboxchannelIds;
+
+    // map channel index to channel url
+    QMap < int, QString > m_freeboxchannelUrl;
+
+    // map channel index to channel name
+    QMap < int, QString > m_freeboxchannelNames;
+
+    // map channel index to channel normalize name
+    QMap < int, QString > m_freeboxchannelNamesN;
+};
+
+#endif
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.cpp mythtv-SVN/libs/libmythtv/freeboxrecorder.cpp
--- mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.cpp	1970-01-01 01:00:00.000000000 +0100
+++ mythtv-SVN/libs/libmythtv/freeboxrecorder.cpp	2006-04-16 19:04:23.000000000 +0200
@@ -0,0 +1,448 @@
+/**
+ *  FreeboxRecorder
+ *  Copyright (c) 2005 by Levent G?u (mythtv@feature-it.com)
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#include <iostream>
+using namespace std;
+
+#include <pthread.h>
+#include "RingBuffer.h"
+#include "mythcontext.h"
+#include "freeboxrecorder.h"
+#include "freeboxchannel.h"
+#include <qhttp.h>
+#include <qobject.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netinet/in.h>          // For sockaddr_in on OS X
+
+void subsessionAfterPlaying(void *clientData);
+void subsessionByeHandler(void *clientData);
+
+FreeboxRecorder::FreeboxRecorder(TVRec *rec, FreeboxChannel *channel)
+	       : DTVRecorder(rec, "FreeboxRecorder"),
+                 m_channel(channel)
+{
+    // the var will be use to abort current rtsp session
+    _abort_rtsp = new char();
+
+    connect (m_channel, SIGNAL(ChannelChanged()),
+             this,      SLOT(  ChannelChanged()));
+}
+
+
+bool FreeboxRecorder::Open()
+{
+    // Start a new RTSP flow with current channel
+    pthread_create(&start_thread, NULL, FreeboxRecorder::StartRtspS, this);
+    return true;
+}
+
+
+void FreeboxRecorder::Close()
+{
+    // ask for RTSP shutdown setting abort_rstp=1, and wait effective shutdown on mutex
+    waitShutdown = new QWaitCondition();
+    *_abort_rtsp = 1;
+    _request_recording = false;
+    waitShutdown->wait();
+
+    if (session == NULL) return;
+
+    // Ensure RTSP cleanup, remove old RTSP session
+    MediaSubsessionIterator iter(*session);
+    MediaSubsession* subsession;
+    while ((subsession = iter.next()) != NULL)
+    {
+        Medium::close(subsession->sink);
+        subsession->sink = NULL;
+    }
+
+    if (session == NULL) return;
+
+    rtspClient->teardownMediaSession(*session);
+
+    // Close all RTSP descriptor
+    Medium::close(session);
+    Medium::close(rtspClient);
+}
+
+
+void FreeboxRecorder::ChannelChanged()
+{
+    // Channel change, we need to close current RTSP flow, and open a new one
+    Close();
+    Open();
+}
+
+
+void FreeboxRecorder::SetOptionsFromProfile(RecordingProfile *profile,
+                                            const QString &videodev,
+                                            const QString &audiodev,
+                                            const QString &vbidev)
+{
+    (void)videodev;
+    (void)audiodev;
+    (void)vbidev;
+    (void)profile;
+}
+
+
+void FreeboxRecorder::StartRecording()
+{
+    // Open RTSP flow for current channel
+    Open();
+
+    _request_recording = true;
+    _recording = true;
+    _request_abort = false;
+
+    // wait until recorder abot
+    while(_request_recording)
+    {
+        if (_request_abort)
+            break;
+
+        usleep(1000);
+    }
+}
+
+
+void FreeboxRecorder::StopRecording(void)
+{
+    // Close the current RTSP flow
+    Close();
+}
+
+
+void *FreeboxRecorder::StartRtspS(void *param)
+{
+    FreeboxRecorder *recorder = (FreeboxRecorder*)param;
+    recorder->StartRtsp();
+    return NULL;
+}
+
+
+/*
+ * Start a new RTSP session for the current channel
+ */
+
+void FreeboxRecorder::StartRtsp()
+{
+    // Retrieve the RTSP channel URL
+    QString url = m_channel->GetCurrentChannelUrl();
+
+    VERBOSE(VB_IMPORTANT, QString("Freebox # URL: %1").arg(url));
+    //
+    // Begin by setting up our usage environment:
+    TaskScheduler* scheduler = BasicTaskScheduler::createNew();
+    env = BasicUsageEnvironment::createNew(*scheduler);
+
+    // Create our client object:
+    rtspClient = RTSPClient::createNew(*env, 0, "myRTSP", 0);
+    if (rtspClient == NULL)
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create RTSP client: %1").arg(env->getResultMsg()));
+        shutdown();
+    }
+
+    // Setup URL for the current session
+    char* sdpDescription = rtspClient->describeURL(url);
+    rtspClient->describeStatus();
+
+    if (sdpDescription == NULL)
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to get a SDP description from URL: %1 %2").arg(url).arg(env->getResultMsg()));
+        shutdown();
+    }
+
+    // Create a media session object from this SDP description:
+    session = MediaSession::createNew(*env, sdpDescription);
+    delete[] sdpDescription;
+    if (session == NULL)
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create a MediaSession object from the SDP description: %1").arg(env->getResultMsg()));
+        shutdown();
+    }
+    else if (!session->hasSubsessions())
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # This session has no media subsessions"));
+        shutdown();
+    }
+
+    // Then, setup the "RTPSource"s for the session:
+    MediaSubsessionIterator iter(*session);
+    MediaSubsession *subsession;
+    Boolean madeProgress = False;
+    while ((subsession = iter.next()) != NULL)
+    {
+        if (!subsession->initiate(-1))
+        {
+            VERBOSE(VB_IMPORTANT, QString("Freebox # Unable to create receiver for: %1 / %2 subsession: %3").arg(subsession->mediumName()).arg(subsession->codecName()).arg(env->getResultMsg()));
+        }
+        else
+        {
+            madeProgress = True;
+
+            if (subsession->rtpSource() != NULL)
+            {
+                                 // 1 second
+                unsigned const thresh = 1000000;
+                subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
+            }
+        }
+    }
+
+    if (!madeProgress) shutdown();
+
+    // Perform additional 'setup' on each subsession, before playing them:
+    madeProgress = false;
+    iter.reset();
+    while ((subsession = iter.next()) != NULL)
+    {
+                                 // port # was not set
+        if (subsession->clientPortNum() == 0) continue;
+
+        if (rtspClient->setupMediaSubsession(*subsession, False, false))
+        {
+            madeProgress = True;
+        }
+        else
+        {
+            VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to setup: %1 %2 : %3").arg(subsession->mediumName()).arg(subsession->codecName()).arg(env->getResultMsg()));
+        }
+    }
+
+    if (!madeProgress) shutdown();
+
+    // Create and start "FileSink"s for each subsession:
+    // FileSink while receive Mpeg2 TS Data & will feed them to mythtv
+    madeProgress = False;
+    iter.reset();
+    while ((subsession = iter.next()) != NULL)
+    {
+                                 // was not initiated
+        if (subsession->readSource() == NULL) continue;
+
+        FreeboxSink* FreeboxSink = FreeboxSink::createNew(*env, this);
+
+        subsession->sink = FreeboxSink;
+        if (subsession->sink == NULL)
+        {
+            VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create sink: %1").arg(env->getResultMsg()));
+        }
+
+        subsession->sink->startPlaying(*(subsession->readSource()),  subsessionAfterPlaying, new FreeboxData(this, subsession));
+
+        if (subsession->rtcpInstance() != NULL)
+        {
+            subsession->rtcpInstance()->setByeHandler(subsessionByeHandler, new FreeboxData(this, subsession));
+        }
+
+        madeProgress = True;
+    }
+
+    if (!madeProgress) shutdown();
+
+    // Setup player
+    if (!(rtspClient->playMediaSession(*session)))
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to start playing session: %1").arg(env->getResultMsg()));
+        shutdown();
+    }
+
+    request_pause = false;
+    paused = false;
+    _request_recording = true;
+    _recording = true;
+    *_abort_rtsp=0;
+
+    // Go into main RTSP loop, feeding data to mythtv
+                                 // does not return
+    env->taskScheduler().doEventLoop(_abort_rtsp);
+
+    // Event loop exists, the recording finish
+    FinishRecording();
+    _recording = false;
+
+    // wakeUp everibody
+    waitShutdown->wakeAll();
+}
+
+
+/*
+ * Find a TS Header in flow
+ */
+int FreeboxRecorder::findTSHeader(unsigned char *data, unsigned dataSize)
+{
+    unsigned int pos = 0;
+
+    while (pos < dataSize)
+    {
+        if (data[pos] == 0x47)
+            return pos;
+        pos++;
+    }
+    return -1;
+}
+
+
+/*
+ * Feed date from RTSP flow to mythtv
+ */
+void FreeboxRecorder::addData(unsigned char* data, unsigned dataSize, struct timeval )
+{
+    unsigned int readIndex = 0;
+
+    // data may be compose from more than one packet, loop to consume all data
+    while (readIndex < dataSize)
+    {
+        // If recorder is pause, stop there
+        if (PauseAndWait())
+        {
+            return;
+        }
+
+        // Find the next TS Header in data
+        int tsPos = findTSHeader(data + readIndex, dataSize);
+
+        // if no TS, something bad happens
+        if (tsPos == -1)
+        {
+            VERBOSE(VB_IMPORTANT, QString("FREEBOX: No TS header."));
+            break;
+        }
+
+        // if TS Header not at start of data, we receive out of sync data
+        if (tsPos > 0)
+        {
+            VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1, not in sync.").arg(tsPos));
+        }
+
+        // Check if the next packet in buffer is complete : packet size is 188 bytes long
+        if ((dataSize - tsPos) < 188)
+        {
+            VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1 but packet not yet complete.").arg(tsPos));
+            break;
+        }
+
+        // Cast current found TS Packet to TSPacket structure
+        const void     *newData     = data + tsPos + readIndex;
+        const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(newData);
+
+        // Feed current packet to myth
+        _buffer_packets = !FindKeyframes(tspacket);
+        BufferedWrite(*tspacket);
+
+        // follow to next packet
+        readIndex += tsPos + TSPacket::SIZE;
+
+    }
+}
+
+
+void FreeboxRecorder::shutdown(int )
+{
+}
+
+
+void subsessionAfterPlaying(void *clientData)
+{
+    FreeboxData *myData = (FreeboxData*)clientData;
+    myData->freeboxRecorder->SubsessionAfterPlaying(myData->mediaSubSession);
+}
+
+
+void subsessionByeHandler(void *clientData)
+{
+    FreeboxData *myData = (FreeboxData*)clientData;
+    myData->freeboxRecorder->SubsessionByeHandler(myData->mediaSubSession);
+}
+
+
+void FreeboxRecorder::SubsessionAfterPlaying(MediaSubsession* subsession)
+{
+    Medium::close(subsession->sink);
+    subsession->sink = NULL;
+
+    MediaSession& session = subsession->parentSession();
+    MediaSubsessionIterator iter(session);
+    while ((subsession = iter.next()) != NULL)
+    {
+        if (subsession->sink != NULL) return;
+    }
+
+    shutdown(0);
+
+}
+
+
+void FreeboxRecorder::SubsessionByeHandler(MediaSubsession* subsession)
+{
+    subsessionAfterPlaying(subsession);
+}
+
+/*
+ * Helper class use to receive RTSP data from socket.
+ */
+
+FreeboxSink::FreeboxSink(UsageEnvironment& pEnv, FreeboxRecorder *pRecorder) : MediaSink(pEnv)
+{
+    recorder = pRecorder;
+    env = &pEnv;
+
+    // Setup the data buffer
+    fBufferSize = 20000;
+    fBuffer = new unsigned char[fBufferSize];
+}
+
+
+FreeboxSink::~FreeboxSink()
+{
+    // free the data buffer
+    delete[] fBuffer;
+}
+
+
+FreeboxSink* FreeboxSink::createNew(UsageEnvironment& env, FreeboxRecorder *pRecorder)
+{
+    FreeboxSink* newSink = new FreeboxSink(env, pRecorder);
+    return newSink;
+}
+
+
+Boolean FreeboxSink::continuePlaying()
+{
+    if (fSource == NULL) return False;
+
+    fSource->getNextFrame(fBuffer, fBufferSize, afterGettingFrame, this, onSourceClosure, this);
+
+    return True;
+}
+
+
+void FreeboxSink::afterGettingFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/,struct timeval presentationTime, unsigned /*durationInMicroseconds*/)
+{
+
+    FreeboxSink* sink = (FreeboxSink*)clientData;
+    sink->afterGettingFrame1(frameSize, presentationTime);
+}
+
+
+void FreeboxSink::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime)
+{
+    addData(fBuffer, frameSize, presentationTime);
+    continuePlaying();
+}
+
+
+void FreeboxSink::addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime)
+{
+    recorder->addData(data, dataSize, presentationTime);
+}
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.h mythtv-SVN/libs/libmythtv/freeboxrecorder.h
--- mythtv-SVN.orig/libs/libmythtv/freeboxrecorder.h	1970-01-01 01:00:00.000000000 +0100
+++ mythtv-SVN/libs/libmythtv/freeboxrecorder.h	2006-04-16 19:04:23.000000000 +0200
@@ -0,0 +1,148 @@
+/**
+ *  DBOX2Recorder
+ *  Copyright (c) 2005 by Levent Gndogdu
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef FREEBOXRECORDER_H_
+#define FREEBOXRECORDER_H_
+
+#include "dtvrecorder.h"
+#include <time.h>
+#include "freeboxchannel.h"
+#include "sitypes.h"
+#include "qhttp.h"
+#include "mpeg/tspacket.h"
+
+
+#include "BasicUsageEnvironment.hh"
+#include "GroupsockHelper.hh"
+#include "liveMedia.hh"
+
+/**
+ *  Constructs a FreeboxRecorder
+ */
+
+#if defined(__WIN32__) || defined(_WIN32)
+#define snprintf _snprintf
+#else
+#include <signal.h>
+#define USE_SIGNALS 1
+#endif
+
+
+
+class FreeboxRecorder:public DTVRecorder
+{
+  Q_OBJECT public:
+    FreeboxRecorder (TVRec * rec, FreeboxChannel * channel);
+    ~FreeboxRecorder ()
+    {
+    }
+
+
+    void StartRecording (void);
+    void StopRecording (void);
+    bool Open (void);
+    void Close ();
+
+    void SetOptionsFromProfile (RecordingProfile * profile,
+                                const QString & videodev,
+                                const QString & audiodev,
+                                const QString & vbidev);
+
+    void SubsessionAfterPlaying (MediaSubsession * subsession);
+    void SubsessionByeHandler (MediaSubsession * subsession);
+
+    // Callback function to add MPEG2 TS data
+    void addData (unsigned char *data, unsigned dataSize,
+                  struct timeval presentationTime);
+
+    // Look for TS Header in data
+    int findTSHeader (unsigned char *data, unsigned dataSize);
+
+
+    public slots:void ChannelChanged ();
+
+
+  private:
+    UsageEnvironment * env;
+    RTSPClient *rtspClient;
+    MediaSession *session;
+
+    // var to check if we need to abort current rtsp session
+    char *_abort_rtsp;
+
+    // request abort for StartRecording Thread         
+    bool _request_abort;
+
+    // Call back function to start RTSP Flow
+    static void *StartRtspS (void *param);
+    void StartRtsp ();
+
+    void shutdown (int exitCode = 1);
+
+    // Current channel         
+    FreeboxChannel *m_channel;
+
+    // Mutex : use to make sure that current RTSP thread as stop
+    QWaitCondition *waitShutdown;
+
+    // The current RTSP thread
+    pthread_t start_thread;
+};
+
+
+/*
+ * Helper class use for static Callback handler
+ */
+class FreeboxData
+{
+  public:
+    FreeboxData (FreeboxRecorder * pFreeboxRecorder,
+                 MediaSubsession * pMediaSubSession)
+    {
+        freeboxRecorder = pFreeboxRecorder;
+        mediaSubSession = pMediaSubSession;
+    }
+
+    FreeboxRecorder *freeboxRecorder;
+    MediaSubsession *mediaSubSession;
+};
+
+
+/*
+ * Helper class use to receive RTSP data from socket.
+ */
+class FreeboxSink:public MediaSink
+{
+  public:
+    static FreeboxSink *createNew (UsageEnvironment & env,
+                                   FreeboxRecorder * pRecorder);
+
+    // Callback function when rtsp data are ready
+    void addData (unsigned char *data, unsigned dataSize,
+                  struct timeval presentationTime);
+
+  protected:
+      FreeboxSink (UsageEnvironment & env, FreeboxRecorder * pRecorder);
+      virtual ~ FreeboxSink ();
+
+    static void afterGettingFrame (void *clientData, unsigned frameSize,
+                                   unsigned numTruncatedBytes,
+                                   struct timeval presentationTime,
+                                   unsigned durationInMicroseconds);
+    virtual void afterGettingFrame1 (unsigned frameSize,
+                                     struct timeval presentationTime);
+
+  private:
+      virtual Boolean continuePlaying ();
+
+    unsigned char *fBuffer;
+    unsigned fBufferSize;
+    UsageEnvironment *env;
+    FreeboxRecorder *recorder;
+    int bufferIndex;
+
+};
+#endif
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/libmythtv.pro mythtv-SVN/libs/libmythtv/libmythtv.pro
--- mythtv-SVN.orig/libs/libmythtv/libmythtv.pro	2006-04-18 09:06:59.000000000 +0200
+++ mythtv-SVN/libs/libmythtv/libmythtv.pro	2006-04-18 09:09:38.000000000 +0200
@@ -347,6 +347,10 @@
     using_dbox2:SOURCES += dbox2recorder.cpp dbox2channel.cpp dbox2epg.cpp
     using_dbox2:HEADERS += dbox2recorder.h dbox2channel.h dbox2epg.h
     using_dbox2:DEFINES += USING_DBOX2
+    
+    # Support for FreeBox
+    using_freebox:SOURCES += freeboxrecorder.cpp freeboxchannel.cpp
+    using_freebox:HEADERS += freeboxrecorder.h freeboxchannel.h
 
     # Support for HDHomeRun box
     using_hdhr {
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/tv_rec.cpp mythtv-SVN/libs/libmythtv/tv_rec.cpp
--- mythtv-SVN.orig/libs/libmythtv/tv_rec.cpp	2006-04-18 09:07:02.000000000 +0200
+++ mythtv-SVN/libs/libmythtv/tv_rec.cpp	2006-04-18 09:36:41.000000000 +0200
@@ -73,6 +73,11 @@
 #include "dbox2channel.h"
 #endif
 
+#ifdef USING_FREEBOX
+#include "freeboxrecorder.h"
+#include "freeboxchannel.h"
+#endif
+
 #ifdef USING_HDHOMERUN
 #include "hdhrrecorder.h"
 #include "hdhrchannel.h"
@@ -188,6 +193,16 @@
         init_run = true;
 #endif
     }
+    else if (genOpt.cardtype == "FREEBOX")
+    {
+#ifdef USING_FREEBOX
+        channel = new FreeboxChannel(this, cardid);
+        if(!channel->Open())
+            return false;
+        InitChannel(genOpt.defaultinput, startchannel);
+        init_run = true;
+#endif
+    }    
     else if (genOpt.cardtype == "HDHOMERUN")
     {
 #ifdef USING_HDHOMERUN
@@ -310,6 +325,11 @@
         GetDBox2Channel()->deleteLater();
     else
 #endif // USING_DBOX2
+#ifdef USING_FREEBOX
+    if (GetFreeboxChannel())
+        GetFreeboxChannel()->deleteLater();
+    else
+#endif // USING_FREEBOX
     if (channel)
         delete channel;
     channel = NULL;
@@ -870,6 +890,12 @@
         recorder->SetOption("httpport", dboxOpt.httpport);
 #endif // USING_DBOX2
     }
+    else if (genOpt.cardtype == "FREEBOX")
+    {
+#ifdef USING_FREEBOX
+        recorder = new FreeboxRecorder(this, GetFreeboxChannel());
+#endif // USING_FREEBOX
+    }
     else if (genOpt.cardtype == "HDHOMERUN")
     {
 #ifdef USING_HDHOMERUN
@@ -1094,6 +1120,15 @@
 #endif // USING_DBOX2
 }
 
+FreeboxChannel *TVRec::GetFreeboxChannel(void)
+{
+#ifdef USING_FREEBOX
+    return dynamic_cast<FreeboxChannel*>(channel);
+#else
+    return NULL;
+#endif // USING_FREEBOX
+}
+ 
 HDHRChannel *TVRec::GetHDHRChannel(void)
 {
 #ifdef USING_HDHOMERUN
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/tv_rec.h mythtv-SVN/libs/libmythtv/tv_rec.h
--- mythtv-SVN.orig/libs/libmythtv/tv_rec.h	2006-04-18 09:07:02.000000000 +0200
+++ mythtv-SVN/libs/libmythtv/tv_rec.h	2006-04-18 09:15:58.000000000 +0200
@@ -36,6 +36,7 @@
 
 class ChannelBase;
 class DBox2Channel;
+class FreeboxChannel;
 class HDHRChannel;
 class DVBChannel;
 class Channel;
@@ -287,10 +288,11 @@
     bool CreateChannel(const QString &startChanNum);
     void InitChannel(const QString &inputname, const QString &startchannel);
     void CloseChannel(void);
-    DBox2Channel *GetDBox2Channel(void);
-    HDHRChannel  *GetHDHRChannel(void);
-    DVBChannel   *GetDVBChannel(void);
-    Channel      *GetV4LChannel(void);
+    DBox2Channel   *GetDBox2Channel(void);
+    HDHRChannel    *GetHDHRChannel(void);
+    DVBChannel     *GetDVBChannel(void);
+    FreeboxChannel *GetFreeboxChannel(void);
+    Channel        *GetV4LChannel(void);
 
     void SetupSignalMonitor(bool enable_table_monitoring, bool notify);
     bool SetupDTVSignalMonitor(void);
diff -u -r -N mythtv-SVN.orig/libs/libmythtv/videosource.cpp mythtv-SVN/libs/libmythtv/videosource.cpp
--- mythtv-SVN.orig/libs/libmythtv/videosource.cpp	2006-04-18 09:07:01.000000000 +0200
+++ mythtv-SVN/libs/libmythtv/videosource.cpp	2006-04-18 09:36:02.000000000 +0200
@@ -914,6 +914,19 @@
     CaptureCard &parent;
  };
 
+class FreeboxConfigurationGroup: public VerticalConfigurationGroup {
+  public:
+    FreeboxConfigurationGroup(CaptureCard& a_parent):
+        ConfigurationGroup(false, true, false, false),
+        VerticalConfigurationGroup(false, true, false, false),
+        parent(a_parent) 
+    {
+        setUseLabel(false);
+    };
+  private:
+    CaptureCard& parent;
+};
+
 class HDHomeRunDeviceID: public LineEditSetting, public CCSetting
 {
   public:
@@ -927,6 +940,7 @@
     }
 };
 
+
 class HDHomeRunTunerIndex: public ComboBoxSetting, public CCSetting
 {
   public:
@@ -1076,6 +1090,10 @@
 #ifdef USING_HDHOMERUN
     addTarget("HDHOMERUN", new HDHomeRunConfigurationGroup(parent));
 #endif // USING_HDHOMERUN
+
+#ifdef USING_FREEBOX
+    addTarget("FREEBOX", new FreeboxConfigurationGroup(parent));
+#endif // USING_FREEBOX
 }
 
 void CaptureCardGroup::triggerChanged(const QString& value) 
@@ -1190,6 +1208,11 @@
         QObject::tr("DBox2 TCP/IP cable box"), "DBOX2");
 #endif // USING_DBOX2
 
+#ifdef USING_FREEBOX
+    setting->addSelection(
+        QObject::tr("Freebox"), "FREEBOX");
+#endif // USING_FREEBOX
+
 #ifdef USING_HDHOMERUN
     setting->addSelection(
         QObject::tr("HDHomeRun DTV tuner box"), "HDHOMERUN");
diff -u -r -N mythtv-SVN.orig/settings.pro mythtv-SVN/settings.pro
--- mythtv-SVN.orig/settings.pro	2006-04-18 09:07:07.000000000 +0200
+++ mythtv-SVN/settings.pro	2006-04-16 19:05:43.000000000 +0200
@@ -79,6 +79,7 @@
 EXTRA_LIBS += $$CONFIG_AUDIO_JACK_LIBS
 EXTRA_LIBS += $$CONFIG_FIREWIRE_LIBS
 EXTRA_LIBS += $$CONFIG_DIRECTFB_LIBS
+EXTRA_LIBS += $$CONFIG_LIVE_LIBS
 
 EXTRA_LIBS += $$LOCAL_LIBDIR_OGL
 EXTRA_LIBS += $$LOCAL_LIBDIR_X11
