Ticket #2152: patch-freebox-unified-udp-v15.diff
File patch-freebox-unified-udp-v15.diff, 86.0 KB (added by , 18 years ago) |
---|
-
libs/libmythtv/freeboxsignalmonitor.cpp
2 2 3 3 // MythTV headers 4 4 #include "mpegstreamdata.h" 5 #include "freeboxchannel.h" 6 #include "freeboxfeederwrapper.h" 5 7 #include "freeboxsignalmonitor.h" 6 #include "rtspcomms.h"7 8 8 9 #undef DBG_SM 9 10 #define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \ … … 34 35 dtvMonitorRunning(false) 35 36 { 36 37 bool isLocked = false; 37 if (GetChannel()->GetRTSP()->Init()) 38 FreeboxChannelInfo chaninfo = GetChannel()->GetCurrentChanInfo(); 39 if (chaninfo.isValid()) 38 40 { 39 FreeboxChannelInfo chaninfo = GetChannel()->GetCurrentChanInfo(); 40 isLocked = (chaninfo.isValid() && 41 GetChannel()->GetRTSP()->Open(chaninfo.m_url)); 41 isLocked = GetChannel()->GetFeeder()->Open(chaninfo.m_url); 42 42 } 43 43 44 44 QMutexLocker locker(&statusLock); … … 51 51 */ 52 52 FreeboxSignalMonitor::~FreeboxSignalMonitor() 53 53 { 54 GetChannel()->Get RTSP()->RemoveListener(this);54 GetChannel()->GetFeeder()->RemoveListener(this); 55 55 Stop(); 56 56 } 57 57 … … 63 63 void FreeboxSignalMonitor::deleteLater(void) 64 64 { 65 65 disconnect(); // disconnect signals we may be sending... 66 GetChannel()->Get RTSP()->RemoveListener(this);66 GetChannel()->GetFeeder()->RemoveListener(this); 67 67 Stop(); 68 68 DTVSignalMonitor::deleteLater(); 69 69 } … … 74 74 void FreeboxSignalMonitor::Stop(void) 75 75 { 76 76 DBG_SM("Stop", "begin"); 77 GetChannel()->Get RTSP()->RemoveListener(this);77 GetChannel()->GetFeeder()->RemoveListener(this); 78 78 SignalMonitor::Stop(); 79 79 if (dtvMonitorRunning) 80 80 { 81 GetChannel()->Get RTSP()->Stop();81 GetChannel()->GetFeeder()->Stop(); 82 82 dtvMonitorRunning = false; 83 83 pthread_join(table_monitor_thread, NULL); 84 84 } … … 101 101 102 102 GetStreamData()->AddListeningPID(0); 103 103 104 GetChannel()->Get RTSP()->AddListener(this);105 GetChannel()->Get RTSP()->Run();106 GetChannel()->Get RTSP()->RemoveListener(this);104 GetChannel()->GetFeeder()->AddListener(this); 105 GetChannel()->GetFeeder()->Run(); 106 GetChannel()->GetFeeder()->RemoveListener(this); 107 107 108 108 dtvMonitorRunning = false; 109 109 DBG_SM("Run", "end"); 110 110 } 111 111 112 void FreeboxSignalMonitor::AddData( 113 unsigned char *data, unsigned dataSize, struct timeval) 112 void FreeboxSignalMonitor::ProcessTSPacket(const TSPacket &packet) 114 113 { 115 GetStreamData()->Process Data(data, dataSize);114 GetStreamData()->ProcessTSPacket(packet); 116 115 } 117 116 118 117 /** \fn FreeboxSignalMonitor::UpdateValues(void) -
libs/libmythtv/freeboxfeederudp.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederUdp 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include "freeboxfeederudp.h" 8 9 // Qt headers 10 #include <qurl.h> 11 12 // Live555 headers 13 #include <BasicUsageEnvironment.hh> 14 #include <Groupsock.hh> 15 #include <GroupsockHelper.hh> 16 #include <BasicUDPSource.hh> 17 #include <TunnelEncaps.hh> 18 19 // MythTV headers 20 #include "freeboxmediasink.h" 21 #include "mythcontext.h" 22 #include "tspacket.h" 23 24 #define LOC QString("FbFeedUdp(%1):").arg(pthread_self()) 25 26 27 FEEDERREG_IMPL(FreeboxFeederUdp,"udp://"); 28 29 30 FreeboxFeederUdp::FreeboxFeederUdp(StreamDataListener &listener) : 31 FreeboxFeederLive(listener), 32 _source(NULL), 33 _sink(NULL) 34 { 35 VERBOSE(VB_RECORD, LOC + "ctor -- success"); 36 } 37 38 FreeboxFeederUdp::~FreeboxFeederUdp() 39 { 40 VERBOSE(VB_RECORD, LOC + "dtor -- begin"); 41 Close(); 42 VERBOSE(VB_RECORD, LOC + "dtor -- end"); 43 } 44 45 bool FreeboxFeederUdp::Open(const QString &url) 46 { 47 VERBOSE(VB_RECORD, LOC + "Open(\""<<url<<"\") -- begin"); 48 49 QMutexLocker locker(&GetLock()); 50 51 if (_source) 52 { 53 VERBOSE(VB_RECORD, LOC + "Open() -- end 1"); 54 return true; 55 } 56 57 QUrl parse(url); 58 if (!parse.isValid() || !parse.hasHost() || !parse.hasPort()) 59 { 60 VERBOSE(VB_RECORD, LOC + "Open() -- end 2"); 61 return false; 62 } 63 64 struct in_addr addr; 65 addr.s_addr = our_inet_addr(parse.host().latin1()); 66 67 // Begin by setting up our usage environment: 68 if (!InitEnv()) 69 return false; 70 71 Groupsock *socket = new Groupsock(GetLiveEnv(), addr, parse.port(), 0); 72 if (!socket) 73 { 74 VERBOSE(VB_IMPORTANT, LOC + "Failed to create Live UDP Socket."); 75 FreeEnv(); 76 return false; 77 } 78 _source = BasicUDPSource::createNew(GetLiveEnv(), socket); 79 if (!_source) 80 { 81 VERBOSE(VB_IMPORTANT, LOC + "Failed to create Live UDP Source."); 82 delete socket; 83 FreeEnv(); 84 return false; 85 } 86 87 _sink = FreeboxMediaSink::CreateNew( 88 GetLiveEnv(), GetListener(), TSPacket::SIZE * 128*1024); 89 if (!_sink) 90 { 91 VERBOSE(VB_IMPORTANT, 92 QString("Freebox # Failed to create sink: %1") 93 .arg(GetLiveEnv().getResultMsg())); 94 Medium::close(_source); 95 _source = NULL; 96 delete socket; 97 FreeEnv(); 98 return false; 99 } 100 _sink->startPlaying(*_source, NULL, NULL); 101 102 VERBOSE(VB_RECORD, LOC + "Open() -- end"); 103 return true; 104 } 105 106 void FreeboxFeederUdp::Close(void) 107 { 108 VERBOSE(VB_RECORD, LOC + "Close() -- begin"); 109 Stop(); 110 111 QMutexLocker locker(&GetLock()); 112 113 if (_sink) 114 { 115 Medium::close(_sink); 116 _sink = NULL; 117 } 118 119 if (_source) 120 { 121 Groupsock *socket=_source->gs(); 122 Medium::close(_source); 123 _source=NULL; 124 delete socket; 125 } 126 127 FreeEnv(); 128 129 VERBOSE(VB_RECORD, LOC + "Close() -- end"); 130 } -
libs/libmythtv/tspacketsplitter.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederUdp 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef _TSPACKETSPLITTER_H_ 8 #define _TSPACKETSPLITTER_H_ 9 10 #include "streamdatalistener.h" 11 12 class TSPacketListener; 13 14 15 class TSPacketSplitter : public StreamDataListener 16 { 17 public: 18 explicit TSPacketSplitter(TSPacketListener &listener); 19 ~TSPacketSplitter(); 20 21 void Reset(void); 22 23 public: // implements StreamDataListener 24 void AddData(unsigned char *data, unsigned int dataSize); 25 26 private: 27 TSPacketListener &_listener; 28 unsigned char *_buffer; 29 int _bufferIndex; 30 31 private: 32 /// avoid default copy operator 33 TSPacketSplitter& operator=(const TSPacketSplitter&); 34 /// avoid default copy constructor 35 TSPacketSplitter(const TSPacketSplitter&); 36 /// avoid default constructor 37 TSPacketSplitter(); 38 }; 39 40 #endif//_TSPACKETSPLITTER_H_ -
libs/libmythtv/streamdatalistener.h
1 /** -*- Mode: c++ -*- 2 * StreamDataListener 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 _STREAMDATALISTENER_H_ 8 #define _STREAMDATALISTENER_H_ 9 10 11 class StreamDataListener 12 { 13 public: 14 /// Callback function to add MPEG2 TS data 15 virtual void AddData(unsigned char *data, 16 unsigned int dataSize) = 0; 17 protected: 18 virtual ~StreamDataListener() {} 19 }; 20 21 #endif//_STREAMDATALISTENER_H_ -
libs/libmythtv/freeboxfeederfile.h
1 /** -*- Mode: c++ -* 2 * FreeboxFeederFile 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXFEEDERFILE_H 8 #define FREEBOXFEEDERFILE_H 9 10 // MythTV headers 11 #include "freeboxfeederlive.h" 12 #include "freeboxfeederwrapper.h" 13 14 class ByteStreamFileSource; 15 class FreeboxMediaSink; 16 17 18 class FreeboxFeederFile : public FreeboxFeederLive 19 { 20 public: 21 FreeboxFeederFile(StreamDataListener &listener); 22 virtual ~FreeboxFeederFile(); 23 24 bool Open(const QString &url); 25 bool IsOpen(void) const { return _source; } 26 void Close(void); 27 28 private: 29 ByteStreamFileSource *_source; 30 FreeboxMediaSink *_sink; 31 32 private: 33 /// avoid default copy operator 34 FreeboxFeederFile& operator=(const FreeboxFeederFile&); 35 /// avoid default copy constructor 36 FreeboxFeederFile(const FreeboxFeederFile&); 37 /// avoid default constructor 38 FreeboxFeederFile(); 39 40 FEEDERREG_DECL 41 }; 42 43 #endif//FREEBOXFEEDERFILE_H -
libs/libmythtv/freeboxchannel.h
12 12 13 13 #include <qmutex.h> 14 14 15 class RTSPComms;15 class FreeboxFeederWrapper; 16 16 17 17 class FreeboxChannel : public ChannelBase 18 18 { … … 32 32 FreeboxChannelInfo GetCurrentChanInfo(void) const 33 33 { return GetChanInfo(curchannelname); } 34 34 35 RTSPComms *GetRTSP(void) { return m_rtsp; }36 const RTSPComms *GetRTSP(void) const { return m_rtsp; }35 FreeboxFeederWrapper *GetFeeder(void) { return m_feeder; } 36 const FreeboxFeederWrapper *GetFeeder(void) const { return m_feeder; } 37 37 38 38 private: 39 39 FreeboxChannelInfo GetChanInfo(const QString& channum, … … 41 41 42 42 QString m_videodev; 43 43 fbox_chan_map_t m_freeboxchannels; 44 RTSPComms *m_rtsp;44 FreeboxFeederWrapper *m_feeder; 45 45 mutable QMutex m_lock; 46 46 47 47 private: -
libs/libmythtv/freeboxchannelfetcher.h
7 7 // Qt headers 8 8 #include <qobject.h> 9 9 #include <qmutex.h> 10 #include <qurloperator.h> 10 11 11 12 // MythTV headers 12 13 #include "freeboxchannelinfo.h" 13 14 15 class FreeboxUrlFetch : public QObject 16 { 17 Q_OBJECT 18 19 private: 20 FreeboxUrlFetch(const QString& url); 21 ~FreeboxUrlFetch(); 22 23 QUrlOperator *op; 24 QNetworkProtocol::State state; 25 QString str; 26 27 private slots: 28 void finished(QNetworkOperation *op); 29 void data(const QByteArray &data,QNetworkOperation *op); 30 31 public: 32 static QString fetchData(const QString &url,bool inQtThread); 33 }; 34 14 35 class FreeboxChannelFetcher : public QObject 15 36 { 16 37 Q_OBJECT -
libs/libmythtv/libmythtv.pro
396 396 using_freebox { 397 397 HEADERS += freeboxrecorder.h freeboxmediasink.h 398 398 HEADERS += freeboxchannel.h freeboxchannelfetcher.h 399 HEADERS += freeboxsignalmonitor.h rtspcomms.h 400 HEADERS += freeboxchannelinfo.h 399 HEADERS += freeboxsignalmonitor.h freeboxchannelinfo.h 400 HEADERS += freeboxfeeder.h freeboxfeederlive.h 401 HEADERS += freeboxfeederrtsp.h freeboxfeederudp.h 402 HEADERS += freeboxfeederfile.h freeboxfeederwrapper.h 403 HEADERS += streamdatalistener.h timeoutedtaskscheduler.h 404 HEADERS += tspacketlistener.h tspacketsplitter.h 405 HEADERS += freeboxfeederrtp.h 401 406 402 407 SOURCES += freeboxrecorder.cpp freeboxmediasink.cpp 403 408 SOURCES += freeboxchannel.cpp freeboxchannelfetcher.cpp 404 SOURCES += freeboxsignalmonitor.cpp rtspcomms.cpp 409 SOURCES += freeboxsignalmonitor.cpp freeboxfeederwrapper.cpp 410 SOURCES += freeboxfeederlive.cpp freeboxfeederrtsp.cpp 411 SOURCES += freeboxfeederudp.cpp freeboxfeederfile.cpp 412 SOURCES += timeoutedtaskscheduler.cpp tspacketsplitter.cpp 413 SOURCES += freeboxfeederrtp.cpp 405 414 406 415 DEFINES += USING_FREEBOX 407 416 } -
libs/libmythtv/freeboxchannel.cpp
11 11 #include "libmyth/mythcontext.h" 12 12 #include "libmyth/mythdbcon.h" 13 13 #include "libmythtv/freeboxchannelfetcher.h" 14 #include "libmythtv/ rtspcomms.h"14 #include "libmythtv/freeboxfeederwrapper.h" 15 15 16 16 #define LOC QString("FBChan(%1): ").arg(GetCardID()) 17 17 #define LOC_ERR QString("FBChan(%1), Error: ").arg(GetCardID()) … … 20 20 const QString &videodev) 21 21 : ChannelBase(parent), 22 22 m_videodev(QDeepCopy<QString>(videodev)), 23 m_ rtsp(new RTSPComms()),23 m_feeder(new FreeboxFeederWrapper()), 24 24 m_lock(true) 25 25 { 26 26 VERBOSE(VB_CHANNEL, LOC + "ctor"); … … 29 29 FreeboxChannel::~FreeboxChannel() 30 30 { 31 31 VERBOSE(VB_CHANNEL, LOC + "dtor -- begin"); 32 if (m_ rtsp)32 if (m_feeder) 33 33 { 34 delete m_ rtsp;35 m_ rtsp= NULL;34 delete m_feeder; 35 m_feeder = NULL; 36 36 } 37 37 VERBOSE(VB_CHANNEL, LOC + "dtor -- end"); 38 38 } … … 193 193 } 194 194 195 195 // Try to map name to a channel in the map 196 const QString name = query.value(1).toString();196 const QString name = QString::fromUtf8(query.value(1).toString()); 197 197 for (it = m_freeboxchannels.begin(); 198 198 it != m_freeboxchannels.end(); ++it) 199 199 { -
libs/libmythtv/freeboxfeederlive.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederLive -- base class for livemedia based FreeboxFeeders 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 "freeboxfeederlive.h" 8 9 #include <cassert> 10 11 // MythTV headers 12 #include "mythcontext.h" 13 #include "timeoutedtaskscheduler.h" 14 15 #define LOC QString("FbFeedLive(%1):").arg(pthread_self()) 16 #define LOC_ERR QString("FbFeedLive(%1), Error:").arg(pthread_self()) 17 18 19 FreeboxFeederLive::FreeboxFeederLive(StreamDataListener &listener) : 20 _abort(0), 21 _running(false), 22 _live_env(NULL), 23 _lock(false), 24 _listener(listener) 25 { 26 } 27 28 FreeboxFeederLive::~FreeboxFeederLive() 29 { 30 } 31 32 bool FreeboxFeederLive::InitEnv(void) 33 { 34 TaskScheduler *scheduler = new TimeoutedTaskScheduler(500); 35 if (!scheduler) 36 { 37 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create Live Scheduler."); 38 return false; 39 } 40 41 assert(_live_env==NULL); 42 _live_env = BasicUsageEnvironment::createNew(*scheduler); 43 if (!_live_env) 44 { 45 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create Live Environment."); 46 delete scheduler; 47 return false; 48 } 49 50 return true; 51 } 52 53 void FreeboxFeederLive::FreeEnv(void) 54 { 55 if (_live_env) 56 { 57 TaskScheduler *scheduler = &_live_env->taskScheduler(); 58 _live_env->reclaim(); 59 _live_env = NULL; 60 delete scheduler; 61 } 62 } 63 64 void FreeboxFeederLive::Run(void) 65 { 66 VERBOSE(VB_RECORD, LOC + "Run() -- begin"); 67 _lock.lock(); 68 _running = true; 69 _abort = 0; 70 _lock.unlock(); 71 72 VERBOSE(VB_RECORD, LOC + "Run() -- loop begin"); 73 if (_live_env) 74 _live_env->taskScheduler().doEventLoop(&_abort); 75 VERBOSE(VB_RECORD, LOC + "Run() -- loop end"); 76 77 _lock.lock(); 78 _running = false; 79 _cond.wakeAll(); 80 _lock.unlock(); 81 VERBOSE(VB_RECORD, LOC + "Run() -- end"); 82 } 83 84 void FreeboxFeederLive::Stop(void) 85 { 86 VERBOSE(VB_RECORD, LOC + "Stop() -- begin"); 87 QMutexLocker locker(&_lock); 88 _abort = 0xFF; 89 90 while (_running) 91 _cond.wait(&_lock, 500); 92 VERBOSE(VB_RECORD, LOC + "Stop() -- end"); 93 } -
libs/libmythtv/freeboxmediasink.cpp
4 4 * Distributed as part of MythTV under GPL v2 and later. 5 5 */ 6 6 7 #include <algorithm>8 using namespace std;9 10 #include "mythcontext.h"11 7 #include "freeboxmediasink.h" 12 #include "rtspcomms.h" 8 #include "mythcontext.h" 9 #include "streamdatalistener.h" 13 10 14 #define LOC QString(" RTSPSink:")15 #define LOC_ERR QString(" RTSPSink, Error:")11 #define LOC QString("FbxSink:") 12 #define LOC_ERR QString("FbxSink, Error:") 16 13 17 FreeboxMediaSink::FreeboxMediaSink(UsageEnvironment &pEnv, 18 unsigned int bufferSize) : 19 MediaSink(pEnv), fBufferSize(bufferSize), 20 env(pEnv), lock(true) 14 FreeboxMediaSink::FreeboxMediaSink(UsageEnvironment &pEnv, 15 StreamDataListener &listener, 16 unsigned int bufferSize) : 17 MediaSink(pEnv), 18 fBufferSize(bufferSize), 19 env(pEnv), 20 _listener(listener), 21 lock(true) 21 22 { 22 23 fBuffer = new unsigned char[fBufferSize]; 23 24 } … … 31 32 } 32 33 } 33 34 34 FreeboxMediaSink *FreeboxMediaSink::CreateNew(UsageEnvironment &env, 35 unsigned int bufferSize) 35 FreeboxMediaSink *FreeboxMediaSink::CreateNew(UsageEnvironment &env, 36 StreamDataListener &listener, 37 unsigned int bufferSize) 36 38 { 37 return new FreeboxMediaSink(env, bufferSize);39 return new FreeboxMediaSink(env, listener, bufferSize); 38 40 } 39 41 40 42 Boolean FreeboxMediaSink::continuePlaying(void) … … 61 63 } 62 64 63 65 void FreeboxMediaSink::afterGettingFrame1(unsigned int frameSize, 64 struct timeval presentationTime)66 struct timeval) 65 67 { 66 lock.lock(); 67 vector<RTSPListener*>::iterator it = listeners.begin(); 68 for (; it != listeners.end(); ++it) 69 (*it)->AddData(fBuffer, frameSize, presentationTime); 70 lock.unlock(); 71 68 _listener.AddData(fBuffer, frameSize); 72 69 continuePlaying(); 73 70 } 74 71 75 void FreeboxMediaSink::AddListener(RTSPListener *item)76 {77 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- begin");78 if (item)79 {80 RemoveListener(item);81 QMutexLocker locker(&lock);82 listeners.push_back(item);83 }84 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end");85 }86 87 void FreeboxMediaSink::RemoveListener(RTSPListener *item)88 {89 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- begin 1");90 QMutexLocker locker(&lock);91 vector<RTSPListener*>::iterator it =92 find(listeners.begin(), listeners.end(), item);93 if (it != listeners.end())94 {95 *it = *listeners.rbegin();96 listeners.resize(listeners.size() - 1);97 }98 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 6");99 }100 101 72 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/freeboxsignalmonitor.h
4 4 #define _FREEBOXSIGNALMONITOR_H_ 5 5 6 6 #include "dtvsignalmonitor.h" 7 #include " freeboxmediasink.h"7 #include "tspacketlistener.h" 8 8 9 class RTSPComms;10 9 class FreeboxChannel; 11 10 12 class FreeboxSignalMonitor : public DTVSignalMonitor, public RTSPListener 11 12 class FreeboxSignalMonitor : public DTVSignalMonitor, public TSPacketListener 13 13 { 14 14 Q_OBJECT 15 15 … … 21 21 22 22 void Stop(void); 23 23 24 // implements RTSPListener 25 void AddData(unsigned char *data, 26 unsigned dataSize, 27 struct timeval); 24 // implements TSPacketListener 25 void ProcessTSPacket(const TSPacket &packet); 28 26 29 27 public slots: 30 28 void deleteLater(void); -
libs/libmythtv/freeboxfeederwrapper.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederWrapper 3 * Copyright (c) 2006 by Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include <qstring.h> 8 #include <vector> 9 10 #include "freeboxfeederwrapper.h" 11 12 #include "freeboxfeeder.h" 13 #include "mythcontext.h" 14 15 #define LOC QString("FBFeed: ") 16 #define LOC_ERR QString("FBFeed, Error: ") 17 18 // Registration of feeders 19 class FreeboxRegistratorSinglton 20 { 21 public: 22 static FreeboxRegistratorSinglton &getInstance(void); 23 24 void Register(FreeboxFeederWrapper::CanHandleFn, 25 FreeboxFeederWrapper::FeederConstructorFn); 26 FreeboxFeeder *CreateNew(const QString &url, StreamDataListener &listener); 27 bool HaveHandler(const QString &url); 28 29 private: 30 // default construct is private to force use of getInstance() 31 FreeboxRegistratorSinglton() {} 32 FreeboxFeederWrapper::FeederConstructorFn GetConstructor(const QString &); 33 34 private: 35 typedef std::pair<FreeboxFeederWrapper::CanHandleFn, 36 FreeboxFeederWrapper::FeederConstructorFn> FuncPair; 37 std::vector<FuncPair> _regdata; 38 39 private: 40 // avoid default copy operator 41 FreeboxRegistratorSinglton &operator=(const FreeboxRegistratorSinglton&); 42 // avoid default copy constructor 43 FreeboxRegistratorSinglton(const FreeboxRegistratorSinglton&); 44 }; 45 46 FreeboxRegistratorSinglton &FreeboxRegistratorSinglton::getInstance() 47 { 48 static FreeboxRegistratorSinglton instance = FreeboxRegistratorSinglton(); 49 return instance; 50 } 51 52 void FreeboxRegistratorSinglton::Register( 53 FreeboxFeederWrapper::CanHandleFn f1, 54 FreeboxFeederWrapper::FeederConstructorFn f2) 55 { 56 _regdata.push_back(FuncPair(f1,f2)); 57 } 58 59 FreeboxFeederWrapper::FeederConstructorFn 60 FreeboxRegistratorSinglton::GetConstructor(const QString &url) 61 { 62 std::vector<FuncPair>::const_iterator it = _regdata.begin(); 63 std::vector<FuncPair>::const_iterator end = _regdata.end(); 64 for( ; it!=end ; ++it ) 65 if (it->first(url)) 66 return it->second; 67 return NULL; 68 } 69 70 FreeboxFeeder *FreeboxRegistratorSinglton::CreateNew( 71 const QString &url, 72 StreamDataListener &listener) 73 { 74 FreeboxFeederWrapper::FeederConstructorFn func = GetConstructor(url); 75 return func ? func(listener) : NULL; 76 } 77 78 bool FreeboxRegistratorSinglton::HaveHandler(const QString &url) 79 { 80 return GetConstructor(url); 81 } 82 83 84 85 void FreeboxFeederWrapper::RegisterHandler( 86 CanHandleFn f1, 87 FeederConstructorFn f2) 88 { 89 FreeboxRegistratorSinglton::getInstance().Register(f1,f2); 90 } 91 92 bool FreeboxFeederWrapper::HaveHandler(const QString &url) 93 { 94 return FreeboxRegistratorSinglton::getInstance().HaveHandler(url); 95 } 96 97 FreeboxFeederWrapper::FreeboxFeederWrapper() : 98 _splitter(*this), 99 _feeder(NULL) 100 { 101 } 102 103 FreeboxFeederWrapper::~FreeboxFeederWrapper() 104 { 105 if (_feeder) 106 { 107 _feeder->Stop(); 108 _feeder->Close(); 109 delete _feeder; 110 } 111 } 112 113 FreeboxFeeder* FreeboxFeederWrapper::NewFeeder(const QString &url, 114 StreamDataListener &listener) 115 { 116 FreeboxFeeder *result = FreeboxRegistratorSinglton::getInstance() 117 .CreateNew(url,listener); 118 if (!result) 119 { 120 VERBOSE(VB_RECORD, LOC_ERR + 121 QString("NewFeeder() -- unhandled url (%1)").arg(url)); 122 } 123 return result; 124 } 125 126 bool FreeboxFeederWrapper::InitFeeder(const QString &url) 127 { 128 VERBOSE(VB_RECORD, LOC + "Init() -- begin"); 129 QMutexLocker locker(&_lock); 130 if (_feeder && _feeder->CanHandle(url)) 131 { 132 VERBOSE(VB_RECORD, LOC + "Init() -- end 0"); 133 return true; 134 } 135 136 delete _feeder; 137 _feeder = NewFeeder(url, _splitter); 138 139 VERBOSE(VB_RECORD, LOC + "Init() -- end 1"); 140 return _feeder != NULL; 141 } 142 143 bool FreeboxFeederWrapper::Open(const QString& url) 144 { 145 VERBOSE(VB_RECORD, LOC + "Open() -- begin"); 146 _splitter.Reset(); 147 bool result = InitFeeder(url) && _feeder->Open(url); 148 VERBOSE(VB_RECORD, LOC + "Open() -- end"); 149 return result; 150 } 151 152 bool FreeboxFeederWrapper::IsOpen(void) const 153 { 154 VERBOSE(VB_RECORD, LOC + "IsOpen() -- begin"); 155 bool result = _feeder && _feeder->IsOpen(); 156 VERBOSE(VB_RECORD, LOC + "IsOpen() -- end"); 157 return result; 158 } 159 160 void FreeboxFeederWrapper::Close(void) 161 { 162 VERBOSE(VB_RECORD, LOC + "Close() -- begin"); 163 _splitter.Reset(); 164 if (_feeder) _feeder->Close(); 165 VERBOSE(VB_RECORD, LOC + "Close() -- end"); 166 } 167 168 void FreeboxFeederWrapper::Run(void) 169 { 170 VERBOSE(VB_RECORD, LOC + "Run() -- begin"); 171 _splitter.Reset(); 172 if (_feeder) _feeder->Run(); 173 VERBOSE(VB_RECORD, LOC + "Run() -- end"); 174 } 175 176 void FreeboxFeederWrapper::Stop(void) 177 { 178 VERBOSE(VB_RECORD, LOC + "Stop() -- begin"); 179 _splitter.Reset(); 180 if (_feeder) _feeder->Stop(); 181 VERBOSE(VB_RECORD, LOC + "Stop() -- end"); 182 } 183 184 void FreeboxFeederWrapper::AddListener(TSPacketListener *item) 185 { 186 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- begin"); 187 if (!item) 188 { 189 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 0"); 190 return; 191 } 192 193 QMutexLocker locker(&_lock); 194 std::vector<TSPacketListener*>::iterator it = 195 find(_listeners.begin(), _listeners.end(), item); 196 if (it == _listeners.end()) // avoid duplicates 197 _listeners.push_back(item); 198 199 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 1"); 200 } 201 202 void FreeboxFeederWrapper::RemoveListener(TSPacketListener *item) 203 { 204 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- begin"); 205 QMutexLocker locker(&_lock); 206 std::vector<TSPacketListener*>::iterator it = 207 find(_listeners.begin(), _listeners.end(), item); 208 209 if (it == _listeners.end()) 210 { 211 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end (not found)"); 212 return; 213 } 214 215 // remove from local list.. 216 *it = *_listeners.rbegin(); 217 _listeners.resize(_listeners.size() - 1); 218 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end (ok, removed)"); 219 } 220 221 void FreeboxFeederWrapper::ProcessTSPacket(const TSPacket &packet) 222 { 223 QMutexLocker locker(&_lock); 224 std::vector<TSPacketListener*>::iterator it = _listeners.begin(); 225 std::vector<TSPacketListener*>::iterator end = _listeners.end(); 226 for( ; it!=end ; ++it ) 227 (*it)->ProcessTSPacket(packet); 228 } -
libs/libmythtv/freeboxchannelfetcher.cpp
4 4 #include <cmath> 5 5 #include <unistd.h> 6 6 7 // Qt headers 8 #include <qnetwork.h> 9 #include <qapplication.h> 10 7 11 // MythTV headers 8 12 #include "mythcontext.h" 9 13 #include "httpcomms.h" 10 14 #include "cardutil.h" 11 15 #include "channelutil.h" 12 16 #include "freeboxchannelfetcher.h" 17 #include "freeboxfeederwrapper.h" 13 18 14 19 #define LOC QString("FBChanFetch: ") 15 20 #define LOC_ERR QString("FBChanFetch, Error: ") … … 21 26 static bool parse_extinf(const QString &data, 22 27 QString &channum, QString &name); 23 28 29 FreeboxUrlFetch::FreeboxUrlFetch(const QString& url) 30 : op(new QUrlOperator(url)), 31 state(QNetworkProtocol::StInProgress), 32 str("") 33 { 34 connect(op, SIGNAL( finished(QNetworkOperation *)), 35 this, SLOT( finished(QNetworkOperation *))); 36 connect(op, SIGNAL( data(const QByteArray &,QNetworkOperation *)), 37 this, SLOT( data(const QByteArray &,QNetworkOperation *))); 38 op->get(); 39 } 40 41 FreeboxUrlFetch::~FreeboxUrlFetch() 42 { 43 disconnect(); 44 delete op; 45 op=NULL; 46 } 47 48 void FreeboxUrlFetch::finished(QNetworkOperation *op) 49 { 50 state = op->state(); 51 } 52 53 void FreeboxUrlFetch::data(const QByteArray &data,QNetworkOperation *op) 54 { 55 if (!data.isNull()) 56 str += QString::fromUtf8(data.data(),data.size()); 57 state = op->state(); 58 } 59 60 QString FreeboxUrlFetch::fetchData(const QString &url,bool inQtThread) 61 { 62 FreeboxUrlFetch obj(url); 63 while(obj.state==QNetworkProtocol::StWaiting || 64 obj.state==QNetworkProtocol::StInProgress) 65 { 66 if (inQtThread) 67 qApp->processEvents(); 68 usleep(1000); 69 } 70 if (obj.state==QNetworkProtocol::StDone) 71 return obj.str; 72 else // QNetworkProtocol::StFailed || QNetworkProtocol::StStopped 73 return QString::null; 74 } 75 76 24 77 FreeboxChannelFetcher::FreeboxChannelFetcher(unsigned _sourceid, 25 78 unsigned _cardid) : 26 79 sourceid(_sourceid), cardid(_cardid), … … 177 230 QString FreeboxChannelFetcher::DownloadPlaylist(const QString &url, 178 231 bool inQtThread) 179 232 { 180 QString redirected_url = url; 233 if (url.startsWith("http:")) { 234 // Use Myth HttpComms for http URLs 235 QString redirected_url = url; 181 236 182 QString tmp = HttpComms::getHttp(183 redirected_url,184 10000 /* ms */, 3 /* retries */,185 3 /* redirects */, true /* allow gzip */,186 NULL /* login */, inQtThread);237 QString tmp = HttpComms::getHttp( 238 redirected_url, 239 10000 /* ms */, 3 /* retries */, 240 3 /* redirects */, true /* allow gzip */, 241 NULL /* login */, inQtThread); 187 242 188 if (redirected_url != url)189 {190 VERBOSE(VB_CHANNEL, QString("Channel URL redirected to %1")191 .arg(redirected_url));192 }243 if (redirected_url != url) 244 { 245 VERBOSE(VB_CHANNEL, QString("Channel URL redirected to %1") 246 .arg(redirected_url)); 247 } 193 248 194 return QString::fromUtf8(tmp); 249 return QString::fromUtf8(tmp); 250 } else 251 return FreeboxUrlFetch::fetchData(url,inQtThread); 195 252 } 196 253 197 254 static uint estimate_number_of_channels(const QString &rawdata) … … 251 308 QString msg = tr("Encountered malformed channel"); 252 309 if (!channum.isEmpty()) 253 310 { 254 chanmap[channum] = info; 255 256 msg = tr("Parsing Channel #%1 : %2 : %3") 257 .arg(channum).arg(info.m_name).arg(info.m_url); 258 VERBOSE(VB_CHANNEL, msg); 259 260 msg = QString::null; // don't tell fetcher 311 if (FreeboxFeederWrapper::HaveHandler(info.m_url)) 312 { 313 chanmap[channum] = info; 314 315 msg = tr("Parsing Channel #%1 : %2 : %3") 316 .arg(channum).arg(info.m_name).arg(info.m_url); 317 VERBOSE(VB_CHANNEL, msg); 318 319 msg = QString::null; // don't tell fetcher 320 } 321 else 322 { 323 msg = tr("Unhandled url %1").arg(info.m_url); 324 VERBOSE(VB_CHANNEL, msg); 325 } 261 326 } 262 327 263 328 if (fetcher) -
libs/libmythtv/tspacketsplitter.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederUdp 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include <cassert> 8 9 #include "tspacketsplitter.h" 10 11 #include "mythcontext.h" 12 #include "tspacket.h" 13 #include "tspacketlistener.h" 14 15 #define LOC_ERR QString("TSSplit, Error: ") 16 #define LOC_WARN QString("TSSplit, Warning: ") 17 18 19 TSPacketSplitter::TSPacketSplitter(TSPacketListener &listener) : 20 _listener(listener), 21 _buffer(new unsigned char[TSPacket::SIZE]), 22 _bufferIndex(0) 23 { 24 } 25 26 TSPacketSplitter::~TSPacketSplitter() 27 { 28 delete[] _buffer; 29 } 30 31 void TSPacketSplitter::Reset(void) 32 { 33 _bufferIndex = 0; 34 } 35 36 // =================================================== 37 // findTSHeader : find a TS Header in flow 38 // =================================================== 39 static int TSPacketSplitter_findTSHeader(const unsigned char *data, 40 uint dataSize) 41 { 42 //TODO improve this with code from MPEGStreamData::ResyncStream() 43 for(unsigned pos = 0; pos < dataSize; ++pos) 44 if (data[pos] == 0x47) 45 return pos; 46 47 return -1; 48 } 49 50 // =================================================== 51 // AddData : feed data from flow to listeners 52 // =================================================== 53 void TSPacketSplitter::AddData(unsigned char *data, 54 unsigned dataSize) 55 { 56 if (_bufferIndex) 57 { 58 // Have old data in buffer 59 unsigned reminder = TSPacket::SIZE - _bufferIndex; 60 memcpy(_buffer + _bufferIndex, data, min(reminder, dataSize)); 61 if (dataSize < reminder) 62 { 63 _bufferIndex += dataSize; 64 return; 65 } 66 else 67 { 68 // We got full packet 69 data += reminder; 70 dataSize -= reminder; 71 // Cast current found TS Packet to TSPacket structure 72 const TSPacket &packet = *reinterpret_cast<const TSPacket*>(_buffer); 73 _listener.ProcessTSPacket(packet); 74 } 75 } 76 77 unsigned int readIndex = 0; 78 79 // data may be compose from more than one packet, loop to consume all data 80 while (readIndex < dataSize) 81 { 82 // Find the next TS Header in data 83 int tsPos = TSPacketSplitter_findTSHeader( 84 data + readIndex, dataSize - readIndex); 85 86 // if no TS, something bad happens 87 if (-1 == tsPos) 88 { 89 readIndex = dataSize; 90 VERBOSE(VB_IMPORTANT, LOC_ERR + "No TS header."); 91 break; 92 } 93 94 // if TS Header not at start of data, we receive out of sync data 95 if (tsPos > 0) 96 { 97 VERBOSE(VB_IMPORTANT, LOC_ERR + 98 QString("TS packet at %1, not in sync.").arg(tsPos)); 99 } 100 101 // Check if the next packet in buffer is complete : 102 // packet size is 188 bytes long 103 if ((dataSize - tsPos - readIndex) < TSPacket::SIZE) 104 { 105 readIndex += tsPos; 106 VERBOSE(VB_IMPORTANT, LOC_ERR + 107 "TS packet at stradles end of buffer."); 108 break; 109 } 110 111 // Cast current found TS Packet to TSPacket structure 112 const void *p = data + tsPos + readIndex; 113 const TSPacket &packet = *reinterpret_cast<const TSPacket*>(p); 114 _listener.ProcessTSPacket(packet); 115 116 // follow to next packet 117 readIndex += tsPos + TSPacket::SIZE; 118 } 119 120 // write in buffer synced data 121 if (readIndex < dataSize) 122 { 123 assert(dataSize - readIndex < TSPacket::SIZE); 124 memcpy(_buffer, data + readIndex, dataSize - readIndex); 125 _bufferIndex = dataSize - readIndex; 126 } 127 else 128 _bufferIndex = 0; 129 } -
libs/libmythtv/freeboxfeederrtsp.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederRtsp 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 FREEBOXFEEDERRTSP_H 8 #define FREEBOXFEEDERRTSP_H 9 10 // MythTV headers 11 #include "freeboxfeederwrapper.h" 12 #include "freeboxfeederlive.h" 13 14 class RTSPClient; 15 class MediaSession; 16 17 18 class FreeboxFeederRtsp : public FreeboxFeederLive 19 { 20 public: 21 FreeboxFeederRtsp(StreamDataListener &listener); 22 virtual ~FreeboxFeederRtsp(); 23 24 bool Open(const QString &url); 25 bool IsOpen(void) const { return _session; } 26 void Close(void); 27 28 private: 29 RTSPClient *_rtsp_client; 30 MediaSession *_session; 31 32 private: 33 /// avoid default copy operator 34 FreeboxFeederRtsp& operator=(const FreeboxFeederRtsp&); 35 /// avoid default copy constructor 36 FreeboxFeederRtsp(const FreeboxFeederRtsp&); 37 /// avoid default constructor 38 FreeboxFeederRtsp(); 39 40 FEEDERREG_DECL 41 }; 42 43 #endif//FREEBOXFEEDERRTSP_H -
libs/libmythtv/freeboxfeederfile.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederFile 3 * 4 * Please, don't submit bug reports if it 5 * can't read your file. Just use MythVideo! 6 * 7 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 8 * Distributed as part of MythTV under GPL v2 and later. 9 */ 10 11 #include "freeboxfeederfile.h" 12 13 // Qt headers 14 #include <qurl.h> 15 16 // Live555 headers 17 #include <BasicUsageEnvironment.hh> 18 #include <Groupsock.hh> 19 #include <GroupsockHelper.hh> 20 #include <ByteStreamFileSource.hh> 21 #include <TunnelEncaps.hh> 22 23 // MythTV headers 24 #include "freeboxmediasink.h" 25 #include "mythcontext.h" 26 #include "tspacket.h" 27 28 #define LOC QString("FbFeedFile:") 29 30 31 FEEDERREG_IMPL(FreeboxFeederFile,"file:"); 32 33 34 FreeboxFeederFile::FreeboxFeederFile(StreamDataListener &listener) : 35 FreeboxFeederLive(listener), 36 _source(NULL), 37 _sink(NULL) 38 { 39 } 40 41 FreeboxFeederFile::~FreeboxFeederFile() 42 { 43 Close(); 44 } 45 46 bool FreeboxFeederFile::Open(const QString &url) 47 { 48 VERBOSE(VB_RECORD, LOC + "Open(\""<<url<<"\") -- begin"); 49 50 QMutexLocker locker(&GetLock()); 51 52 if (_source) 53 { 54 VERBOSE(VB_RECORD, LOC + "Open() -- end 1"); 55 return true; 56 } 57 58 QUrl parse(url); 59 if (!parse.hasPath() || !parse.isLocalFile()) 60 { 61 VERBOSE(VB_RECORD, LOC + "Open() -- end 2"); 62 return false; 63 } 64 65 // Begin by setting up our usage environment: 66 if (!InitEnv()) 67 return false; 68 69 _source = ByteStreamFileSource::createNew(GetLiveEnv(), parse.path().local8Bit()); 70 if (!_source) 71 { 72 VERBOSE(VB_IMPORTANT, LOC + "Failed to create Live File Source."); 73 FreeEnv(); 74 return false; 75 } 76 77 _sink = FreeboxMediaSink::CreateNew( 78 GetLiveEnv(), GetListener(), TSPacket::SIZE * 128*1024); 79 if (!_sink) 80 { 81 VERBOSE(VB_IMPORTANT, 82 QString("Freebox # Failed to create sink: %1") 83 .arg(GetLiveEnv().getResultMsg())); 84 Medium::close(_source); 85 _source = NULL; 86 FreeEnv(); 87 return false; 88 } 89 _sink->startPlaying(*_source, NULL, NULL); 90 91 VERBOSE(VB_RECORD, LOC + "Open() -- end"); 92 return true; 93 } 94 95 void FreeboxFeederFile::Close(void) 96 { 97 VERBOSE(VB_RECORD, LOC + "Close() -- begin"); 98 Stop(); 99 100 QMutexLocker locker(&GetLock()); 101 102 if (_sink) 103 { 104 Medium::close(_sink); 105 _sink = NULL; 106 } 107 108 if (_source) 109 { 110 Medium::close(_source); 111 _source=NULL; 112 } 113 114 FreeEnv(); 115 116 VERBOSE(VB_RECORD, LOC + "Close() -- end"); 117 } -
libs/libmythtv/freeboxrecorder.cpp
8 8 #include "mpegstreamdata.h" 9 9 #include "tspacket.h" 10 10 #include "freeboxchannel.h" 11 #include "freeboxfeederwrapper.h" 11 12 #include "freeboxrecorder.h" 12 #include "rtspcomms.h"13 13 14 14 #define LOC QString("FBRec: ") 15 15 #define LOC_ERR QString("FBRec, Error: ") … … 23 23 _channel(channel), 24 24 _stream_data(NULL) 25 25 { 26 _channel->Get RTSP()->AddListener(this);26 _channel->GetFeeder()->AddListener(this); 27 27 } 28 28 29 29 FreeboxRecorder::~FreeboxRecorder() 30 30 { 31 31 StopRecording(); 32 _channel->Get RTSP()->RemoveListener(this);32 _channel->GetFeeder()->RemoveListener(this); 33 33 } 34 34 35 35 bool FreeboxRecorder::Open(void) 36 36 { 37 37 VERBOSE(VB_RECORD, LOC + "Open() -- begin"); 38 38 39 if (_channel->Get RTSP()->IsOpen())40 _channel->Get RTSP()->Close();39 if (_channel->GetFeeder()->IsOpen()) 40 _channel->GetFeeder()->Close(); 41 41 42 42 FreeboxChannelInfo chaninfo = _channel->GetCurrentChanInfo(); 43 if (!chaninfo.isValid()) 44 { 45 _error = true; 46 } 47 else 48 { 49 _error = !(_channel->GetRTSP()->Init()); 50 if (!_error) 51 _error = !(_channel->GetRTSP()->Open(chaninfo.m_url)); 52 } 43 _error = !chaninfo.isValid() 44 || !_channel->GetFeeder()->Open(chaninfo.m_url); 53 45 54 46 VERBOSE(VB_RECORD, LOC + "Open() -- end err("<<_error<<")"); 55 47 return !_error; … … 58 50 void FreeboxRecorder::Close(void) 59 51 { 60 52 VERBOSE(VB_RECORD, LOC + "Close() -- begin"); 61 _channel->Get RTSP()->Stop();62 _channel->Get RTSP()->Close();53 _channel->GetFeeder()->Stop(); 54 _channel->GetFeeder()->Close(); 63 55 VERBOSE(VB_RECORD, LOC + "Close() -- end"); 64 56 } 65 57 … … 67 59 { 68 60 VERBOSE(VB_RECORD, LOC + "Pause() -- begin"); 69 61 DTVRecorder::Pause(clear); 70 _channel->Get RTSP()->Stop();71 _channel->Get RTSP()->Close();62 _channel->GetFeeder()->Stop(); 63 _channel->GetFeeder()->Close(); 72 64 VERBOSE(VB_RECORD, LOC + "Pause() -- end"); 73 65 } 74 66 75 67 void FreeboxRecorder::Unpause(void) 76 68 { 77 69 VERBOSE(VB_RECORD, LOC + "Unpause() -- begin"); 78 if (_recording && !_channel->Get RTSP()->IsOpen())70 if (_recording && !_channel->GetFeeder()->IsOpen()) 79 71 Open(); 72 if (_stream_data) 73 _stream_data->Reset(_stream_data->DesiredProgram()); 80 74 DTVRecorder::Unpause(); 81 75 VERBOSE(VB_RECORD, LOC + "Unpause() -- end"); 82 76 } … … 99 93 if (PauseAndWait()) 100 94 continue; 101 95 102 if (!_channel->Get RTSP()->IsOpen())96 if (!_channel->GetFeeder()->IsOpen()) 103 97 { 104 98 usleep(5000); 105 99 continue; 106 100 } 107 101 108 102 // Go into main RTSP loop, feeding data to AddData 109 _channel->Get RTSP()->Run();103 _channel->GetFeeder()->Run(); 110 104 } 111 105 112 106 // Finish up... … … 122 116 { 123 117 VERBOSE(VB_RECORD, LOC + "StopRecording() -- begin"); 124 118 Pause(); 125 _channel->Get RTSP()->Close();119 _channel->GetFeeder()->Close(); 126 120 127 121 _request_recording = false; 128 122 while (_recording) … … 131 125 VERBOSE(VB_RECORD, LOC + "StopRecording() -- end"); 132 126 } 133 127 134 // ===================================================135 // findTSHeader : find a TS Header in flow136 // ===================================================137 static int FreeboxRecorder_findTSHeader(const unsigned char *data,138 uint dataSize)139 {140 unsigned int pos = 0;141 142 while (pos < dataSize)143 {144 if (data[pos] == 0x47)145 return pos;146 pos++;147 }148 149 return -1;150 }151 152 // ===================================================153 // AddData : feed data from RTSP flow to mythtv154 // ===================================================155 void FreeboxRecorder::AddData(unsigned char *data,156 unsigned dataSize,157 struct timeval)158 {159 unsigned int readIndex = 0;160 161 // data may be compose from more than one packet, loop to consume all data162 while (readIndex < dataSize)163 {164 // If recorder is paused, stop there165 if (IsPaused())166 return;167 168 // Find the next TS Header in data169 int tsPos = FreeboxRecorder_findTSHeader(data + readIndex, dataSize);170 171 // if no TS, something bad happens172 if (tsPos == -1)173 {174 VERBOSE(VB_IMPORTANT, LOC_ERR + "No TS header.");175 break;176 }177 178 // if TS Header not at start of data, we receive out of sync data179 if (tsPos > 0)180 {181 VERBOSE(VB_IMPORTANT, LOC_ERR +182 QString("TS packet at %1, not in sync.").arg(tsPos));183 }184 185 // Check if the next packet in buffer is complete :186 // packet size is 188 bytes long187 if ((dataSize - tsPos) < TSPacket::SIZE)188 {189 VERBOSE(VB_IMPORTANT, LOC_ERR +190 "TS packet at stradles end of buffer.");191 break;192 }193 194 // Cast current found TS Packet to TSPacket structure195 const void *newData = data + tsPos + readIndex;196 ProcessTSPacket(*reinterpret_cast<const TSPacket*>(newData));197 198 // follow to next packet199 readIndex += tsPos + TSPacket::SIZE;200 }201 }202 203 128 void FreeboxRecorder::ProcessTSPacket(const TSPacket& tspacket) 204 129 { 130 // If recorder is paused, stop there 131 if (IsPaused()) 132 return; 133 205 134 if (!_stream_data) 206 135 return; 207 136 … … 232 161 233 162 void FreeboxRecorder::SetStreamData(MPEGStreamData *data) 234 163 { 235 VERBOSE(VB_RECORD, LOC + "SetStreamData( )");164 VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- begin"); 236 165 if (data == _stream_data) 166 { 167 VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 0"); 237 168 return; 169 } 238 170 239 171 MPEGStreamData *old_data = _stream_data; 240 172 _stream_data = data; … … 243 175 244 176 if (data) 245 177 data->AddMPEGSPListener(this); 178 VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 1"); 246 179 } 247 180 248 181 void FreeboxRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) -
libs/libmythtv/rtspcomms.cpp
1 /** -*- Mode: c++ -*-2 * RTSPComms3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 #include "rtspcomms.h"8 9 // Live555 headers10 #include <RTSPClient.hh>11 #include <BasicUsageEnvironment.hh>12 #include <MediaSession.hh>13 14 // MythTV headers15 #include "freeboxmediasink.h"16 #include "mythcontext.h"17 #include "tspacket.h"18 19 #define LOC QString("RTSPData:")20 #define LOC_ERR QString("RTSPData, Error:")21 22 // ============================================================================23 // RTSPData : Helper class use for static Callback handler24 // ============================================================================25 class RTSPData26 {27 public:28 RTSPData(MediaSubsession *pMediaSubSession) :29 mediaSubSession(pMediaSubSession)30 {31 }32 33 void SubsessionAfterPlayingCB(void);34 void SubsessionByeHandlerCB(void);35 36 private:37 MediaSubsession *mediaSubSession;38 };39 40 void RTSPData::SubsessionAfterPlayingCB(void)41 {42 MediaSubsession *subsession = mediaSubSession;43 Medium::close(subsession->sink);44 subsession->sink = NULL;45 46 MediaSession &session = subsession->parentSession();47 MediaSubsessionIterator iter(session);48 49 while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */50 {51 if (subsession->sink)52 return;53 }54 }55 56 static void sub_after_playing_cb(void *clientData)57 {58 ((RTSPData*)clientData)->SubsessionAfterPlayingCB();59 }60 61 void RTSPData::SubsessionByeHandlerCB(void)62 {63 SubsessionAfterPlayingCB();64 }65 66 static void sub_bye_handler_cb(void *clientData)67 {68 ((RTSPData*)clientData)->SubsessionByeHandlerCB();69 }70 71 RTSPComms::RTSPComms() :72 _abort(0), _running(false),73 _live_env(NULL), _rtsp_client(NULL),74 _session(NULL), _lock(false)75 {76 //Init();77 }78 79 RTSPComms::~RTSPComms()80 {81 VERBOSE(VB_RECORD, LOC + "dtor -- begin");82 //Stop();83 Close();84 //Deinit();85 VERBOSE(VB_RECORD, LOC + "dtor -- end");86 }87 88 bool RTSPComms::Init(void)89 {90 VERBOSE(VB_RECORD, LOC + "Init() -- begin");91 QMutexLocker locker(&_lock);92 93 if (_rtsp_client)94 return true;95 96 // Begin by setting up our usage environment:97 TaskScheduler *scheduler = BasicTaskScheduler::createNew();98 if (!scheduler)99 {100 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create Live Scheduler.");101 return false;102 }103 104 _live_env = BasicUsageEnvironment::createNew(*scheduler);105 if (!_live_env)106 {107 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create Live Environment.");108 delete scheduler;109 return false;110 }111 112 // Create our client object:113 _rtsp_client = RTSPClient::createNew(*_live_env, 0, "myRTSP", 0);114 115 if (!_rtsp_client)116 {117 VERBOSE(VB_IMPORTANT, LOC_ERR +118 QString("Failed to create RTSP client: %1")119 .arg(_live_env->getResultMsg()));120 121 _live_env->reclaim();122 _live_env = NULL;123 delete scheduler;124 }125 126 VERBOSE(VB_RECORD, LOC + "Init() -- end");127 return _rtsp_client;128 }129 130 void RTSPComms::Deinit(void)131 {132 VERBOSE(VB_RECORD, LOC + "Deinit() -- begin");133 134 if (_session)135 Close();136 137 if (_rtsp_client)138 {139 Medium::close(_rtsp_client);140 _rtsp_client = NULL;141 }142 143 if (_live_env)144 {145 TaskScheduler *scheduler = &_live_env->taskScheduler();146 _live_env->reclaim();147 _live_env = NULL;148 delete scheduler;149 }150 VERBOSE(VB_RECORD, LOC + "Deinit() -- end");151 }152 153 bool RTSPComms::Open(const QString &url)154 {155 VERBOSE(VB_RECORD, LOC + "Open() -- begin");156 157 if (!Init())158 return false;159 160 QMutexLocker locker(&_lock);161 162 // Setup URL for the current session163 char *sdpDescription = _rtsp_client->describeURL(url);164 _rtsp_client->describeStatus();165 166 if (!sdpDescription)167 {168 VERBOSE(VB_IMPORTANT, LOC + QString(169 "Failed to get a SDP "170 "description from URL: %1 %2")171 .arg(url).arg(_live_env->getResultMsg()));172 return false;173 }174 175 // Create a media session object from this SDP description:176 _session = MediaSession::createNew(*_live_env, sdpDescription);177 178 delete[] sdpDescription;179 180 if (!_session)181 {182 VERBOSE(VB_IMPORTANT, LOC +183 QString("Failed to create MediaSession: %1")184 .arg(_live_env->getResultMsg()));185 return false;186 }187 else if (!_session->hasSubsessions())188 {189 VERBOSE(VB_IMPORTANT, LOC +190 "This session has no media subsessions");191 Close();192 return false;193 }194 195 // Then, setup the "RTPSource"s for the session:196 MediaSubsessionIterator iter(*_session);197 MediaSubsession *subsession;198 bool madeProgress = false;199 200 while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */201 {202 if (!subsession->initiate(-1))203 {204 VERBOSE(VB_IMPORTANT, LOC +205 QString("Can't create receiver for: "206 "%1 / %2 subsession: %3")207 .arg(subsession->mediumName())208 .arg(subsession->codecName())209 .arg(_live_env->getResultMsg()));210 }211 else212 {213 madeProgress = true;214 215 if (subsession->rtpSource() != NULL)216 {217 unsigned const thresh = 1000000; // 1 second218 subsession->rtpSource()->219 setPacketReorderingThresholdTime(thresh);220 }221 }222 }223 224 if (!madeProgress)225 return false;226 227 // Perform additional 'setup' on each subsession, before playing them:228 madeProgress = false;229 iter.reset();230 while ((subsession = iter.next()) != NULL)231 {232 if (subsession->clientPortNum() == 0)233 continue; // port # was not set234 235 if (_rtsp_client->setupMediaSubsession(*subsession, false, false))236 {237 madeProgress = true;238 }239 else240 {241 VERBOSE(VB_IMPORTANT, LOC +242 QString("Failed to setup: %1 %2 : %3")243 .arg(subsession->mediumName())244 .arg(subsession->codecName())245 .arg(_live_env->getResultMsg()));246 }247 }248 249 if (!madeProgress)250 return false;251 252 // Create and start "FileSink"s for each subsession:253 // FileSink while receive Mpeg2 TS Data & will feed them to mythtv254 madeProgress = false;255 iter.reset();256 257 while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */258 {259 if (!subsession->readSource())260 continue; // was not initiated261 262 FreeboxMediaSink *freeboxMediaSink = FreeboxMediaSink::CreateNew(263 *_live_env, TSPacket::SIZE * 128*1024);264 265 subsession->sink = freeboxMediaSink;266 if (!subsession->sink)267 {268 VERBOSE(VB_IMPORTANT,269 QString("Freebox # Failed to create sink: %1")270 .arg(_live_env->getResultMsg()));271 }272 273 vector<RTSPListener*>::iterator it = _listeners.begin();274 for (; it != _listeners.end(); ++it)275 freeboxMediaSink->AddListener(*it);276 277 subsession->sink->startPlaying(*(subsession->readSource()),278 sub_after_playing_cb,279 new RTSPData(subsession));280 281 if (subsession->rtcpInstance())282 {283 subsession->rtcpInstance()->setByeHandler(284 sub_bye_handler_cb, new RTSPData(subsession));285 }286 287 madeProgress = true;288 }289 290 if (!madeProgress)291 return false;292 293 // Setup player294 if (!(_rtsp_client->playMediaSession(*_session)))295 {296 VERBOSE(VB_IMPORTANT, LOC +297 QString("Failed to start playing session: %1")298 .arg(_live_env->getResultMsg()));299 return false;300 }301 302 VERBOSE(VB_RECORD, LOC + "Open() -- end");303 return true;304 }305 306 void RTSPComms::Close(void)307 {308 VERBOSE(VB_RECORD, LOC + "Close() -- begin");309 Stop();310 311 VERBOSE(VB_RECORD, LOC + "Close() -- middle 1");312 313 _lock.lock();314 if (_session)315 {316 // Ensure RTSP cleanup, remove old RTSP session317 MediaSubsessionIterator iter(*_session);318 MediaSubsession *subsession;319 while ((subsession = iter.next())) /*<-extra braces for pedantic gcc*/320 {321 Medium::close(subsession->sink);322 subsession->sink = NULL;323 }324 325 _rtsp_client->teardownMediaSession(*_session);326 327 // Close all RTSP descriptor328 Medium::close(_session);329 _session = NULL;330 }331 _lock.unlock();332 333 VERBOSE(VB_RECORD, LOC + "Close() -- middle 2");334 335 Deinit();336 VERBOSE(VB_RECORD, LOC + "Close() -- end");337 }338 339 void RTSPComms::Run(void)340 {341 VERBOSE(VB_RECORD, LOC + "Run() -- begin");342 _lock.lock();343 _running = true;344 _abort = 0;345 _lock.unlock();346 347 VERBOSE(VB_RECORD, LOC + "Run() -- loop begin");348 if (_live_env)349 _live_env->taskScheduler().doEventLoop(&_abort);350 VERBOSE(VB_RECORD, LOC + "Run() -- loop end");351 352 _lock.lock();353 _running = false;354 _cond.wakeAll();355 _lock.unlock();356 VERBOSE(VB_RECORD, LOC + "Run() -- end");357 }358 359 void RTSPComms::Stop(void)360 {361 VERBOSE(VB_RECORD, LOC + "Stop() -- begin");362 QMutexLocker locker(&_lock);363 _abort = 0xFF;364 365 while (_running)366 _cond.wait(&_lock, 500);367 VERBOSE(VB_RECORD, LOC + "Stop() -- end");368 }369 370 void RTSPComms::AddListener(RTSPListener *item)371 {372 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- begin");373 if (!item)374 {375 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 0");376 return;377 }378 379 // avoid duplicates380 RemoveListener(item);381 382 // add to local list383 QMutexLocker locker(&_lock);384 _listeners.push_back(item);385 386 // if there is a session, add to each subsession->sink387 if (!_session)388 {389 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 1");390 return;391 }392 393 MediaSubsessionIterator mit(*_session);394 MediaSubsession *subsession;395 while ((subsession = mit.next())) /* <- extra braces for pedantic gcc */396 {397 FreeboxMediaSink *sink = NULL;398 if ((sink = dynamic_cast<FreeboxMediaSink*>(subsession->sink)))399 sink->AddListener(item);400 }401 VERBOSE(VB_RECORD, LOC + "AddListener("<<item<<") -- end 2");402 }403 404 void RTSPComms::RemoveListener(RTSPListener *item)405 {406 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- begin");407 QMutexLocker locker(&_lock);408 vector<RTSPListener*>::iterator it =409 find(_listeners.begin(), _listeners.end(), item);410 411 if (it == _listeners.end())412 {413 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 1");414 return;415 }416 417 // remove from local list..418 *it = *_listeners.rbegin();419 _listeners.resize(_listeners.size() - 1);420 421 // if there is a session, remove from each subsession->sink422 if (!_session)423 {424 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 2");425 return;426 }427 428 MediaSubsessionIterator mit(*_session);429 MediaSubsession *subsession;430 while ((subsession = mit.next())) /* <- extra braces for pedantic gcc */431 {432 FreeboxMediaSink *sink = NULL;433 if ((sink = dynamic_cast<FreeboxMediaSink*>(subsession->sink)))434 sink->RemoveListener(item);435 }436 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<item<<") -- end 3");437 } -
libs/libmythtv/timeoutedtaskscheduler.cpp
1 /** -*- Mode: c++ -*- 2 * TimeoutedTaskScheduler 3 * Copyright (c) 2006 by Mike Mironov 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include "timeoutedtaskscheduler.h" 8 9 10 TimeoutedTaskScheduler::TimeoutedTaskScheduler(unsigned maxDelayTimeMS) : 11 _maxDelayTimeUS(maxDelayTimeMS*1000) 12 { 13 } 14 15 void TimeoutedTaskScheduler::doEventLoop(char* watchVariable) 16 { 17 // Repeatedly loop, handling readble sockets and timed events: 18 while (1) 19 { 20 if (watchVariable != NULL && *watchVariable != 0) 21 break; 22 SingleStep(_maxDelayTimeUS); 23 } 24 } -
libs/libmythtv/freeboxfeederudp.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederUdp 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXFEEDERUDP_H 8 #define FREEBOXFEEDERUDP_H 9 10 // MythTV headers 11 #include "freeboxfeederwrapper.h" 12 #include "freeboxfeederlive.h" 13 14 class BasicUDPSource; 15 class FreeboxMediaSink; 16 17 18 class FreeboxFeederUdp : public FreeboxFeederLive 19 { 20 public: 21 FreeboxFeederUdp(StreamDataListener &listener); 22 virtual ~FreeboxFeederUdp(); 23 24 bool Open(const QString &url); 25 bool IsOpen(void) const { return _source; } 26 void Close(void); 27 28 private: 29 BasicUDPSource *_source; 30 FreeboxMediaSink *_sink; 31 32 private: 33 /// avoid default copy operator 34 FreeboxFeederUdp& operator=(const FreeboxFeederUdp&); 35 /// avoid default copy constructor 36 FreeboxFeederUdp(const FreeboxFeederUdp&); 37 /// avoid default constructor 38 FreeboxFeederUdp(); 39 40 FEEDERREG_DECL 41 }; 42 43 #endif//FREEBOXFEEDERUDP_H -
libs/libmythtv/tspacketlistener.h
1 /** -*- Mode: c++ -*- 2 * StreamDataListener 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 _TSPACKETLISTENER_H_ 8 #define _TSPACKETLISTENER_H_ 9 10 class TSPacket; 11 12 class TSPacketListener 13 { 14 public: 15 /// Callback function to process MPEG2 TS packet 16 virtual void ProcessTSPacket(const TSPacket &packet) = 0; 17 protected: 18 virtual ~TSPacketListener() {} 19 }; 20 21 #endif//_TSPACKETLISTENER_H_ -
libs/libmythtv/freeboxmediasink.h
7 7 #ifndef _FREEBOXMEDIASINK_H_ 8 8 #define _FREEBOXMEDIASINK_H_ 9 9 10 #include <vector>11 using namespace std;12 13 10 #include <qmutex.h> 14 11 15 12 #include <MediaSink.hh> 16 13 17 class RTSPListener 18 { 19 public: 20 /// Callback function to add MPEG2 TS data 21 virtual void AddData(unsigned char *data, 22 unsigned int dataSize, 23 struct timeval presentationTime) = 0; 24 protected: 25 virtual ~RTSPListener() {} 26 }; 14 class StreamDataListener; 27 15 16 28 17 // ============================================================================ 29 18 // FreeboxMediaSink : Helper class use to receive RTSP data from socket. 30 19 // ============================================================================ 31 20 class FreeboxMediaSink : public MediaSink 32 21 { 33 22 public: 34 static FreeboxMediaSink *CreateNew(UsageEnvironment &env, 35 unsigned bufferSize); 23 static FreeboxMediaSink *CreateNew(UsageEnvironment &env, 24 StreamDataListener &listener, 25 unsigned bufferSize); 36 26 37 void AddListener(RTSPListener*);38 void RemoveListener(RTSPListener*);39 40 27 protected: 41 FreeboxMediaSink(UsageEnvironment &env, 42 unsigned int bufferSize); 28 FreeboxMediaSink(UsageEnvironment &env, 29 StreamDataListener &listener, 30 unsigned int bufferSize); 43 31 virtual ~FreeboxMediaSink(); 44 32 45 33 virtual void afterGettingFrame1(unsigned frameSize, … … 58 46 unsigned char *fBuffer; 59 47 unsigned int fBufferSize; 60 48 UsageEnvironment &env; 61 vector<RTSPListener*> listeners;49 StreamDataListener &_listener; 62 50 mutable QMutex lock; 63 51 64 52 private: -
libs/libmythtv/freeboxrecorder.h
10 10 #include <qwaitcondition.h> 11 11 12 12 #include "dtvrecorder.h" 13 #include " freeboxmediasink.h"13 #include "tspacketlistener.h" 14 14 #include "streamlisteners.h" 15 15 16 16 class FreeboxChannel; 17 17 18 /** \brief Processes data from RTSPCommsand writes it to disk.18 /** \brief Processes data from StreamDataListener and writes it to disk. 19 19 */ 20 class FreeboxRecorder : public DTVRecorder, public RTSPListener, 20 class FreeboxRecorder : public DTVRecorder, 21 public TSPacketListener, 21 22 public MPEGSingleProgramStreamListener 22 23 { 23 24 friend class FreeboxMediaSink; 24 friend class RTSPComms;25 25 26 26 public: 27 27 FreeboxRecorder(TVRec *rec, FreeboxChannel *channel); … … 43 43 virtual MPEGStreamData *GetStreamData(void) { return _stream_data; } 44 44 45 45 private: 46 // implements TSPacketListener 46 47 void ProcessTSPacket(const TSPacket& tspacket); 47 48 48 // implements RTSPListener49 void AddData(unsigned char *data,50 unsigned int dataSize,51 struct timeval presentationTime);52 53 49 // implements MPEGSingleProgramStreamListener 54 50 void HandleSingleProgramPAT(ProgramAssociationTable *pat); 55 51 void HandleSingleProgramPMT(ProgramMapTable *pmt); … … 59 55 MPEGStreamData *_stream_data; 60 56 QWaitCondition _cond_recording; 61 57 62 63 58 private: 64 59 FreeboxRecorder& operator=(const FreeboxRecorder&); //< avoid default impl 65 60 FreeboxRecorder(const FreeboxRecorder&); //< avoid default impl -
libs/libmythtv/timeoutedtaskscheduler.h
1 /** -*- Mode: c++ -*- 2 * TimeoutedTaskScheduler 3 * Copyright (c) 2006 by Mike Mironov 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef _TIMEOUTEDTASKSCHEDULER_H_ 8 #define _TIMEOUTEDTASKSCHEDULER_H_ 9 10 // Live555 headers 11 #include <BasicUsageEnvironment.hh> 12 13 14 class TimeoutedTaskScheduler : public BasicTaskScheduler 15 { 16 public: 17 TimeoutedTaskScheduler(unsigned maxDelayTimeMS); 18 19 public: 20 virtual void doEventLoop(char* watchVariable); 21 22 private: 23 unsigned _maxDelayTimeUS; 24 }; 25 26 #endif//_TIMEOUTEDTASKSCHEDULER_H_ -
libs/libmythtv/freeboxfeeder.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeeder 3 * Copyright (c) 2006 by Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXFEEDER_H 8 #define FREEBOXFEEDER_H 9 10 class QString; 11 12 13 /** \interface FreeboxFeeder 14 ** \brief This is the interface that need to be implemented to support new 15 ** protocols in the FreeboxRecorder. 16 ** 17 ** To add a new implementation, sub-class FreeboxFeederFactory and register 18 ** it using FreeboxFeederFactory::Register() 19 ** 20 ** \sa FreeboxFeederFactory 21 ** \sa FreeboxFeederFactory::Register() 22 */ 23 class FreeboxFeeder 24 { 25 public: 26 virtual ~FreeboxFeeder() {} 27 28 /** \brief Returns true if the feeder can handle url 29 ** \sa FreeboxFeederFactory::CanHandle(const QString&) 30 */ 31 virtual bool CanHandle(const QString &url) const = 0; 32 33 /// \brief Inits the feeder and opens the stream identified by url 34 virtual bool Open(const QString &url) = 0; 35 36 /// \brief Returns true if the feeder is currently open 37 virtual bool IsOpen(void) const = 0; 38 39 /// \brief Closes the stream and frees resources allocated in Open() 40 virtual void Close(void) = 0; 41 42 /** \brief Reads the stream and sends data to its StreamDataListener. This 43 ** is a blocking call : it should not exit until Stop() is called. 44 ** \sa Stop() 45 */ 46 virtual void Run(void) = 0; 47 48 /** \brief Signals to the Run() function that it should stop and exit 49 ** cleanly. 50 ** 51 ** This function should block until Run() has finished up. 52 ** \sa Run() 53 */ 54 virtual void Stop(void) = 0; 55 }; 56 57 #endif//FREEBOXFEEDER_H -
libs/libmythtv/freeboxfeederrtsp.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederRtsp 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 "freeboxfeederrtsp.h" 8 9 // Live555 headers 10 #include <RTSPClient.hh> 11 #include <BasicUsageEnvironment.hh> 12 #include <MediaSession.hh> 13 14 // MythTV headers 15 #include "freeboxmediasink.h" 16 #include "mythcontext.h" 17 #include "tspacket.h" 18 19 #define LOC QString("FbFeedRtsp(%1):").arg(pthread_self()) 20 #define LOC_ERR QString("FbFeedRtsp(%1), Error:").arg(pthread_self()) 21 22 // ============================================================================ 23 // RTSPData : Helper class use for static Callback handler 24 // ============================================================================ 25 class RTSPData 26 { 27 public: 28 RTSPData(MediaSubsession *pMediaSubSession) : 29 mediaSubSession(pMediaSubSession) 30 { 31 } 32 33 void SubsessionAfterPlayingCB(void); 34 void SubsessionByeHandlerCB(void); 35 36 private: 37 MediaSubsession *mediaSubSession; 38 }; 39 40 void RTSPData::SubsessionAfterPlayingCB(void) 41 { 42 MediaSubsession *subsession = mediaSubSession; 43 Medium::close(subsession->sink); 44 subsession->sink = NULL; 45 } 46 47 static void sub_after_playing_cb(void *clientData) 48 { 49 ((RTSPData*)clientData)->SubsessionAfterPlayingCB(); 50 } 51 52 void RTSPData::SubsessionByeHandlerCB(void) 53 { 54 SubsessionAfterPlayingCB(); 55 } 56 57 static void sub_bye_handler_cb(void *clientData) 58 { 59 ((RTSPData*)clientData)->SubsessionByeHandlerCB(); 60 } 61 62 63 FEEDERREG_IMPL(FreeboxFeederRtsp,"rtsp://"); 64 65 66 FreeboxFeederRtsp::FreeboxFeederRtsp(StreamDataListener &listener) : 67 FreeboxFeederLive(listener), 68 _rtsp_client(NULL), 69 _session(NULL) 70 { 71 VERBOSE(VB_RECORD, LOC + "ctor -- success"); 72 } 73 74 FreeboxFeederRtsp::~FreeboxFeederRtsp() 75 { 76 VERBOSE(VB_RECORD, LOC + "dtor -- begin"); 77 Close(); 78 VERBOSE(VB_RECORD, LOC + "dtor -- end"); 79 } 80 81 bool FreeboxFeederRtsp::Open(const QString &url) 82 { 83 VERBOSE(VB_RECORD, LOC + "Open(\""<<url<<"\") -- begin"); 84 85 QMutexLocker locker(&GetLock()); 86 87 if (_rtsp_client) 88 { 89 VERBOSE(VB_RECORD, LOC + "Open() -- end 1"); 90 return true; 91 } 92 93 // Begin by setting up our usage environment: 94 if (!InitEnv()) 95 return false; 96 97 // Create our client object: 98 _rtsp_client = RTSPClient::createNew(GetLiveEnv(), 0, "myRTSP", 0); 99 if (!_rtsp_client) 100 { 101 VERBOSE(VB_IMPORTANT, LOC_ERR + 102 QString("Failed to create RTSP client: %1") 103 .arg(GetLiveEnv().getResultMsg())); 104 FreeEnv(); 105 } 106 107 // Setup URL for the current session 108 char *sdpDescription = _rtsp_client->describeURL(url); 109 _rtsp_client->describeStatus(); 110 111 if (!sdpDescription) 112 { 113 VERBOSE(VB_IMPORTANT, LOC + QString( 114 "Failed to get a SDP " 115 "description from URL: %1 %2") 116 .arg(url).arg(GetLiveEnv().getResultMsg())); 117 return false; 118 } 119 120 // Create a media session object from this SDP description: 121 _session = MediaSession::createNew(GetLiveEnv(), sdpDescription); 122 123 delete[] sdpDescription; 124 125 if (!_session) 126 { 127 VERBOSE(VB_IMPORTANT, LOC + 128 QString("Failed to create MediaSession: %1") 129 .arg(GetLiveEnv().getResultMsg())); 130 return false; 131 } 132 else if (!_session->hasSubsessions()) 133 { 134 VERBOSE(VB_IMPORTANT, LOC + 135 "This session has no media subsessions"); 136 Close(); 137 return false; 138 } 139 140 // Then, setup the "RTPSource"s for the session: 141 MediaSubsessionIterator iter(*_session); 142 MediaSubsession *subsession; 143 bool madeProgress = false; 144 145 while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */ 146 { 147 if (!subsession->initiate(-1)) 148 { 149 VERBOSE(VB_IMPORTANT, LOC + 150 QString("Can't create receiver for: " 151 "%1 / %2 subsession: %3") 152 .arg(subsession->mediumName()) 153 .arg(subsession->codecName()) 154 .arg(GetLiveEnv().getResultMsg())); 155 } 156 else 157 { 158 madeProgress = true; 159 160 if (subsession->rtpSource() != NULL) 161 { 162 unsigned const thresh = 1000000; // 1 second 163 subsession->rtpSource()-> 164 setPacketReorderingThresholdTime(thresh); 165 } 166 } 167 } 168 169 if (!madeProgress) 170 return false; 171 172 // Perform additional 'setup' on each subsession, before playing them: 173 madeProgress = false; 174 iter.reset(); 175 while ((subsession = iter.next()) != NULL) 176 { 177 if (subsession->clientPortNum() == 0) 178 continue; // port # was not set 179 180 if (_rtsp_client->setupMediaSubsession(*subsession, false, false)) 181 { 182 madeProgress = true; 183 } 184 else 185 { 186 VERBOSE(VB_IMPORTANT, LOC + 187 QString("Failed to setup: %1 %2 : %3") 188 .arg(subsession->mediumName()) 189 .arg(subsession->codecName()) 190 .arg(GetLiveEnv().getResultMsg())); 191 } 192 } 193 194 if (!madeProgress) 195 return false; 196 197 // Create and start "FileSink"s for each subsession: 198 // FileSink while receive Mpeg2 TS Data & will feed them to mythtv 199 madeProgress = false; 200 iter.reset(); 201 202 while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */ 203 { 204 if (!subsession->readSource()) 205 continue; // was not initiated 206 207 FreeboxMediaSink *freeboxMediaSink = FreeboxMediaSink::CreateNew( 208 GetLiveEnv(), GetListener(), TSPacket::SIZE * 128*1024); 209 210 subsession->sink = freeboxMediaSink; 211 if (!subsession->sink) 212 { 213 VERBOSE(VB_IMPORTANT, 214 QString("Freebox # Failed to create sink: %1") 215 .arg(GetLiveEnv().getResultMsg())); 216 } 217 218 subsession->sink->startPlaying(*(subsession->readSource()), 219 sub_after_playing_cb, 220 new RTSPData(subsession)); 221 222 if (subsession->rtcpInstance()) 223 { 224 subsession->rtcpInstance()->setByeHandler( 225 sub_bye_handler_cb, new RTSPData(subsession)); 226 } 227 228 madeProgress = true; 229 } 230 231 if (!madeProgress) 232 return false; 233 234 // Setup player 235 if (!(_rtsp_client->playMediaSession(*_session))) 236 { 237 VERBOSE(VB_IMPORTANT, LOC + 238 QString("Failed to start playing session: %1") 239 .arg(GetLiveEnv().getResultMsg())); 240 return false; 241 } 242 243 VERBOSE(VB_RECORD, LOC + "Open() -- end"); 244 return true; 245 } 246 247 void FreeboxFeederRtsp::Close(void) 248 { 249 VERBOSE(VB_RECORD, LOC + "Close() -- begin"); 250 Stop(); 251 252 QMutexLocker locker(&GetLock()); 253 254 if (_session) 255 { 256 // Ensure RTSP cleanup, remove old RTSP session 257 MediaSubsessionIterator iter(*_session); 258 MediaSubsession *subsession; 259 while ((subsession = iter.next())) /*<-extra braces for pedantic gcc*/ 260 { 261 Medium::close(subsession->sink); 262 subsession->sink = NULL; 263 } 264 265 _rtsp_client->teardownMediaSession(*_session); 266 267 // Close all RTSP descriptor 268 Medium::close(_session); 269 _session = NULL; 270 } 271 272 if (_rtsp_client) 273 { 274 Medium::close(_rtsp_client); 275 _rtsp_client = NULL; 276 } 277 278 FreeEnv(); 279 280 VERBOSE(VB_RECORD, LOC + "Close() -- end"); 281 } -
libs/libmythtv/freeboxfeederrtp.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederRtp 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXFEEDERRTP_H 8 #define FREEBOXFEEDERRTP_H 9 10 // MythTV headers 11 #include "freeboxfeederwrapper.h" 12 #include "freeboxfeederlive.h" 13 14 class SimpleRTPSource; 15 class FreeboxMediaSink; 16 17 18 class FreeboxFeederRtp : public FreeboxFeederLive 19 { 20 public: 21 FreeboxFeederRtp(StreamDataListener &listener); 22 virtual ~FreeboxFeederRtp(); 23 24 bool Open(const QString &url); 25 bool IsOpen(void) const { return _source; } 26 void Close(void); 27 28 private: 29 SimpleRTPSource *_source; 30 FreeboxMediaSink *_sink; 31 32 private: 33 /// avoid default copy operator 34 FreeboxFeederRtp& operator=(const FreeboxFeederRtp&); 35 /// avoid default copy constructor 36 FreeboxFeederRtp(const FreeboxFeederRtp&); 37 /// avoid default constructor 38 FreeboxFeederRtp(); 39 40 FEEDERREG_DECL 41 }; 42 43 #endif//FREEBOXFEEDERRTP_H -
libs/libmythtv/freeboxfeederwrapper.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederWrapper 3 * Copyright (c) 2006 by Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #ifndef FREEBOXFEEDERWRAPPER_H 8 #define FREEBOXFEEDERWRAPPER_H 9 10 #include <qmutex.h> 11 #include <vector> 12 13 #include "tspacketlistener.h" 14 #include "tspacketsplitter.h" 15 16 class FreeboxFeeder; 17 class FreeboxFeederFactory; 18 class QString; 19 class StreamDataListener; 20 21 22 // Helper macros for registration of new feeder 23 #define FEEDERREG_DECL \ 24 public: \ 25 static bool CanHandleStatic(const QString &url); \ 26 bool CanHandle(const QString &url) const \ 27 { \ 28 return CanHandleStatic(url); \ 29 } \ 30 static FreeboxFeeder *createNew(StreamDataListener &listener); 31 32 #define FEEDERREG_IMPL(TYPE,PREFIX) \ 33 class TYPE##Reg \ 34 { \ 35 public: \ 36 TYPE##Reg() \ 37 { \ 38 FreeboxFeederWrapper::RegisterHandler( \ 39 TYPE::CanHandleStatic, \ 40 TYPE::createNew); \ 41 } \ 42 }; \ 43 static TYPE##Reg TYPE##RegInstance=TYPE##Reg(); \ 44 bool TYPE::CanHandleStatic(const QString &url) \ 45 { \ 46 return url.startsWith(PREFIX,false); \ 47 } \ 48 FreeboxFeeder *TYPE::createNew(StreamDataListener &listener) \ 49 { \ 50 return new TYPE(listener); \ 51 } 52 53 54 /** \class FreeboxFeederWrapper 55 ** \brief Handles the various implementations of FeederRecorder. 56 */ 57 class FreeboxFeederWrapper : private TSPacketListener 58 { 59 public: 60 FreeboxFeederWrapper(); 61 ~FreeboxFeederWrapper(); 62 63 public: 64 bool Open(const QString &url); 65 bool IsOpen(void) const; 66 void Close(void); 67 68 void Run(void); 69 void Stop(void); 70 71 void AddListener(TSPacketListener*); 72 void RemoveListener(TSPacketListener*); 73 74 // Feeder registration 75 typedef FreeboxFeeder *(*FeederConstructorFn)(StreamDataListener &listener); 76 typedef bool (*CanHandleFn)(const QString &url); 77 static void RegisterHandler(CanHandleFn, FeederConstructorFn); 78 static bool HaveHandler(const QString &url); 79 80 private: 81 static FreeboxFeeder* NewFeeder(const QString &url, 82 StreamDataListener &listener); 83 bool InitFeeder(const QString &url); 84 85 private: // implements TSPacketListener 86 void ProcessTSPacket(const TSPacket &packet); 87 88 private: 89 TSPacketSplitter _splitter; 90 FreeboxFeeder *_feeder; 91 mutable QMutex _lock; ///< Lock used to coordinate threads 92 std::vector<TSPacketListener*> _listeners; 93 94 private: 95 /// avoid default copy operator 96 FreeboxFeederWrapper& operator=(const FreeboxFeederWrapper&); 97 /// avoid default copy constructor 98 FreeboxFeederWrapper(const FreeboxFeederWrapper&); 99 }; 100 101 #endif//FREEBOXFEEDERWRAPPER_H -
libs/libmythtv/freeboxfeederlive.h
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederLive -- base class for livemedia based FreeboxFeeders 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 _FREEBOXFEEDERLIVE_H_ 8 #define _FREEBOXFEEDERLIVE_H_ 9 10 // C++ headers 11 #include <vector> 12 13 // Qt headers 14 #include <qwaitcondition.h> 15 #include <qmutex.h> 16 17 // Mythtv headers 18 #include "freeboxfeeder.h" 19 20 class QString; 21 class StreamDataListener; 22 class UsageEnvironment; 23 24 25 class FreeboxFeederLive : public FreeboxFeeder 26 { 27 public: 28 FreeboxFeederLive(StreamDataListener &listener); 29 30 void Run(void); 31 void Stop(void); 32 33 protected: 34 virtual ~FreeboxFeederLive(); 35 bool InitEnv(void); 36 void FreeEnv(void); 37 38 UsageEnvironment& GetLiveEnv() { return *_live_env; } 39 QMutex& GetLock() { return _lock; } 40 StreamDataListener& GetListener() { return _listener; } 41 42 private: 43 char _abort; 44 bool _running; 45 UsageEnvironment *_live_env; 46 QWaitCondition _cond; ///< Condition used to coordinate threads 47 mutable QMutex _lock; ///< Lock used to coordinate threads 48 StreamDataListener &_listener; 49 50 private: 51 /// avoid default copy operator 52 FreeboxFeederLive& operator=(const FreeboxFeederLive&); 53 /// avoid default copy constructor 54 FreeboxFeederLive(const FreeboxFeederLive&); 55 /// avoid default constructor 56 FreeboxFeederLive(); 57 }; 58 59 #endif//_FREEBOXFEEDERLIVE_H_ -
libs/libmythtv/freeboxfeederrtp.cpp
1 /** -*- Mode: c++ -*- 2 * FreeboxFeederRtp 3 * Copyright (c) 2006 by Mike Mironov & Mickaël Remars 4 * Distributed as part of MythTV under GPL v2 and later. 5 */ 6 7 #include "freeboxfeederrtp.h" 8 9 // Qt headers 10 #include <qurl.h> 11 12 // Live555 headers 13 #include <BasicUsageEnvironment.hh> 14 #include <Groupsock.hh> 15 #include <GroupsockHelper.hh> 16 #include <SimpleRTPSource.hh> 17 #include <TunnelEncaps.hh> 18 19 // MythTV headers 20 #include "freeboxmediasink.h" 21 #include "mythcontext.h" 22 #include "tspacket.h" 23 24 #define LOC QString("FbFeedRtp(%1):").arg(pthread_self()) 25 26 27 FEEDERREG_IMPL(FreeboxFeederRtp,"rtp://"); 28 29 30 FreeboxFeederRtp::FreeboxFeederRtp(StreamDataListener &listener) : 31 FreeboxFeederLive(listener), 32 _source(NULL), 33 _sink(NULL) 34 { 35 VERBOSE(VB_RECORD, LOC + "ctor -- success"); 36 } 37 38 FreeboxFeederRtp::~FreeboxFeederRtp() 39 { 40 VERBOSE(VB_RECORD, LOC + "dtor -- begin"); 41 Close(); 42 VERBOSE(VB_RECORD, LOC + "dtor -- end"); 43 } 44 45 bool FreeboxFeederRtp::Open(const QString &url) 46 { 47 VERBOSE(VB_RECORD, LOC + "Open(\""<<url<<"\") -- begin"); 48 49 QMutexLocker locker(&GetLock()); 50 51 if (_source) 52 { 53 VERBOSE(VB_RECORD, LOC + "Open() -- end 1"); 54 return true; 55 } 56 57 QUrl parse(url); 58 if (!parse.isValid() || !parse.hasHost() || !parse.hasPort()) 59 { 60 VERBOSE(VB_RECORD, LOC + "Open() -- end 2"); 61 return false; 62 } 63 64 struct in_addr addr; 65 addr.s_addr = our_inet_addr(parse.host().latin1()); 66 67 // Begin by setting up our usage environment: 68 if (!InitEnv()) 69 return false; 70 71 Groupsock *socket = new Groupsock(GetLiveEnv(), addr, parse.port(), 0); 72 if (!socket) 73 { 74 VERBOSE(VB_IMPORTANT, LOC + "Failed to create Live RTP Socket."); 75 FreeEnv(); 76 return false; 77 } 78 79 _source = SimpleRTPSource::createNew(GetLiveEnv(), socket, 33, 90000, "video/MP2T", 0, False); 80 if (!_source) 81 { 82 VERBOSE(VB_IMPORTANT, LOC + "Failed to create Live RTP Source."); 83 delete socket; 84 FreeEnv(); 85 return false; 86 } 87 88 _sink = FreeboxMediaSink::CreateNew( 89 GetLiveEnv(), GetListener(), TSPacket::SIZE * 128*1024); 90 if (!_sink) 91 { 92 VERBOSE(VB_IMPORTANT, 93 QString("Freebox # Failed to create sink: %1") 94 .arg(GetLiveEnv().getResultMsg())); 95 Medium::close(_source); 96 _source = NULL; 97 delete socket; 98 FreeEnv(); 99 return false; 100 } 101 _sink->startPlaying(*_source, NULL, NULL); 102 103 VERBOSE(VB_RECORD, LOC + "Open() -- end"); 104 return true; 105 } 106 107 void FreeboxFeederRtp::Close(void) 108 { 109 VERBOSE(VB_RECORD, LOC + "Close() -- begin"); 110 Stop(); 111 112 QMutexLocker locker(&GetLock()); 113 114 if (_sink) 115 { 116 Medium::close(_sink); 117 _sink = NULL; 118 } 119 120 if (_source) 121 { 122 Groupsock *socket=_source->RTPgs(); 123 Medium::close(_source); 124 _source=NULL; 125 delete socket; 126 } 127 128 FreeEnv(); 129 130 VERBOSE(VB_RECORD, LOC + "Close() -- end"); 131 } -
libs/libmythtv/rtspcomms.h
1 /** -*- Mode: c++ -*-2 * RTSPComms3 * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars4 * Distributed as part of MythTV under GPL v2 and later.5 */6 7 // C++ headers8 #include <vector>9 using namespace std;10 11 // Qt headers12 #include <qwaitcondition.h>13 #include <qmutex.h>14 15 // MythTV headers16 #include "freeboxchannel.h"17 18 class UsageEnvironment;19 class RTSPClient;20 class MediaSession;21 class RTSPListener;22 23 class RTSPComms24 {25 public:26 RTSPComms();27 virtual ~RTSPComms();28 29 bool Init(void);30 void Deinit(void);31 32 bool Open(const QString &url);33 bool IsOpen(void) const { return _session; }34 void Close(void);35 36 void Run(void);37 void Stop(void);38 39 void AddListener(RTSPListener*);40 void RemoveListener(RTSPListener*);41 42 private:43 44 char _abort;45 bool _running;46 UsageEnvironment *_live_env;47 RTSPClient *_rtsp_client;48 MediaSession *_session;49 vector<RTSPListener*> _listeners;50 QWaitCondition _cond; ///< Condition used to coordinate threads51 mutable QMutex _lock; ///< Lock used to coordinate threads52 };