Index: configure
===================================================================
--- configure	(revision 10149)
+++ configure	(working copy)
@@ -54,6 +54,7 @@
 lirc="yes"
 joystick_menu="yes"
 firewire_cable_box="yes"
+freebox_box="yes"
 dbox2_dvb_box="yes"
 ip_network_recorder="yes"
 hdhomerun_box="yes"
@@ -178,6 +179,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 "  --disable-freebox        disable 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-crciprec       disable support for Network Recorder"
@@ -819,6 +823,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"
@@ -2036,6 +2048,42 @@
     fi
 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."
+            freebox_box="no"
+        fi
+    else
+        if test ! -f "$live_lib_dir/liveMedia/libliveMedia.a"; then
+            echo "Unable to find Live Media library."
+            freebox_box="no"
+        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."
+            freebox_box="no"
+        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."
+                freebox_box="no"
+            fi
+        fi
+    fi
+fi
+
 lamemp3="no"
 if has_library libmp3lame ; then
     if has_header lame/lame.h ; then
@@ -2322,6 +2370,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"
   echo "CRC Ip Rec sup.  $ip_network_recorder"
 fi
@@ -2984,6 +3033,13 @@
   CCONFIG="$CCONFIG using_ip_rec"
 fi
 
+if test x"$freebox_box" = x"yes" ; then
+    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"$lirc" = x"yes" ; then
   CCONFIG="$CCONFIG using_lirc"
   echo "CONFIG_LIRC_LIBS=-llirc_client" >> $MYTH_CONFIG_MAK
Index: libs/libmythtv/freeboxchannel.h
===================================================================
--- libs/libmythtv/freeboxchannel.h	(revision 0)
+++ libs/libmythtv/freeboxchannel.h	(revision 0)
@@ -0,0 +1,48 @@
+/** -*- Mode: c++ -*-
+ *  FreeboxChannel
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef FREEBOXCHANNEL_H
+#define FREEBOXCHANNEL_H
+
+#include "freeboxchannel_util.h"
+#include "channelbase.h"
+
+class FreeboxRecorder;
+
+class FreeboxChannel : public ChannelBase
+{
+    friend class FreeboxRecorder;
+  public:
+    FreeboxChannel(TVRec *parent, const QString &videodev);
+    ~FreeboxChannel(void) { }
+
+    bool Open(void);
+    void Close(void) { m_isopen = false; }
+
+    bool    IsOpen(void) const { return m_isopen; }
+
+    bool SwitchToInput(const QString &inputname, const QString &channum);
+    bool SwitchToInput(int inputNum, bool setstarting);
+    bool SetChannelByString(const QString &channum);
+
+    void SetRecorder(FreeboxRecorder *rec)
+        { QMutexLocker locker(&m_lock); m_recorder = rec; }
+
+  private:
+    FBChanInfo GetChanInfo(const QString &channum, uint sourceid = 0) const;
+    FBChanInfo GetCurrentChanInfo(void) const
+        { return GetChanInfo(curchannelname); }
+
+    QString               m_videodev;
+    FreeboxRecorder      *m_recorder;
+    bool                  m_isopen;
+    fbox_chan_map_t       m_freeboxchannels;
+    mutable QMutex        m_lock;
+};
+
+#endif // FREEBOXCHANNEL_H
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 10149)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -373,6 +373,13 @@
     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 (http://adsl.free.fr/)
+    using_freebox:SOURCES += freeboxrecorder.cpp freeboxmediasink.cpp
+    using_freebox:SOURCES += freeboxchannel.cpp  freeboxchannel_util.cpp
+    using_freebox:HEADERS += freeboxrecorder.h   freeboxmediasink.h
+    using_freebox:HEADERS += freeboxchannel.h    freeboxchannel_util.h
+    using_freebox:DEFINES += USING_FREEBOX
 
     # Support for HDHomeRun box
     using_hdhr {
Index: libs/libmythtv/freeboxchannel.cpp
===================================================================
--- libs/libmythtv/freeboxchannel.cpp	(revision 0)
+++ libs/libmythtv/freeboxchannel.cpp	(revision 0)
@@ -0,0 +1,155 @@
+/** -*- Mode: c++ -*-
+ *  FreeboxChannel
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#include "freeboxchannel.h"
+#include "freeboxrecorder.h"
+#include "libmythtv/tv_rec.h"
+
+#define LOC QString("FBChan%1: ").arg(GetCardID())
+#define LOC_ERR QString("FBChan%1, Error: ").arg(GetCardID())
+
+FreeboxChannel::FreeboxChannel(TVRec *parent, const QString &videodev)
+    : ChannelBase(parent),
+      m_videodev(videodev),   m_recorder(NULL),
+      m_isopen(false),        m_lock(true)
+{
+}
+
+bool FreeboxChannel::Open(void)
+{
+    QMutexLocker locker(&m_lock);
+
+    if (InitializeInputs())
+        return false;
+
+    m_freeboxchannels = FBChannelFetcher::GetChannels(m_videodev);
+
+    return m_isopen = m_freeboxchannels.size();
+}
+
+bool FreeboxChannel::SwitchToInput(const QString &inputname,
+                                   const QString &channum)
+{
+    QMutexLocker locker(&m_lock);
+
+    int inputNum = GetInputByName(inputname);
+    if (inputNum < 0)
+        return false;
+
+    return SetChannelByString(channum);
+}
+
+bool FreeboxChannel::SwitchToInput(int inputNum, bool setstarting)
+{
+    QMutexLocker locker(&m_lock);
+
+    InputMap::const_iterator it = inputs.find(inputNum);
+    if (it == inputs.end())
+        return false;
+
+    QString channum = (*it)->startChanNum;
+
+    if (setstarting)
+        return SetChannelByString(channum);
+
+    return true;
+}
+
+bool FreeboxChannel::SetChannelByString(const QString &channum)
+{
+    QMutexLocker locker(&m_lock);
+
+    // Verify that channel exists
+    if (!GetChanInfo(channum).isValid())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("SetChannelByString(%1)").arg(channum) +
+                " Invalid channel");
+        return false;
+    }
+
+    // Set the channel..
+    curchannelname = channum;
+
+    // Send signal to recorder that channel has changed.
+    if (m_recorder)
+        m_recorder->ChannelChanged();
+
+    return true;
+}
+
+FBChanInfo FreeboxChannel::GetChanInfo(const QString &channum,
+                                       uint sourceid) const
+{
+    QMutexLocker locker(&m_lock);
+
+    FBChanInfo dummy;
+    QString msg = LOC_ERR + QString("GetChanInfo(%1) failed").arg(channum);
+
+    if (channum.isEmpty())
+    {
+        VERBOSE(VB_IMPORTANT, msg);
+        return dummy;
+    }
+
+    if (!sourceid)
+    {
+        InputMap::const_iterator it = inputs.find(currentInputID);
+        if (it == inputs.end())
+        {
+            VERBOSE(VB_IMPORTANT, msg);
+            return dummy;
+        }
+        sourceid = (*it)->sourceid;
+    }
+
+    MSqlQuery query(MSqlQuery::InitCon());
+    query.prepare(
+        "SELECT freqid, xmltvid, name"
+        "FROM channel "
+        "WHERE channum  = :CHANNUM AND "
+        "      sourceid = :SOURCEID");
+
+    query.bindValue(":CHANNUM",  channum);
+    query.bindValue(":SOURCEID", sourceid);
+
+    if (!query.exec() || !query.isActive())
+    {
+        MythContext::DBError("fetching chaninfo", query);
+        VERBOSE(VB_IMPORTANT, msg);
+        return dummy;
+    }
+
+    while (query.next())
+    {
+        // Try to map freqid or name to a channel in the map
+        const QString freqid = query.value(0).toString();
+        fbox_chan_map_t::const_iterator it;
+        if (!freqid.isEmpty())
+        {
+            it = m_freeboxchannels.find(freqid);
+            if (it != m_freeboxchannels.end())
+                return *it;
+        }
+
+        // Try to map xmltvid or name to a channel in the map
+        const QString xmltvid = query.value(1).toString();
+        const QString name    = query.value(2).toString();
+        for (it = m_freeboxchannels.begin();
+             it != m_freeboxchannels.end(); ++it)
+        {
+            if ((*it).m_xmltvid == xmltvid)
+                return *it;
+            if ((*it).m_name == name)
+                return *it;
+        }
+    }
+
+    VERBOSE(VB_IMPORTANT, msg);
+    return dummy;
+}
+
+/* vim: set expandtab tabstop = 4 shiftwidth = 4: */
Index: libs/libmythtv/freeboxmediasink.cpp
===================================================================
--- libs/libmythtv/freeboxmediasink.cpp	(revision 0)
+++ libs/libmythtv/freeboxmediasink.cpp	(revision 0)
@@ -0,0 +1,70 @@
+/**
+ *  FreeboxMediaSink
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#include "freeboxmediasink.h"
+
+#include "freeboxrecorder.h"
+
+
+
+FreeboxMediaSink::FreeboxMediaSink(UsageEnvironment& pEnv,
+                                   FreeboxRecorder&  pRecorder,
+                                   unsigned          bufferSize) :
+    MediaSink(pEnv),
+    fBufferSize(bufferSize),
+    env(pEnv),
+    recorder(pRecorder)
+{
+    // Setup the data buffer
+    fBuffer = new unsigned char[fBufferSize];
+}
+
+FreeboxMediaSink::~FreeboxMediaSink()
+{
+    // free the data buffer
+    delete[] fBuffer;
+}
+
+FreeboxMediaSink* FreeboxMediaSink::createNew(UsageEnvironment& env,
+                                              FreeboxRecorder&  pRecorder,
+                                              unsigned          bufferSize)
+{
+    return new FreeboxMediaSink(env, pRecorder, bufferSize);
+}
+
+Boolean FreeboxMediaSink::continuePlaying()
+{
+    if (fSource == NULL) return False;
+
+    fSource->getNextFrame(fBuffer, fBufferSize,
+                          afterGettingFrame, this,
+                          onSourceClosure, this);
+    return True;
+}
+
+void FreeboxMediaSink::afterGettingFrame(void*          clientData,
+                                         unsigned       frameSize,
+                                         unsigned       /*numTruncatedBytes*/,
+                                         struct timeval presentationTime,
+                                         unsigned       /*durationInMicroseconds*/)
+{
+    FreeboxMediaSink* sink = (FreeboxMediaSink*)clientData;
+    sink->afterGettingFrame1(frameSize, presentationTime);
+}
+
+void FreeboxMediaSink::afterGettingFrame1(unsigned       frameSize,
+                                          struct timeval presentationTime)
+{
+    addData(fBuffer, frameSize, presentationTime);
+    continuePlaying();
+}
+
+void FreeboxMediaSink::addData(unsigned char* data,
+                               unsigned       dataSize,
+                               struct timeval presentationTime)
+{
+    recorder.addData(data, dataSize, presentationTime);
+}
Index: libs/libmythtv/dbcheck.cpp
===================================================================
--- libs/libmythtv/dbcheck.cpp	(revision 10149)
+++ libs/libmythtv/dbcheck.cpp	(working copy)
@@ -10,7 +10,7 @@
 #include "mythdbcon.h"
 
 /// This is the DB schema version expected by the running MythTV instance.
-const QString currentDatabaseVersion = "1142";
+const QString currentDatabaseVersion = "1143";
 
 static bool UpdateDBVersionNumber(const QString &newnumber);
 static bool performActualUpdate(const QString updates[], QString version,
@@ -2268,6 +2268,18 @@
 //"ALTER TABLE capturecard DROP COLUMN dvb_hw_decoder;" in 0.21
 //"ALTER TABLE cardinput DROP COLUMN  preference;" in 0.22
 
+  if (dbver == "1142")
+    {
+        const QString updates[] = {
+"INSERT INTO profilegroups SET name = 'Freebox Input', cardtype = 'Freebox', is_default = 1;",
+""
+};
+
+        if (!performActualUpdate(updates, "1143", dbver))
+            return false;
+    }
+
+
     return true;
 }
 
@@ -2328,6 +2340,7 @@
 "  dbox2_port int(10) unsigned NOT NULL default '31338',"
 "  dbox2_httpport int(10) unsigned NOT NULL default '80',"
 "  dbox2_host varchar(32) default NULL,"
+"  freebox_mrl varchar(64) DEFAULT 'http://mafreebox.freebox.fr/freeboxtv/playlist.m3u',"
 "  signal_timeout int(11) NOT NULL default '1000',"
 "  channel_timeout int(11) NOT NULL default '3000',"
 "  PRIMARY KEY  (cardid)"
@@ -2894,6 +2907,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);",
Index: libs/libmythtv/freeboxrecorder.cpp
===================================================================
--- libs/libmythtv/freeboxrecorder.cpp	(revision 0)
+++ libs/libmythtv/freeboxrecorder.cpp	(revision 0)
@@ -0,0 +1,431 @@
+/**
+ *  FreeboxRecorder
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#include "freeboxrecorder.h"
+
+#include <BasicUsageEnvironment.hh>
+#include <MediaSession.hh>
+#include <RTSPClient.hh>
+#include <qwaitcondition.h>
+#include <qmutex.h>
+
+#include "mpeg/tspacket.h"
+#include "freeboxchannel.h"
+#include "freeboxmediasink.h"
+
+
+
+// ============================================================================
+// FreeboxData : Helper class use for static Callback handler
+// ============================================================================
+class FreeboxData
+{
+  public:
+    FreeboxData(FreeboxRecorder *pFreeboxRecorder, MediaSubsession *pMediaSubSession) :
+        freeboxRecorder(pFreeboxRecorder),
+        mediaSubSession(pMediaSubSession)
+    {
+    }
+    
+    static void subsessionAfterPlayingCallback(void *clientData);
+    static void subsessionByeHandlerCallback(void *clientData);
+    void SubsessionAfterPlaying();
+    void SubsessionByeHandler();
+
+  private:
+    FreeboxRecorder *freeboxRecorder;
+    MediaSubsession *mediaSubSession;
+};
+
+void FreeboxData::subsessionAfterPlayingCallback(void *clientData)
+{
+    ((FreeboxData*)clientData)->SubsessionAfterPlaying();
+}
+
+void FreeboxData::subsessionByeHandlerCallback(void *clientData)
+{
+    ((FreeboxData*)clientData)->SubsessionByeHandler();
+}
+
+void FreeboxData::SubsessionAfterPlaying()
+{
+    MediaSubsession* subsession = mediaSubSession;
+    Medium::close(subsession->sink);
+    subsession->sink = NULL;
+
+    MediaSession& session = subsession->parentSession();
+    MediaSubsessionIterator iter(session);
+    while ((subsession = iter.next()) != NULL)
+    {
+        if (subsession->sink != NULL) return;
+    }
+}
+
+void FreeboxData::SubsessionByeHandler()
+{
+    SubsessionAfterPlaying();
+}
+
+
+
+class FreeboxRecorderImpl
+{
+  public:
+    FreeboxRecorderImpl(FreeboxChannel& channel) :
+        env(NULL),
+        rtspClient(NULL),
+        session(NULL),
+        _channel(channel),
+        _abort_rtsp(0),
+        _abort_recording(false)
+    {
+    }
+
+    // livemedia
+    UsageEnvironment* env;
+    RTSPClient* rtspClient;
+    MediaSession* session;
+
+    // Current channel
+    FreeboxChannel& _channel;
+
+    // condition  used to coordinate threads
+    QWaitCondition _cond;
+    
+    // lock  used to coordinate threads
+    QMutex _lock;
+
+    // var to check if we need to abort current rtsp session
+    char _abort_rtsp;
+
+    // request abort for StartRecording method
+    bool _abort_recording;
+};
+
+
+
+FreeboxRecorder::FreeboxRecorder(TVRec *rec, FreeboxChannel *channel) :
+    DTVRecorder(rec),
+    _impl(new FreeboxRecorderImpl(*channel))
+{
+    channel->SetRecorder(this);
+}
+
+
+
+FreeboxRecorder::~FreeboxRecorder()
+{
+    _impl->_channel.SetRecorder(NULL);
+    delete _impl;
+}
+
+
+
+bool FreeboxRecorder::Open()
+{
+    bool result = StartRtsp();
+    _error = !result;
+    return result;
+}
+
+
+
+void FreeboxRecorder::Close()
+{
+    if (_impl->session == NULL) return;
+
+    // Ensure RTSP cleanup, remove old RTSP session
+    MediaSubsessionIterator iter(*_impl->session);
+    MediaSubsession* subsession;
+    while ((subsession = iter.next()) != NULL)
+    {
+        Medium::close(subsession->sink);
+        subsession->sink = NULL;
+    }
+
+    if (_impl->session == NULL) return;
+
+    _impl->rtspClient->teardownMediaSession(*_impl->session);
+
+    // Close all RTSP descriptor
+    Medium::close(_impl->session);
+    Medium::close(_impl->rtspClient);
+}
+
+
+
+void FreeboxRecorder::ChannelChanged()
+{
+    // Channel change, we need to close current RTSP flow, and open a new one
+    ResetEventLoop();
+}
+
+
+
+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()
+{
+    _impl->_lock.lock();
+    _recording = true;
+    while(!_impl->_abort_recording && Open())
+    {
+        _impl->_lock.unlock();
+        // Go into main RTSP loop, feeding data to mythtv
+        _impl->env->taskScheduler().doEventLoop(&_impl->_abort_rtsp);
+
+        _impl->_lock.lock();
+        FinishRecording();
+        Close();
+
+        // Reset _abort_rtsp before unlocking ResetEventLoop() to avoid race condition
+        _impl->_abort_rtsp = 0;
+        _impl->_cond.wakeAll();
+    }
+    _recording = false;
+    _impl->_lock.unlock();
+}
+
+void FreeboxRecorder::StopRecording(void)
+{
+    _impl->_abort_recording = true; // No lock needed
+    ResetEventLoop();
+}
+
+void FreeboxRecorder::ResetEventLoop()
+{
+    _impl->_lock.lock();
+    _impl->_abort_rtsp = ~0;
+    while(_recording && _impl->_abort_rtsp)
+        _impl->_cond.wait(&_impl->_lock, 1000);
+    _impl->_lock.unlock();
+}
+
+// ======================================================================
+// StartRtsp : start a new RTSP session for the current channel
+// ======================================================================
+bool FreeboxRecorder::StartRtsp()
+{
+    // Retrieve the RTSP channel URL
+    FBChanInfo chaninfo = _impl->_channel.GetCurrentChanInfo();
+    if (!chaninfo.isValid())
+        return false;
+    QString url = chaninfo.m_url;
+
+    // Begin by setting up our usage environment:
+    TaskScheduler* scheduler = BasicTaskScheduler::createNew();
+    _impl->env = BasicUsageEnvironment::createNew(*scheduler);
+
+
+    // Create our client object:
+    _impl->rtspClient = RTSPClient::createNew(*_impl->env, 0, "myRTSP", 0);
+    if (_impl->rtspClient == NULL)
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create RTSP client: %1")
+            .arg(_impl->env->getResultMsg()));
+        return false;
+    }
+
+    // Setup URL for the current session
+    char* sdpDescription = _impl->rtspClient->describeURL(url);
+    _impl->rtspClient->describeStatus();
+    if (sdpDescription == NULL)
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to get a SDP description from URL: %1 %2")
+            .arg(url)
+            .arg(_impl->env->getResultMsg()));
+        return false;
+    }
+
+    // Create a media session object from this SDP description:
+    _impl->session = MediaSession::createNew(*_impl->env, sdpDescription);
+    delete[] sdpDescription;
+    if (_impl->session == NULL)
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create MediaSession: %1")
+            .arg(_impl->env->getResultMsg()));
+        return false;
+    }
+    else if (!_impl->session->hasSubsessions())
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # This session has no media subsessions"));
+        return false;
+    }
+
+    // Then, setup the "RTPSource"s for the session:
+    MediaSubsessionIterator iter(*_impl->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(_impl->env->getResultMsg()));
+        }
+        else
+        {
+            madeProgress = True;
+
+            if (subsession->rtpSource() != NULL)
+            {
+                  unsigned const thresh = 1000000; // 1 second
+                  subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
+            }
+        }
+    }
+
+    if (!madeProgress) return false;
+
+    // Perform additional 'setup' on each subsession, before playing them:
+    madeProgress = false;
+    iter.reset();
+    while ((subsession = iter.next()) != NULL)
+    {
+        if (subsession->clientPortNum() == 0) continue; // port # was not set
+
+        if (_impl->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(_impl->env->getResultMsg()));
+        }
+    }
+
+    if (!madeProgress) return false;
+
+   // 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)
+    {
+        if (subsession->readSource() == NULL) continue; // was not initiated
+
+        FreeboxMediaSink* freeboxMediaSink =
+            FreeboxMediaSink::createNew(*_impl->env, *this, TSPacket::SIZE*128);
+
+        subsession->sink = freeboxMediaSink;
+        if (subsession->sink == NULL)
+        {
+            VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create sink: %1")
+                .arg(_impl->env->getResultMsg()));
+        }
+
+        subsession->sink->startPlaying(
+                *(subsession->readSource()),
+                FreeboxData::subsessionAfterPlayingCallback,
+                new FreeboxData(this, subsession));
+
+        if (subsession->rtcpInstance() != NULL)
+        {
+            subsession->rtcpInstance()->setByeHandler(
+                    FreeboxData::subsessionByeHandlerCallback,
+                    new FreeboxData(this, subsession));
+        }
+
+        madeProgress = True;
+    }
+
+    if (!madeProgress) return false;
+
+    // Setup player
+    if (!(_impl->rtspClient->playMediaSession(*_impl->session)))
+    {
+        VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to start playing session: %1")
+            .arg(_impl->env->getResultMsg()));
+        return false;
+    }
+
+    return true;
+}
+
+// ===================================================
+// findTSHeader : find a TS Header in flow
+// ===================================================
+static int FreeboxRecorder_findTSHeader(const unsigned char *data, unsigned dataSize)
+{
+    unsigned int pos = 0;
+    while (pos < dataSize)
+    {
+        if (data[pos] == 0x47)
+            return pos;
+        pos++;
+    }
+    return -1;
+}
+
+// ===================================================
+// addData : 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 = FreeboxRecorder_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) < TSPacket::SIZE)
+        {
+            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 = !FindMPEG2Keyframes(tspacket);
+        BufferedWrite(*tspacket);
+
+        // follow to next packet
+        readIndex += tsPos + TSPacket::SIZE;
+    }
+}
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmythtv/freeboxchannel_util.cpp
===================================================================
--- libs/libmythtv/freeboxchannel_util.cpp	(revision 0)
+++ libs/libmythtv/freeboxchannel_util.cpp	(revision 0)
@@ -0,0 +1,200 @@
+/** -*- Mode: c++ -*-
+ *  FreeboxChannel utils
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+// Qt headers
+#include <qhttp.h>
+#include <qurl.h>
+
+// MythTV headers
+#include "mythcontext.h"
+#include "freeboxchannel_util.h"
+
+#define LOC QString("FBChanFetch: ")
+#define LOC_ERR QString("FBChanFetch, Error: ")
+
+static QString channame_to_xmltvid(const QString &channelName);
+static bool parse_chan_info(const QString&, QString&, QString&);
+
+FBChannelFetcher::FBChannelFetcher()
+    : m_http(new QHttp())
+{
+    connect(m_http, SIGNAL(done(bool)), this, SLOT(HttpRequestDone(bool)));
+}
+
+FBChannelFetcher::~FBChannelFetcher()
+{
+    m_http->deleteLater();
+}
+
+fbox_chan_map_t FBChannelFetcher::GetChannels(const QString &videodev)
+{
+    FBChannelFetcher fetcher;
+    return fetcher.LoadChannels(videodev, 10 * 1000);
+}
+
+/** \fn FBChannelFetcher::LoadChannels(const QString&,uint)
+ *  \brief Request Channel list via http.
+ *  \return true if we get a channel list, false otherwise.
+ */
+fbox_chan_map_t FBChannelFetcher::LoadChannels(const QString &videodev,
+                                               uint max_wait)
+{
+    QMutexLocker locker(&m_lock);
+    m_freeboxchannels.clear();
+
+    QUrl url(videodev);
+    if (!url.isValid())
+        return m_freeboxchannels;
+
+    m_http->setHost(url.host(), url.hasPort() ? url.port() : 80);
+
+    QHttpRequestHeader header("GET", url.path());
+    header.setValue("Host", url.host());
+    m_http->request(header);
+
+    m_load_channel_wait.wait(&m_lock, max_wait);
+
+    m_http->abort();
+    m_http->closeConnection();
+    m_http->disconnect();
+
+    return m_freeboxchannels;
+}
+
+// 
+// HttpRequestDone : Receive response to channel list request
+//
+void FBChannelFetcher::HttpRequestDone(bool error)
+{
+    if (error)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + 
+                QString("Reading channel list failed (%1)")
+                .arg(m_http->errorString()));
+        return;
+    }
+
+    QString buffer = QString::fromUtf8(m_http->readAll());
+
+    m_lock.lock();
+    m_freeboxchannels = ParseChannelList(buffer);
+    m_lock.unlock();
+
+    m_load_channel_wait.wakeAll();
+}
+
+fbox_chan_map_t FBChannelFetcher::ParseChannelList(const QString &rawdata)
+{
+    fbox_chan_map_t chanmap;
+
+    // Verify header is ok
+    QString header = rawdata.section("\n", 0, 0);
+    if (header != "#EXTM3U")
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("Invalid channel list header (%1)").arg(header));
+
+        return chanmap;
+    }
+
+    // Parse each channel
+    for (int i = 1; true; i += 2)
+    {
+        QString tmp = rawdata.section("\n", i+0, i+0);
+        QString url = rawdata.section("\n", i+1, i+1);
+        if (tmp.isEmpty() || url.isEmpty())
+            break;
+
+        QString channum, name;
+        if (parse_chan_info(tmp, channum, name))
+        {
+            chanmap[channum] = FBChanInfo(
+                name, channame_to_xmltvid(name), url);
+        }
+    }
+
+    return chanmap;
+}
+
+static QString channame_to_xmltvid(const QString &channelName)
+{
+    // Normalize Channel name so we can try to automap channel
+    // return by freebox to channel coming from tv_grab_fr
+    static const QString map1 = QString::fromUtf8(
+        "áâäàãåçéêëèíîïìñóôöòõúûüùýÿ");
+    static const QString map2 = QString::fromUtf8(
+        "aaaaaaceeeeiiiinooooouuuuyy");
+
+    QString ret = "";
+    for (uint i = 0; i < channelName.length(); i++)
+    {
+        QChar c = channelName[i].lower();
+
+        if (c.isSpace())
+            continue;
+
+        int pos = map1.find(c);
+        if (pos >= 0)
+            c = map2[pos];
+
+        ret += c;
+    }
+
+    return ret;
+}
+
+static bool parse_chan_info(const QString &line1,
+                            QString &channum, QString &name)
+{
+    // each line contains ://
+    // header:extension,channelNum - channelName rtsp://channelUrl
+    //#EXTINF:0,2 - France 2 rtsp://mafreebox.freebox.fr/freeboxtv/201
+
+    QString msg = LOC_ERR +
+        QString("Invalid header in channel list line \n\t\t\t%1").arg(line1);
+
+    channum = name = QString::null;
+
+    // Verify Line Header
+    int pos = line1.find(":", 0);
+    if ((pos < 0) || (line1.mid(0, pos) != "#EXTINF"))
+    {
+        VERBOSE(VB_IMPORTANT, msg);
+        return false;
+    }
+
+    // Parse extension portion
+    pos = line1.find(",", pos + 1);
+    if (pos < 0)
+    {
+        VERBOSE(VB_IMPORTANT, msg);
+        return false;
+    }
+    //list.push_back(line1.mid(oldPos, pos - oldPos));
+
+    // Parse freebox channel number
+    int oldpos = pos + 1;
+    pos = line1.find(" ", pos + 1);
+    if (pos < 0)
+    {
+        VERBOSE(VB_IMPORTANT, msg);
+        return false;
+    }
+    channum = line1.mid(oldpos, pos - oldpos);
+
+    // Parse freebox channel name
+    pos = line1.find("- ", pos + 1);
+    if (pos < 0)
+    {
+        VERBOSE(VB_IMPORTANT, msg);
+        return false;
+    }
+    name = line1.mid(pos + 2, line1.length());
+
+    return true;
+}
+
+/* vim: set expandtab tabstop = 4 shiftwidth = 4: */
Index: libs/libmythtv/cardutil.cpp
===================================================================
--- libs/libmythtv/cardutil.cpp	(revision 10149)
+++ libs/libmythtv/cardutil.cpp	(working copy)
@@ -571,6 +571,7 @@
 
     if (("FIREWIRE"  == cardtype) ||
         ("DBOX2"     == cardtype) ||
+        ("FREEBOX"   == cardtype) ||
         ("HDHOMERUN" == cardtype) ||
         ("CRC_IP"    == cardtype)) 
     {
@@ -804,6 +805,7 @@
 
     if (("FIREWIRE"  == cardtype) ||
         ("DBOX2"     == cardtype) ||
+        ("FREEBOX"   == cardtype) ||
         ("HDHOMERUN" == cardtype) ||
         ("CRC_IP"    == cardtype))
     {
Index: libs/libmythtv/freeboxmediasink.h
===================================================================
--- libs/libmythtv/freeboxmediasink.h	(revision 0)
+++ libs/libmythtv/freeboxmediasink.h	(revision 0)
@@ -0,0 +1,58 @@
+/**
+ *  FreeboxMediaSink
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _FREEBOXMEDIASINK_H_
+#define _FREEBOXMEDIASINK_H_
+
+#include <MediaSink.hh>
+
+class FreeboxRecorder;
+
+
+
+// ============================================================================
+// FreeboxMediaSink : Helper class use to receive RTSP data from socket.
+// ============================================================================
+class FreeboxMediaSink: public MediaSink
+{
+  public:
+    static FreeboxMediaSink* createNew(UsageEnvironment& env,
+                                       FreeboxRecorder&  pRecorder,
+                                       unsigned          bufferSize);
+
+    // Callback function when rtsp data are ready
+    void addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime);
+
+  protected:
+    FreeboxMediaSink(UsageEnvironment& env,
+                     FreeboxRecorder&  pRecorder,
+                     unsigned          bufferSize);
+    virtual ~FreeboxMediaSink();
+
+    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();
+
+  private:
+    unsigned char*    fBuffer;
+    unsigned          fBufferSize;
+    UsageEnvironment& env;
+    FreeboxRecorder&  recorder;
+
+  private:
+    // avoid default contructors & operator=
+    FreeboxMediaSink();
+    FreeboxMediaSink(const FreeboxMediaSink&);
+    FreeboxMediaSink& operator=(const FreeboxMediaSink&);
+};
+
+#endif//_FREEBOXMEDIASINK_H_
Index: libs/libmythtv/videosource.cpp
===================================================================
--- libs/libmythtv/videosource.cpp	(revision 10149)
+++ libs/libmythtv/videosource.cpp	(working copy)
@@ -993,6 +993,17 @@
     }
 };
 
+class FreeboxHost : public LineEditSetting, public CCSetting {
+  public:
+    FreeboxHost(const CaptureCard &parent):
+        CCSetting(parent, "freebox_mrl")
+    {
+        setValue("http://mafreebox.freebox.fr/freeboxtv/playlist.m3u");
+        setLabel(QObject::tr("Freebox MRL"));
+        setHelpText(QObject::tr("The freebox Media Resource Locator (MRL)."));
+    }
+};
+
 class HDHomeRunTunerIndex: public ComboBoxSetting, public CCSetting
 {
   public:
@@ -1005,6 +1016,20 @@
     }
 };
 
+class FreeboxConfigurationGroup: public VerticalConfigurationGroup {
+  public:
+    FreeboxConfigurationGroup(CaptureCard& a_parent):
+       ConfigurationGroup(false, true, false, false),
+       VerticalConfigurationGroup(false, true, false, false),
+       parent(a_parent)
+    {
+       setUseLabel(false);
+       addChild(new FreeboxHost(parent));
+    };
+  private:
+    CaptureCard& parent;
+};
+
 void HDHRCardInput::fillSelections(const QString&)
 {
     clearSelections();
@@ -1229,6 +1254,10 @@
     addTarget("DBOX2",     new DBOX2ConfigurationGroup(parent));
 #endif // USING_DBOX2
 
+#ifdef USING_FREEBOX
+    addTarget("FREEBOX",   new FreeboxConfigurationGroup(parent));
+#endif // USING_FREEBOX
+
 #ifdef USING_HDHOMERUN
     addTarget("HDHOMERUN", new HDHomeRunConfigurationGroup(parent));
 #endif // USING_HDHOMERUN
@@ -1350,6 +1379,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");
Index: libs/libmythtv/freeboxrecorder.h
===================================================================
--- libs/libmythtv/freeboxrecorder.h	(revision 0)
+++ libs/libmythtv/freeboxrecorder.h	(revision 0)
@@ -0,0 +1,59 @@
+/**
+ *  FreeboxRecorder
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef FREEBOXRECORDER_H_
+#define FREEBOXRECORDER_H_
+
+#include "dtvrecorder.h"
+
+class FreeboxChannel;
+class FreeboxRecorderImpl;
+
+
+
+/**
+ *  Constructs a FreeboxRecorder
+ */
+class FreeboxRecorder :
+    public QObject, //FIXME see changeset #9743 for details
+    public DTVRecorder
+{
+    Q_OBJECT
+  public:
+    FreeboxRecorder(TVRec *rec, FreeboxChannel *channel);
+    ~FreeboxRecorder();
+    
+    void StartRecording(void);  //< RecorderBase
+    void StopRecording(void);   //< DTVRecorder
+
+    // RecorderBase
+    void SetOptionsFromProfile(RecordingProfile *profile,
+                               const QString    &videodev,
+                               const QString    &audiodev,
+                               const QString    &vbidev);
+
+  public slots:
+    void ChannelChanged();
+
+  private:
+    friend class FreeboxMediaSink;
+
+    bool Open(); //< RecorderBase
+    void Close();
+
+    // Callback function to add MPEG2 TS data
+    void addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime);
+
+    bool StartRtsp();
+    void ResetEventLoop();
+
+  private:
+    FreeboxRecorderImpl* _impl;
+};
+
+#endif//FREEBOXRECORDER_H_
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmythtv/tv_rec.cpp
===================================================================
--- libs/libmythtv/tv_rec.cpp	(revision 10149)
+++ libs/libmythtv/tv_rec.cpp	(working copy)
@@ -45,6 +45,7 @@
 #include "dvbchannel.h"
 #include "dbox2channel.h"
 #include "hdhrchannel.h"
+#include "freeboxchannel.h"
 
 #include "recorderbase.h"
 #include "NuppelVideoRecorder.h"
@@ -53,6 +54,7 @@
 #include "dvbrecorder.h"
 #include "dbox2recorder.h"
 #include "hdhrrecorder.h"
+#include "freeboxrecorder.h"
 
 #ifdef USING_CRC_IP_NETWORK_REC
 #include "crcipnetworkrecorder.h"
@@ -178,6 +180,16 @@
         init_run = true;
 #endif
     }
+    else if (genOpt.cardtype == "FREEBOX")
+    {
+#ifdef USING_FREEBOX
+        channel = new FreeboxChannel(this, getOpt.videodev);
+        if (!channel->Open())
+            return false;
+        InitChannel(genOpt.defaultinput, startchannel);
+        init_run = true;
+#endif
+    }    
     else if (genOpt.cardtype == "HDHOMERUN")
     {
 #ifdef USING_HDHOMERUN
@@ -867,6 +879,14 @@
         recorder->SetOption("httpport", dboxOpt.httpport);
 #endif // USING_DBOX2
     }
+    else if (genOpt.cardtype == "FREEBOX")
+    {
+#ifdef USING_FREEBOX
+        FreeboxChannel chan = dynamic_cast<FreeboxChannel*>(channel);
+        recorder = new FreeboxRecorder(this, chan);
+        recorder->SetOption("mrl", genOpt.videodev);
+#endif // USING_FREEBOX
+    }
     else if (genOpt.cardtype == "HDHOMERUN")
     {
 #ifdef USING_HDHOMERUN
Index: libs/libmythtv/freeboxchannel_util.h
===================================================================
--- libs/libmythtv/freeboxchannel_util.h	(revision 0)
+++ libs/libmythtv/freeboxchannel_util.h	(revision 0)
@@ -0,0 +1,67 @@
+/** -*- Mode: c++ -*-
+ *  FreeboxChannel utils
+ *  Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars
+ *  Distributed as part of MythTV under GPL v2 and later.
+ */
+
+#ifndef _FREEBOXCHANNEL_UTIL_H_
+#define _FREEBOXCHANNEL_UTIL_H_
+
+// Qt headers
+#include <qwaitcondition.h>
+#include <qmutex.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qmap.h>
+
+class QHttp;
+
+class FBChanInfo
+{
+  public:
+    FBChanInfo() :
+        m_name(QString::null), m_xmltvid(QString::null),
+        m_url(QString::null) {}
+
+    FBChanInfo(const QString &name, const QString &xmltvid,
+               const QString &url) :
+        m_name(name), m_xmltvid(xmltvid), m_url(url) {}
+
+    bool isValid(void) const
+    {
+        return !m_name.isEmpty() && !m_xmltvid.isEmpty() && !m_url.isEmpty();
+    }
+
+  public:
+    QString m_name;
+    QString m_xmltvid;
+    QString m_url;
+};
+typedef QMap<QString,FBChanInfo> fbox_chan_map_t;
+
+class FBChannelFetcher : public QObject
+{
+    Q_OBJECT
+  public:
+    FBChannelFetcher();
+   ~FBChannelFetcher();
+
+    static fbox_chan_map_t GetChannels(const QString &videodev);
+
+  private slots:
+    void HttpRequestDone(bool error);
+
+  private:
+    fbox_chan_map_t LoadChannels(const QString &videodev, uint max_wait);
+    static fbox_chan_map_t ParseChannelList(const QString &rawdata);
+
+  private:
+    QHttp           *m_http;
+    QMutex           m_lock;
+    QWaitCondition   m_load_channel_wait;
+    fbox_chan_map_t  m_freeboxchannels;
+};
+
+#endif // _FREEBOXCHANNEL_UTIL_H_
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmythtv/tv_rec.h
===================================================================
--- libs/libmythtv/tv_rec.h	(revision 10149)
+++ libs/libmythtv/tv_rec.h	(working copy)
@@ -237,7 +237,7 @@
     void SetPseudoLiveTVRecording(ProgramInfo*);
     void TeardownAll(void);
 
-    static bool GetDevices(int cardid,
+    static bool GetDevices(int                cardid,
                            GeneralDBOptions   &general_opts,
                            DVBDBOptions       &dvb_opts,
                            FireWireDBOptions  &firewire_opts,
@@ -255,11 +255,12 @@
     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);
+    Channel        *GetV4LChannel(void);
+
     void SetupSignalMonitor(bool enable_table_monitoring, bool notify);
     bool SetupDTVSignalMonitor(void);
     void TeardownSignalMonitor(void);
Index: settings.pro
===================================================================
--- settings.pro	(revision 10149)
+++ settings.pro	(working copy)
@@ -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
