Ticket #1704: 1704-v2.patch
File 1704-v2.patch, 43.5 KB (added by , 18 years ago) |
---|
-
configure
54 54 lirc="yes" 55 55 joystick_menu="yes" 56 56 firewire_cable_box="yes" 57 freebox_box="yes" 57 58 dbox2_dvb_box="yes" 58 59 ip_network_recorder="yes" 59 60 hdhomerun_box="yes" … … 178 179 echo " --disable-lirc disable lirc support (Infrared Remotes)" 179 180 echo " --disable-joystick-menu disable joystick menu" 180 181 echo " --disable-firewire disable support for FireWire cable boxes" 182 echo " --disable-freebox disable support for Freebox" 183 echo " --livelibdir=DIR location of Live streaming library" 184 echo " --liveincludedir=DIR location of Live streaming include files" 181 185 echo " --disable-dbox2 disable support for Nokia DBOX2 DVB boxes (or compatibles)" 182 186 echo " --disable-hdhomerun disable support for HDHomeRun boxes" 183 187 echo " --disable-crciprec disable support for Network Recorder" … … 819 823 ;; 820 824 --disable-dbox2) dbox2_dvb_box="no" 821 825 ;; 826 --enable-freebox) freebox_box="yes" 827 ;; 828 --disable-freebox) freebox_box="no" 829 ;; 830 --livelibdir=*) live_lib_dir=`echo $opt | cut -d '=' -f 2` 831 ;; 832 --liveincludedir=*) live_include_dir=`echo $opt | cut -d '=' -f 2` 833 ;; 822 834 --enable-hdhomerun) hdhomerun_box="yes" 823 835 ;; 824 836 --disable-hdhomerun) hdhomerun_box="no" … … 2036 2048 fi 2037 2049 fi 2038 2050 2051 if test x"$freebox_box" = x"yes" ; then 2052 if test x"$live_lib_dir" = x""; then 2053 if has_library libliveMedia; then 2054 CONFIG_LIVE_LIBS="-lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment" 2055 else 2056 echo "Unable to find Live Media library." 2057 freebox_box="no" 2058 fi 2059 else 2060 if test ! -f "$live_lib_dir/liveMedia/libliveMedia.a"; then 2061 echo "Unable to find Live Media library." 2062 freebox_box="no" 2063 fi 2064 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" 2065 fi 2066 if test "x$live_include_dir" = "x"; then 2067 if has_header liveMedia.hh; then 2068 true 2069 else 2070 echo "Unable to find Live Media headers." 2071 freebox_box="no" 2072 fi 2073 else 2074 if test -f "$live_include_dir/liveMedia/include/liveMedia.hh"; then 2075 LIVE_INCLUDES="$live_include_dir/liveMedia/include $live_include_dir/UsageEnvironment/include $live_include_dir/BasicUsageEnvironment/include $live_include_dir/groupsock/include" 2076 else 2077 if test -f "$live_include_dir/liveMedia/liveMedia.hh"; then 2078 LIVE_INCLUDES="$live_include_dir/liveMedia $live_include_dir/UsageEnvironment $live_include_dir/BasicUsageEnvironment $live_include_dir/groupsock" 2079 else 2080 echo "Unable to find Live Media headers." 2081 freebox_box="no" 2082 fi 2083 fi 2084 fi 2085 fi 2086 2039 2087 lamemp3="no" 2040 2088 if has_library libmp3lame ; then 2041 2089 if has_header lame/lame.h ; then … … 2322 2370 echo "FireWire support $firewire_cable_box" 2323 2371 echo "DVB support $dvb [$dvb_path]" 2324 2372 echo "DBox2 support $dbox2_dvb_box" 2373 echo "freebox support $freebox_box" 2325 2374 echo "HDHomeRun sup. $hdhomerun_box" 2326 2375 echo "CRC Ip Rec sup. $ip_network_recorder" 2327 2376 fi … … 2984 3033 CCONFIG="$CCONFIG using_ip_rec" 2985 3034 fi 2986 3035 3036 if test x"$freebox_box" = x"yes" ; then 3037 CCONFIG="$CCONFIG using_freebox" 3038 CONFIG_DEFINES="$CONFIG_DEFINES USING_FREEBOX" 3039 echo "CONFIG_LIVE_LIBS=$CONFIG_LIVE_LIBS" >> $MYTH_CONFIG_MAK 3040 CONFIG_INCLUDEPATH="$CONFIG_INCLUDEPATH $LIVE_INCLUDES" 3041 fi 3042 2987 3043 if test x"$lirc" = x"yes" ; then 2988 3044 CCONFIG="$CCONFIG using_lirc" 2989 3045 echo "CONFIG_LIRC_LIBS=-llirc_client" >> $MYTH_CONFIG_MAK -
libs/libmythtv/freeboxchannel.h
1 /** -*- Mode: c++ -*- 2 * FreeboxChannel 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXCHANNEL_H 8 #define FREEBOXCHANNEL_H 9 10 #include "freeboxchannel_util.h" 11 #include "channelbase.h" 12 13 class FreeboxRecorder; 14 15 class FreeboxChannel : public ChannelBase 16 { 17 friend class FreeboxRecorder; 18 public: 19 FreeboxChannel(TVRec *parent, const QString &videodev); 20 ~FreeboxChannel(void) { } 21 22 bool Open(void); 23 void Close(void) { m_isopen = false; } 24 25 bool IsOpen(void) const { return m_isopen; } 26 27 bool SwitchToInput(const QString &inputname, const QString &channum); 28 bool SwitchToInput(int inputNum, bool setstarting); 29 bool SetChannelByString(const QString &channum); 30 31 void SetRecorder(FreeboxRecorder *rec) 32 { QMutexLocker locker(&m_lock); m_recorder = rec; } 33 34 private: 35 FBChanInfo GetChanInfo(const QString &channum, uint sourceid = 0) const; 36 FBChanInfo GetCurrentChanInfo(void) const 37 { return GetChanInfo(curchannelname); } 38 39 QString m_videodev; 40 FreeboxRecorder *m_recorder; 41 bool m_isopen; 42 fbox_chan_map_t m_freeboxchannels; 43 mutable QMutex m_lock; 44 }; 45 46 #endif // FREEBOXCHANNEL_H 47 48 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/libmythtv.pro
373 373 using_dbox2:SOURCES += dbox2recorder.cpp dbox2channel.cpp dbox2epg.cpp 374 374 using_dbox2:HEADERS += dbox2recorder.h dbox2channel.h dbox2epg.h 375 375 using_dbox2:DEFINES += USING_DBOX2 376 377 # Support for freebox (http://adsl.free.fr/) 378 using_freebox:SOURCES += freeboxrecorder.cpp freeboxmediasink.cpp 379 using_freebox:SOURCES += freeboxchannel.cpp freeboxchannel_util.cpp 380 using_freebox:HEADERS += freeboxrecorder.h freeboxmediasink.h 381 using_freebox:HEADERS += freeboxchannel.h freeboxchannel_util.h 382 using_freebox:DEFINES += USING_FREEBOX 376 383 377 384 # Support for HDHomeRun box 378 385 using_hdhr { -
libs/libmythtv/freeboxchannel.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxChannel 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include "freeboxchannel.h" 8 #include "freeboxrecorder.h" 9 #include "libmythtv/tv_rec.h" 10 11 #define LOC QString("FBChan%1: ").arg(GetCardID()) 12 #define LOC_ERR QString("FBChan%1, Error: ").arg(GetCardID()) 13 14 FreeboxChannel::FreeboxChannel(TVRec *parent, const QString &videodev) 15 : ChannelBase(parent), 16 m_videodev(videodev), m_recorder(NULL), 17 m_isopen(false), m_lock(true) 18 { 19 } 20 21 bool FreeboxChannel::Open(void) 22 { 23 QMutexLocker locker(&m_lock); 24 25 if (InitializeInputs()) 26 return false; 27 28 m_freeboxchannels = FBChannelFetcher::GetChannels(m_videodev); 29 30 return m_isopen = m_freeboxchannels.size(); 31 } 32 33 bool FreeboxChannel::SwitchToInput(const QString &inputname, 34 const QString &channum) 35 { 36 QMutexLocker locker(&m_lock); 37 38 int inputNum = GetInputByName(inputname); 39 if (inputNum < 0) 40 return false; 41 42 return SetChannelByString(channum); 43 } 44 45 bool FreeboxChannel::SwitchToInput(int inputNum, bool setstarting) 46 { 47 QMutexLocker locker(&m_lock); 48 49 InputMap::const_iterator it = inputs.find(inputNum); 50 if (it == inputs.end()) 51 return false; 52 53 QString channum = (*it)->startChanNum; 54 55 if (setstarting) 56 return SetChannelByString(channum); 57 58 return true; 59 } 60 61 bool FreeboxChannel::SetChannelByString(const QString &channum) 62 { 63 QMutexLocker locker(&m_lock); 64 65 // Verify that channel exists 66 if (!GetChanInfo(channum).isValid()) 67 { 68 VERBOSE(VB_IMPORTANT, LOC_ERR + 69 QString("SetChannelByString(%1)").arg(channum) + 70 " Invalid channel"); 71 return false; 72 } 73 74 // Set the channel.. 75 curchannelname = channum; 76 77 // Send signal to recorder that channel has changed. 78 if (m_recorder) 79 m_recorder->ChannelChanged(); 80 81 return true; 82 } 83 84 FBChanInfo FreeboxChannel::GetChanInfo(const QString &channum, 85 uint sourceid) const 86 { 87 QMutexLocker locker(&m_lock); 88 89 FBChanInfo dummy; 90 QString msg = LOC_ERR + QString("GetChanInfo(%1) failed").arg(channum); 91 92 if (channum.isEmpty()) 93 { 94 VERBOSE(VB_IMPORTANT, msg); 95 return dummy; 96 } 97 98 if (!sourceid) 99 { 100 InputMap::const_iterator it = inputs.find(currentInputID); 101 if (it == inputs.end()) 102 { 103 VERBOSE(VB_IMPORTANT, msg); 104 return dummy; 105 } 106 sourceid = (*it)->sourceid; 107 } 108 109 MSqlQuery query(MSqlQuery::InitCon()); 110 query.prepare( 111 "SELECT freqid, xmltvid, name" 112 "FROM channel " 113 "WHERE channum = :CHANNUM AND " 114 " sourceid = :SOURCEID"); 115 116 query.bindValue(":CHANNUM", channum); 117 query.bindValue(":SOURCEID", sourceid); 118 119 if (!query.exec() || !query.isActive()) 120 { 121 MythContext::DBError("fetching chaninfo", query); 122 VERBOSE(VB_IMPORTANT, msg); 123 return dummy; 124 } 125 126 while (query.next()) 127 { 128 // Try to map freqid or name to a channel in the map 129 const QString freqid = query.value(0).toString(); 130 fbox_chan_map_t::const_iterator it; 131 if (!freqid.isEmpty()) 132 { 133 it = m_freeboxchannels.find(freqid); 134 if (it != m_freeboxchannels.end()) 135 return *it; 136 } 137 138 // Try to map xmltvid or name to a channel in the map 139 const QString xmltvid = query.value(1).toString(); 140 const QString name = query.value(2).toString(); 141 for (it = m_freeboxchannels.begin(); 142 it != m_freeboxchannels.end(); ++it) 143 { 144 if ((*it).m_xmltvid == xmltvid) 145 return *it; 146 if ((*it).m_name == name) 147 return *it; 148 } 149 } 150 151 VERBOSE(VB_IMPORTANT, msg); 152 return dummy; 153 } 154 155 /* vim: set expandtab tabstop = 4 shiftwidth = 4: */ -
libs/libmythtv/freeboxmediasink.cpp
1 /** 2 * FreeboxMediaSink 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include "freeboxmediasink.h" 8 9 #include "freeboxrecorder.h" 10 11 12 13 FreeboxMediaSink::FreeboxMediaSink(UsageEnvironment& pEnv, 14 FreeboxRecorder& pRecorder, 15 unsigned bufferSize) : 16 MediaSink(pEnv), 17 fBufferSize(bufferSize), 18 env(pEnv), 19 recorder(pRecorder) 20 { 21 // Setup the data buffer 22 fBuffer = new unsigned char[fBufferSize]; 23 } 24 25 FreeboxMediaSink::~FreeboxMediaSink() 26 { 27 // free the data buffer 28 delete[] fBuffer; 29 } 30 31 FreeboxMediaSink* FreeboxMediaSink::createNew(UsageEnvironment& env, 32 FreeboxRecorder& pRecorder, 33 unsigned bufferSize) 34 { 35 return new FreeboxMediaSink(env, pRecorder, bufferSize); 36 } 37 38 Boolean FreeboxMediaSink::continuePlaying() 39 { 40 if (fSource == NULL) return False; 41 42 fSource->getNextFrame(fBuffer, fBufferSize, 43 afterGettingFrame, this, 44 onSourceClosure, this); 45 return True; 46 } 47 48 void FreeboxMediaSink::afterGettingFrame(void* clientData, 49 unsigned frameSize, 50 unsigned /*numTruncatedBytes*/, 51 struct timeval presentationTime, 52 unsigned /*durationInMicroseconds*/) 53 { 54 FreeboxMediaSink* sink = (FreeboxMediaSink*)clientData; 55 sink->afterGettingFrame1(frameSize, presentationTime); 56 } 57 58 void FreeboxMediaSink::afterGettingFrame1(unsigned frameSize, 59 struct timeval presentationTime) 60 { 61 addData(fBuffer, frameSize, presentationTime); 62 continuePlaying(); 63 } 64 65 void FreeboxMediaSink::addData(unsigned char* data, 66 unsigned dataSize, 67 struct timeval presentationTime) 68 { 69 recorder.addData(data, dataSize, presentationTime); 70 } -
libs/libmythtv/dbcheck.cpp
10 10 #include "mythdbcon.h" 11 11 12 12 /// This is the DB schema version expected by the running MythTV instance. 13 const QString currentDatabaseVersion = "114 2";13 const QString currentDatabaseVersion = "1143"; 14 14 15 15 static bool UpdateDBVersionNumber(const QString &newnumber); 16 16 static bool performActualUpdate(const QString updates[], QString version, … … 2268 2268 //"ALTER TABLE capturecard DROP COLUMN dvb_hw_decoder;" in 0.21 2269 2269 //"ALTER TABLE cardinput DROP COLUMN preference;" in 0.22 2270 2270 2271 if (dbver == "1142") 2272 { 2273 const QString updates[] = { 2274 "INSERT INTO profilegroups SET name = 'Freebox Input', cardtype = 'Freebox', is_default = 1;", 2275 "" 2276 }; 2277 2278 if (!performActualUpdate(updates, "1143", dbver)) 2279 return false; 2280 } 2281 2282 2271 2283 return true; 2272 2284 } 2273 2285 … … 2328 2340 " dbox2_port int(10) unsigned NOT NULL default '31338'," 2329 2341 " dbox2_httpport int(10) unsigned NOT NULL default '80'," 2330 2342 " dbox2_host varchar(32) default NULL," 2343 " freebox_mrl varchar(64) DEFAULT 'http://mafreebox.freebox.fr/freeboxtv/playlist.m3u'," 2331 2344 " signal_timeout int(11) NOT NULL default '1000'," 2332 2345 " channel_timeout int(11) NOT NULL default '3000'," 2333 2346 " PRIMARY KEY (cardid)" … … 2894 2907 "INSERT INTO profilegroups VALUES (8," 2895 2908 " 'USB Mpeg-4 Encoder (Plextor ConvertX, etc)','GO7007',1,NULL);", 2896 2909 "INSERT INTO profilegroups VALUES (9,'DBOX2 Input','DBOX2',1,NULL);", 2910 "INSERT INTO `profilegroups` VALUES (10,'Freebox Input','Freebox',1,NULL);", 2897 2911 "INSERT INTO recordingprofiles VALUES (1,'Default',NULL,NULL,1);", 2898 2912 "INSERT INTO recordingprofiles VALUES (2,'Live TV',NULL,NULL,1);", 2899 2913 "INSERT INTO recordingprofiles VALUES (3,'High Quality',NULL,NULL,1);", -
libs/libmythtv/freeboxrecorder.cpp
1 /** 2 * FreeboxRecorder 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include "freeboxrecorder.h" 8 9 #include <BasicUsageEnvironment.hh> 10 #include <MediaSession.hh> 11 #include <RTSPClient.hh> 12 #include <qwaitcondition.h> 13 #include <qmutex.h> 14 15 #include "mpeg/tspacket.h" 16 #include "freeboxchannel.h" 17 #include "freeboxmediasink.h" 18 19 20 21 // ============================================================================ 22 // FreeboxData : Helper class use for static Callback handler 23 // ============================================================================ 24 class FreeboxData 25 { 26 public: 27 FreeboxData(FreeboxRecorder *pFreeboxRecorder, MediaSubsession *pMediaSubSession) : 28 freeboxRecorder(pFreeboxRecorder), 29 mediaSubSession(pMediaSubSession) 30 { 31 } 32 33 static void subsessionAfterPlayingCallback(void *clientData); 34 static void subsessionByeHandlerCallback(void *clientData); 35 void SubsessionAfterPlaying(); 36 void SubsessionByeHandler(); 37 38 private: 39 FreeboxRecorder *freeboxRecorder; 40 MediaSubsession *mediaSubSession; 41 }; 42 43 void FreeboxData::subsessionAfterPlayingCallback(void *clientData) 44 { 45 ((FreeboxData*)clientData)->SubsessionAfterPlaying(); 46 } 47 48 void FreeboxData::subsessionByeHandlerCallback(void *clientData) 49 { 50 ((FreeboxData*)clientData)->SubsessionByeHandler(); 51 } 52 53 void FreeboxData::SubsessionAfterPlaying() 54 { 55 MediaSubsession* subsession = mediaSubSession; 56 Medium::close(subsession->sink); 57 subsession->sink = NULL; 58 59 MediaSession& session = subsession->parentSession(); 60 MediaSubsessionIterator iter(session); 61 while ((subsession = iter.next()) != NULL) 62 { 63 if (subsession->sink != NULL) return; 64 } 65 } 66 67 void FreeboxData::SubsessionByeHandler() 68 { 69 SubsessionAfterPlaying(); 70 } 71 72 73 74 class FreeboxRecorderImpl 75 { 76 public: 77 FreeboxRecorderImpl(FreeboxChannel& channel) : 78 env(NULL), 79 rtspClient(NULL), 80 session(NULL), 81 _channel(channel), 82 _abort_rtsp(0), 83 _abort_recording(false) 84 { 85 } 86 87 // livemedia 88 UsageEnvironment* env; 89 RTSPClient* rtspClient; 90 MediaSession* session; 91 92 // Current channel 93 FreeboxChannel& _channel; 94 95 // condition used to coordinate threads 96 QWaitCondition _cond; 97 98 // lock used to coordinate threads 99 QMutex _lock; 100 101 // var to check if we need to abort current rtsp session 102 char _abort_rtsp; 103 104 // request abort for StartRecording method 105 bool _abort_recording; 106 }; 107 108 109 110 FreeboxRecorder::FreeboxRecorder(TVRec *rec, FreeboxChannel *channel) : 111 DTVRecorder(rec), 112 _impl(new FreeboxRecorderImpl(*channel)) 113 { 114 channel->SetRecorder(this); 115 } 116 117 118 119 FreeboxRecorder::~FreeboxRecorder() 120 { 121 _impl->_channel.SetRecorder(NULL); 122 delete _impl; 123 } 124 125 126 127 bool FreeboxRecorder::Open() 128 { 129 bool result = StartRtsp(); 130 _error = !result; 131 return result; 132 } 133 134 135 136 void FreeboxRecorder::Close() 137 { 138 if (_impl->session == NULL) return; 139 140 // Ensure RTSP cleanup, remove old RTSP session 141 MediaSubsessionIterator iter(*_impl->session); 142 MediaSubsession* subsession; 143 while ((subsession = iter.next()) != NULL) 144 { 145 Medium::close(subsession->sink); 146 subsession->sink = NULL; 147 } 148 149 if (_impl->session == NULL) return; 150 151 _impl->rtspClient->teardownMediaSession(*_impl->session); 152 153 // Close all RTSP descriptor 154 Medium::close(_impl->session); 155 Medium::close(_impl->rtspClient); 156 } 157 158 159 160 void FreeboxRecorder::ChannelChanged() 161 { 162 // Channel change, we need to close current RTSP flow, and open a new one 163 ResetEventLoop(); 164 } 165 166 167 168 void FreeboxRecorder::SetOptionsFromProfile(RecordingProfile *profile, 169 const QString &videodev, 170 const QString &audiodev, 171 const QString &vbidev) 172 { 173 (void)videodev; 174 (void)audiodev; 175 (void)vbidev; 176 (void)profile; 177 } 178 179 180 181 void FreeboxRecorder::StartRecording() 182 { 183 _impl->_lock.lock(); 184 _recording = true; 185 while(!_impl->_abort_recording && Open()) 186 { 187 _impl->_lock.unlock(); 188 // Go into main RTSP loop, feeding data to mythtv 189 _impl->env->taskScheduler().doEventLoop(&_impl->_abort_rtsp); 190 191 _impl->_lock.lock(); 192 FinishRecording(); 193 Close(); 194 195 // Reset _abort_rtsp before unlocking ResetEventLoop() to avoid race condition 196 _impl->_abort_rtsp = 0; 197 _impl->_cond.wakeAll(); 198 } 199 _recording = false; 200 _impl->_lock.unlock(); 201 } 202 203 void FreeboxRecorder::StopRecording(void) 204 { 205 _impl->_abort_recording = true; // No lock needed 206 ResetEventLoop(); 207 } 208 209 void FreeboxRecorder::ResetEventLoop() 210 { 211 _impl->_lock.lock(); 212 _impl->_abort_rtsp = ~0; 213 while(_recording && _impl->_abort_rtsp) 214 _impl->_cond.wait(&_impl->_lock, 1000); 215 _impl->_lock.unlock(); 216 } 217 218 // ====================================================================== 219 // StartRtsp : start a new RTSP session for the current channel 220 // ====================================================================== 221 bool FreeboxRecorder::StartRtsp() 222 { 223 // Retrieve the RTSP channel URL 224 FBChanInfo chaninfo = _impl->_channel.GetCurrentChanInfo(); 225 if (!chaninfo.isValid()) 226 return false; 227 QString url = chaninfo.m_url; 228 229 // Begin by setting up our usage environment: 230 TaskScheduler* scheduler = BasicTaskScheduler::createNew(); 231 _impl->env = BasicUsageEnvironment::createNew(*scheduler); 232 233 234 // Create our client object: 235 _impl->rtspClient = RTSPClient::createNew(*_impl->env, 0, "myRTSP", 0); 236 if (_impl->rtspClient == NULL) 237 { 238 VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create RTSP client: %1") 239 .arg(_impl->env->getResultMsg())); 240 return false; 241 } 242 243 // Setup URL for the current session 244 char* sdpDescription = _impl->rtspClient->describeURL(url); 245 _impl->rtspClient->describeStatus(); 246 if (sdpDescription == NULL) 247 { 248 VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to get a SDP description from URL: %1 %2") 249 .arg(url) 250 .arg(_impl->env->getResultMsg())); 251 return false; 252 } 253 254 // Create a media session object from this SDP description: 255 _impl->session = MediaSession::createNew(*_impl->env, sdpDescription); 256 delete[] sdpDescription; 257 if (_impl->session == NULL) 258 { 259 VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create MediaSession: %1") 260 .arg(_impl->env->getResultMsg())); 261 return false; 262 } 263 else if (!_impl->session->hasSubsessions()) 264 { 265 VERBOSE(VB_IMPORTANT, QString("Freebox # This session has no media subsessions")); 266 return false; 267 } 268 269 // Then, setup the "RTPSource"s for the session: 270 MediaSubsessionIterator iter(*_impl->session); 271 MediaSubsession *subsession; 272 Boolean madeProgress = False; 273 while ((subsession = iter.next()) != NULL) 274 { 275 if (!subsession->initiate(-1)) 276 { 277 VERBOSE(VB_IMPORTANT, QString("Freebox # Unable to create receiver for: %1 / %2 subsession: %3") 278 .arg(subsession->mediumName()) 279 .arg(subsession->codecName()) 280 .arg(_impl->env->getResultMsg())); 281 } 282 else 283 { 284 madeProgress = True; 285 286 if (subsession->rtpSource() != NULL) 287 { 288 unsigned const thresh = 1000000; // 1 second 289 subsession->rtpSource()->setPacketReorderingThresholdTime(thresh); 290 } 291 } 292 } 293 294 if (!madeProgress) return false; 295 296 // Perform additional 'setup' on each subsession, before playing them: 297 madeProgress = false; 298 iter.reset(); 299 while ((subsession = iter.next()) != NULL) 300 { 301 if (subsession->clientPortNum() == 0) continue; // port # was not set 302 303 if (_impl->rtspClient->setupMediaSubsession(*subsession, False, false)) 304 { 305 madeProgress = True; 306 } 307 else 308 { 309 VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to setup: %1 %2 : %3") 310 .arg(subsession->mediumName()) 311 .arg(subsession->codecName()) 312 .arg(_impl->env->getResultMsg())); 313 } 314 } 315 316 if (!madeProgress) return false; 317 318 // Create and start "FileSink"s for each subsession: 319 // FileSink while receive Mpeg2 TS Data & will feed them to mythtv 320 madeProgress = False; 321 iter.reset(); 322 while ((subsession = iter.next()) != NULL) 323 { 324 if (subsession->readSource() == NULL) continue; // was not initiated 325 326 FreeboxMediaSink* freeboxMediaSink = 327 FreeboxMediaSink::createNew(*_impl->env, *this, TSPacket::SIZE*128); 328 329 subsession->sink = freeboxMediaSink; 330 if (subsession->sink == NULL) 331 { 332 VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to create sink: %1") 333 .arg(_impl->env->getResultMsg())); 334 } 335 336 subsession->sink->startPlaying( 337 *(subsession->readSource()), 338 FreeboxData::subsessionAfterPlayingCallback, 339 new FreeboxData(this, subsession)); 340 341 if (subsession->rtcpInstance() != NULL) 342 { 343 subsession->rtcpInstance()->setByeHandler( 344 FreeboxData::subsessionByeHandlerCallback, 345 new FreeboxData(this, subsession)); 346 } 347 348 madeProgress = True; 349 } 350 351 if (!madeProgress) return false; 352 353 // Setup player 354 if (!(_impl->rtspClient->playMediaSession(*_impl->session))) 355 { 356 VERBOSE(VB_IMPORTANT, QString("Freebox # Failed to start playing session: %1") 357 .arg(_impl->env->getResultMsg())); 358 return false; 359 } 360 361 return true; 362 } 363 364 // =================================================== 365 // findTSHeader : find a TS Header in flow 366 // =================================================== 367 static int FreeboxRecorder_findTSHeader(const unsigned char *data, unsigned dataSize) 368 { 369 unsigned int pos = 0; 370 while (pos < dataSize) 371 { 372 if (data[pos] == 0x47) 373 return pos; 374 pos++; 375 } 376 return -1; 377 } 378 379 // =================================================== 380 // addData : feed date from RTSP flow to mythtv 381 // =================================================== 382 void FreeboxRecorder::addData(unsigned char* data, unsigned dataSize, struct timeval) 383 { 384 unsigned int readIndex = 0; 385 386 // data may be compose from more than one packet, loop to consume all data 387 while (readIndex < dataSize) 388 { 389 // If recorder is pause, stop there 390 if (PauseAndWait()) 391 { 392 return; 393 } 394 395 // Find the next TS Header in data 396 int tsPos = FreeboxRecorder_findTSHeader(data + readIndex, dataSize); 397 398 // if no TS, something bad happens 399 if (tsPos == -1) 400 { 401 VERBOSE(VB_IMPORTANT, QString("FREEBOX: No TS header.")); 402 break; 403 } 404 405 // if TS Header not at start of data, we receive out of sync data 406 if (tsPos > 0) 407 { 408 VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1, not in sync.").arg(tsPos)); 409 } 410 411 // Check if the next packet in buffer is complete : packet size is 188 bytes long 412 if ((dataSize - tsPos) < TSPacket::SIZE) 413 { 414 VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1 but packet not yet complete.").arg(tsPos)); 415 break; 416 } 417 418 // Cast current found TS Packet to TSPacket structure 419 const void *newData = data + tsPos + readIndex; 420 const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(newData); 421 422 // Feed current packet to myth 423 _buffer_packets = !FindMPEG2Keyframes(tspacket); 424 BufferedWrite(*tspacket); 425 426 // follow to next packet 427 readIndex += tsPos + TSPacket::SIZE; 428 } 429 } 430 431 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/freeboxchannel_util.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxChannel utils 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 // Qt headers 8 #include <qhttp.h> 9 #include <qurl.h> 10 11 // MythTV headers 12 #include "mythcontext.h" 13 #include "freeboxchannel_util.h" 14 15 #define LOC QString("FBChanFetch: ") 16 #define LOC_ERR QString("FBChanFetch, Error: ") 17 18 static QString channame_to_xmltvid(const QString &channelName); 19 static bool parse_chan_info(const QString&, QString&, QString&); 20 21 FBChannelFetcher::FBChannelFetcher() 22 : m_http(new QHttp()) 23 { 24 connect(m_http, SIGNAL(done(bool)), this, SLOT(HttpRequestDone(bool))); 25 } 26 27 FBChannelFetcher::~FBChannelFetcher() 28 { 29 m_http->deleteLater(); 30 } 31 32 fbox_chan_map_t FBChannelFetcher::GetChannels(const QString &videodev) 33 { 34 FBChannelFetcher fetcher; 35 return fetcher.LoadChannels(videodev, 10 * 1000); 36 } 37 38 /** \fn FBChannelFetcher::LoadChannels(const QString&,uint) 39 * \brief Request Channel list via http. 40 * \return true if we get a channel list, false otherwise. 41 */ 42 fbox_chan_map_t FBChannelFetcher::LoadChannels(const QString &videodev, 43 uint max_wait) 44 { 45 QMutexLocker locker(&m_lock); 46 m_freeboxchannels.clear(); 47 48 QUrl url(videodev); 49 if (!url.isValid()) 50 return m_freeboxchannels; 51 52 m_http->setHost(url.host(), url.hasPort() ? url.port() : 80); 53 54 QHttpRequestHeader header("GET", url.path()); 55 header.setValue("Host", url.host()); 56 m_http->request(header); 57 58 m_load_channel_wait.wait(&m_lock, max_wait); 59 60 m_http->abort(); 61 m_http->closeConnection(); 62 m_http->disconnect(); 63 64 return m_freeboxchannels; 65 } 66 67 // 68 // HttpRequestDone : Receive response to channel list request 69 // 70 void FBChannelFetcher::HttpRequestDone(bool error) 71 { 72 if (error) 73 { 74 VERBOSE(VB_IMPORTANT, LOC_ERR + 75 QString("Reading channel list failed (%1)") 76 .arg(m_http->errorString())); 77 return; 78 } 79 80 QString buffer = QString::fromUtf8(m_http->readAll()); 81 82 m_lock.lock(); 83 m_freeboxchannels = ParseChannelList(buffer); 84 m_lock.unlock(); 85 86 m_load_channel_wait.wakeAll(); 87 } 88 89 fbox_chan_map_t FBChannelFetcher::ParseChannelList(const QString &rawdata) 90 { 91 fbox_chan_map_t chanmap; 92 93 // Verify header is ok 94 QString header = rawdata.section("\n", 0, 0); 95 if (header != "#EXTM3U") 96 { 97 VERBOSE(VB_IMPORTANT, LOC_ERR + 98 QString("Invalid channel list header (%1)").arg(header)); 99 100 return chanmap; 101 } 102 103 // Parse each channel 104 for (int i = 1; true; i += 2) 105 { 106 QString tmp = rawdata.section("\n", i+0, i+0); 107 QString url = rawdata.section("\n", i+1, i+1); 108 if (tmp.isEmpty() || url.isEmpty()) 109 break; 110 111 QString channum, name; 112 if (parse_chan_info(tmp, channum, name)) 113 { 114 chanmap[channum] = FBChanInfo( 115 name, channame_to_xmltvid(name), url); 116 } 117 } 118 119 return chanmap; 120 } 121 122 static QString channame_to_xmltvid(const QString &channelName) 123 { 124 // Normalize Channel name so we can try to automap channel 125 // return by freebox to channel coming from tv_grab_fr 126 static const QString map1 = QString::fromUtf8( 127 "áâÀà ãåçéêëÚÃîïìñóÎöòõúûÌùÜÿ"); 128 static const QString map2 = QString::fromUtf8( 129 "aaaaaaceeeeiiiinooooouuuuyy"); 130 131 QString ret = ""; 132 for (uint i = 0; i < channelName.length(); i++) 133 { 134 QChar c = channelName[i].lower(); 135 136 if (c.isSpace()) 137 continue; 138 139 int pos = map1.find(c); 140 if (pos >= 0) 141 c = map2[pos]; 142 143 ret += c; 144 } 145 146 return ret; 147 } 148 149 static bool parse_chan_info(const QString &line1, 150 QString &channum, QString &name) 151 { 152 // each line contains :// 153 // header:extension,channelNum - channelName rtsp://channelUrl 154 //#EXTINF:0,2 - France 2 rtsp://mafreebox.freebox.fr/freeboxtv/201 155 156 QString msg = LOC_ERR + 157 QString("Invalid header in channel list line \n\t\t\t%1").arg(line1); 158 159 channum = name = QString::null; 160 161 // Verify Line Header 162 int pos = line1.find(":", 0); 163 if ((pos < 0) || (line1.mid(0, pos) != "#EXTINF")) 164 { 165 VERBOSE(VB_IMPORTANT, msg); 166 return false; 167 } 168 169 // Parse extension portion 170 pos = line1.find(",", pos + 1); 171 if (pos < 0) 172 { 173 VERBOSE(VB_IMPORTANT, msg); 174 return false; 175 } 176 //list.push_back(line1.mid(oldPos, pos - oldPos)); 177 178 // Parse freebox channel number 179 int oldpos = pos + 1; 180 pos = line1.find(" ", pos + 1); 181 if (pos < 0) 182 { 183 VERBOSE(VB_IMPORTANT, msg); 184 return false; 185 } 186 channum = line1.mid(oldpos, pos - oldpos); 187 188 // Parse freebox channel name 189 pos = line1.find("- ", pos + 1); 190 if (pos < 0) 191 { 192 VERBOSE(VB_IMPORTANT, msg); 193 return false; 194 } 195 name = line1.mid(pos + 2, line1.length()); 196 197 return true; 198 } 199 200 /* vim: set expandtab tabstop = 4 shiftwidth = 4: */ -
libs/libmythtv/cardutil.cpp
571 571 572 572 if (("FIREWIRE" == cardtype) || 573 573 ("DBOX2" == cardtype) || 574 ("FREEBOX" == cardtype) || 574 575 ("HDHOMERUN" == cardtype) || 575 576 ("CRC_IP" == cardtype)) 576 577 { … … 804 805 805 806 if (("FIREWIRE" == cardtype) || 806 807 ("DBOX2" == cardtype) || 808 ("FREEBOX" == cardtype) || 807 809 ("HDHOMERUN" == cardtype) || 808 810 ("CRC_IP" == cardtype)) 809 811 { -
libs/libmythtv/freeboxmediasink.h
1 /** 2 * FreeboxMediaSink 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef _FREEBOXMEDIASINK_H_ 8 #define _FREEBOXMEDIASINK_H_ 9 10 #include <MediaSink.hh> 11 12 class FreeboxRecorder; 13 14 15 16 // ============================================================================ 17 // FreeboxMediaSink : Helper class use to receive RTSP data from socket. 18 // ============================================================================ 19 class FreeboxMediaSink: public MediaSink 20 { 21 public: 22 static FreeboxMediaSink* createNew(UsageEnvironment& env, 23 FreeboxRecorder& pRecorder, 24 unsigned bufferSize); 25 26 // Callback function when rtsp data are ready 27 void addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime); 28 29 protected: 30 FreeboxMediaSink(UsageEnvironment& env, 31 FreeboxRecorder& pRecorder, 32 unsigned bufferSize); 33 virtual ~FreeboxMediaSink(); 34 35 static void afterGettingFrame(void* clientData, 36 unsigned frameSize, 37 unsigned numTruncatedBytes, 38 struct timeval presentationTime, 39 unsigned durationInMicroseconds); 40 virtual void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime); 41 42 private: 43 virtual Boolean continuePlaying(); 44 45 private: 46 unsigned char* fBuffer; 47 unsigned fBufferSize; 48 UsageEnvironment& env; 49 FreeboxRecorder& recorder; 50 51 private: 52 // avoid default contructors & operator= 53 FreeboxMediaSink(); 54 FreeboxMediaSink(const FreeboxMediaSink&); 55 FreeboxMediaSink& operator=(const FreeboxMediaSink&); 56 }; 57 58 #endif//_FREEBOXMEDIASINK_H_ -
libs/libmythtv/videosource.cpp
993 993 } 994 994 }; 995 995 996 class FreeboxHost : public LineEditSetting, public CCSetting { 997 public: 998 FreeboxHost(const CaptureCard &parent): 999 CCSetting(parent, "freebox_mrl") 1000 { 1001 setValue("http://mafreebox.freebox.fr/freeboxtv/playlist.m3u"); 1002 setLabel(QObject::tr("Freebox MRL")); 1003 setHelpText(QObject::tr("The freebox Media Resource Locator (MRL).")); 1004 } 1005 }; 1006 996 1007 class HDHomeRunTunerIndex: public ComboBoxSetting, public CCSetting 997 1008 { 998 1009 public: … … 1005 1016 } 1006 1017 }; 1007 1018 1019 class FreeboxConfigurationGroup: public VerticalConfigurationGroup { 1020 public: 1021 FreeboxConfigurationGroup(CaptureCard& a_parent): 1022 ConfigurationGroup(false, true, false, false), 1023 VerticalConfigurationGroup(false, true, false, false), 1024 parent(a_parent) 1025 { 1026 setUseLabel(false); 1027 addChild(new FreeboxHost(parent)); 1028 }; 1029 private: 1030 CaptureCard& parent; 1031 }; 1032 1008 1033 void HDHRCardInput::fillSelections(const QString&) 1009 1034 { 1010 1035 clearSelections(); … … 1229 1254 addTarget("DBOX2", new DBOX2ConfigurationGroup(parent)); 1230 1255 #endif // USING_DBOX2 1231 1256 1257 #ifdef USING_FREEBOX 1258 addTarget("FREEBOX", new FreeboxConfigurationGroup(parent)); 1259 #endif // USING_FREEBOX 1260 1232 1261 #ifdef USING_HDHOMERUN 1233 1262 addTarget("HDHOMERUN", new HDHomeRunConfigurationGroup(parent)); 1234 1263 #endif // USING_HDHOMERUN … … 1350 1379 QObject::tr("DBox2 TCP/IP cable box"), "DBOX2"); 1351 1380 #endif // USING_DBOX2 1352 1381 1382 #ifdef USING_FREEBOX 1383 setting->addSelection( 1384 QObject::tr("Freebox"), "FREEBOX"); 1385 #endif // USING_FREEBOX 1386 1353 1387 #ifdef USING_HDHOMERUN 1354 1388 setting->addSelection( 1355 1389 QObject::tr("HDHomeRun DTV tuner box"), "HDHOMERUN"); -
libs/libmythtv/freeboxrecorder.h
1 /** 2 * FreeboxRecorder 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXRECORDER_H_ 8 #define FREEBOXRECORDER_H_ 9 10 #include "dtvrecorder.h" 11 12 class FreeboxChannel; 13 class FreeboxRecorderImpl; 14 15 16 17 /** 18 * Constructs a FreeboxRecorder 19 */ 20 class FreeboxRecorder : public DTVRecorder 21 { 22 public: 23 FreeboxRecorder(TVRec *rec, FreeboxChannel *channel); 24 ~FreeboxRecorder(); 25 26 void StartRecording(void); //< RecorderBase 27 void StopRecording(void); //< DTVRecorder 28 29 // RecorderBase 30 void SetOptionsFromProfile(RecordingProfile *profile, 31 const QString &videodev, 32 const QString &audiodev, 33 const QString &vbidev); 34 35 void ChannelChanged(void); 36 37 private: 38 friend class FreeboxMediaSink; 39 40 bool Open(void); //< RecorderBase 41 void Close(void); 42 43 // Callback function to add MPEG2 TS data 44 void addData(unsigned char* data, unsigned dataSize, 45 struct timeval presentationTime); 46 47 bool StartRtsp(void); 48 void ResetEventLoop(void); 49 50 private: 51 FreeboxRecorderImpl* _impl; 52 }; 53 54 #endif //FREEBOXRECORDER_H_ 55 56 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/tv_rec.cpp
45 45 #include "dvbchannel.h" 46 46 #include "dbox2channel.h" 47 47 #include "hdhrchannel.h" 48 #include "freeboxchannel.h" 48 49 49 50 #include "recorderbase.h" 50 51 #include "NuppelVideoRecorder.h" … … 53 54 #include "dvbrecorder.h" 54 55 #include "dbox2recorder.h" 55 56 #include "hdhrrecorder.h" 57 #include "freeboxrecorder.h" 56 58 57 59 #ifdef USING_CRC_IP_NETWORK_REC 58 60 #include "crcipnetworkrecorder.h" … … 178 180 init_run = true; 179 181 #endif 180 182 } 183 else if (genOpt.cardtype == "FREEBOX") 184 { 185 #ifdef USING_FREEBOX 186 channel = new FreeboxChannel(this, genOpt.videodev); 187 if (!channel->Open()) 188 return false; 189 InitChannel(genOpt.defaultinput, startchannel); 190 init_run = true; 191 #endif 192 } 181 193 else if (genOpt.cardtype == "HDHOMERUN") 182 194 { 183 195 #ifdef USING_HDHOMERUN … … 867 879 recorder->SetOption("httpport", dboxOpt.httpport); 868 880 #endif // USING_DBOX2 869 881 } 882 else if (genOpt.cardtype == "FREEBOX") 883 { 884 #ifdef USING_FREEBOX 885 FreeboxChannel *chan = dynamic_cast<FreeboxChannel*>(channel); 886 recorder = new FreeboxRecorder(this, chan); 887 recorder->SetOption("mrl", genOpt.videodev); 888 #endif // USING_FREEBOX 889 } 870 890 else if (genOpt.cardtype == "HDHOMERUN") 871 891 { 872 892 #ifdef USING_HDHOMERUN -
libs/libmythtv/freeboxchannel_util.h
1 /** -*- Mode: c++ -*- 2 * FreeboxChannel utils 3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef _FREEBOXCHANNEL_UTIL_H_ 8 #define _FREEBOXCHANNEL_UTIL_H_ 9 10 // Qt headers 11 #include <qwaitcondition.h> 12 #include <qmutex.h> 13 #include <qobject.h> 14 #include <qstring.h> 15 #include <qmap.h> 16 17 class QHttp; 18 19 class FBChanInfo 20 { 21 public: 22 FBChanInfo() : 23 m_name(QString::null), m_xmltvid(QString::null), 24 m_url(QString::null) {} 25 26 FBChanInfo(const QString &name, const QString &xmltvid, 27 const QString &url) : 28 m_name(name), m_xmltvid(xmltvid), m_url(url) {} 29 30 bool isValid(void) const 31 { 32 return !m_name.isEmpty() && !m_xmltvid.isEmpty() && !m_url.isEmpty(); 33 } 34 35 public: 36 QString m_name; 37 QString m_xmltvid; 38 QString m_url; 39 }; 40 typedef QMap<QString,FBChanInfo> fbox_chan_map_t; 41 42 class FBChannelFetcher : public QObject 43 { 44 Q_OBJECT 45 public: 46 FBChannelFetcher(); 47 ~FBChannelFetcher(); 48 49 static fbox_chan_map_t GetChannels(const QString &videodev); 50 51 private slots: 52 void HttpRequestDone(bool error); 53 54 private: 55 fbox_chan_map_t LoadChannels(const QString &videodev, uint max_wait); 56 static fbox_chan_map_t ParseChannelList(const QString &rawdata); 57 58 private: 59 QHttp *m_http; 60 QMutex m_lock; 61 QWaitCondition m_load_channel_wait; 62 fbox_chan_map_t m_freeboxchannels; 63 }; 64 65 #endif // _FREEBOXCHANNEL_UTIL_H_ 66 67 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/tv_rec.h
237 237 void SetPseudoLiveTVRecording(ProgramInfo*); 238 238 void TeardownAll(void); 239 239 240 static bool GetDevices(int cardid,240 static bool GetDevices(int cardid, 241 241 GeneralDBOptions &general_opts, 242 242 DVBDBOptions &dvb_opts, 243 243 FireWireDBOptions &firewire_opts, … … 255 255 bool CreateChannel(const QString &startChanNum); 256 256 void InitChannel(const QString &inputname, const QString &startchannel); 257 257 void CloseChannel(void); 258 DBox2Channel *GetDBox2Channel(void);259 HDHRChannel *GetHDHRChannel(void);260 DVBChannel *GetDVBChannel(void);261 Channel *GetV4LChannel(void);262 258 259 DBox2Channel *GetDBox2Channel(void); 260 HDHRChannel *GetHDHRChannel(void); 261 DVBChannel *GetDVBChannel(void); 262 Channel *GetV4LChannel(void); 263 263 264 void SetupSignalMonitor(bool enable_table_monitoring, bool notify); 264 265 bool SetupDTVSignalMonitor(void); 265 266 void TeardownSignalMonitor(void); -
settings.pro
79 79 EXTRA_LIBS += $$CONFIG_AUDIO_JACK_LIBS 80 80 EXTRA_LIBS += $$CONFIG_FIREWIRE_LIBS 81 81 EXTRA_LIBS += $$CONFIG_DIRECTFB_LIBS 82 EXTRA_LIBS += $$CONFIG_LIVE_LIBS 82 83 83 84 EXTRA_LIBS += $$LOCAL_LIBDIR_OGL 84 85 EXTRA_LIBS += $$LOCAL_LIBDIR_X11