diff options
| -rw-r--r-- | lib/dvb/demux.cpp | 258 | ||||
| -rw-r--r-- | lib/dvb/demux.h | 41 | ||||
| -rw-r--r-- | lib/dvb/eit.h | 2 | ||||
| -rw-r--r-- | lib/dvb/esection.h | 2 | ||||
| -rw-r--r-- | lib/dvb/pmt.cpp | 2 | ||||
| -rw-r--r-- | lib/dvb/pmt.h | 2 | ||||
| -rw-r--r-- | lib/dvb/scan.h | 2 | ||||
| -rw-r--r-- | lib/dvb/specs.h | 2 |
8 files changed, 305 insertions, 6 deletions
diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp index f24fcddc..f6bdbd7b 100644 --- a/lib/dvb/demux.cpp +++ b/lib/dvb/demux.cpp @@ -4,6 +4,9 @@ #include <sys/ioctl.h> #include <errno.h> #include <unistd.h> +#include <signal.h> + +#include <lib/base/thread.h> #if HAVE_DVB_API_VERSION < 3 #include <ost/dmx.h> @@ -24,6 +27,7 @@ eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux) { + m_dvr_busy = 0; } eDVBDemux::~eDVBDemux() @@ -41,6 +45,14 @@ RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader return res; } +RESULT eDVBDemux::createTSRecorder(ePtr<iDVBTSRecorder> &recorder) +{ + if (m_dvr_busy) + return -EBUSY; + recorder = new eDVBTSRecorder(this); + return 0; +} + RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder) { decoder = new eTSMPEGDecoder(this, 0); @@ -165,3 +177,249 @@ RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eCo conn = new eConnection(this, read.connect(r)); return 0; } + +DEFINE_REF(eDVBTSRecorder); + +class eDVBTSRecorderThread: public eThread +{ +public: + eDVBTSRecorderThread(); + void thread(); + void stop(); + void start(int sourcefd, int destfd); +private: + int m_stop; + unsigned char m_buffer[65536]; + int m_buf_start, m_buf_end; + int m_fd_source, m_fd_dest; +}; + +eDVBTSRecorderThread::eDVBTSRecorderThread() +{ + m_stop = 0; + m_buf_start = m_buf_end = 0; +} + +static void signal_handler(int x) +{ +} + +void eDVBTSRecorderThread::thread() +{ + eDebug("RECORDING THREAD START"); + // this is race. FIXME. + + /* we set the signal to not restart syscalls, so we can detect our signal. */ + struct sigaction act; + act.sa_handler = signal_handler; // no, SIG_IGN doesn't do it :/ + act.sa_flags = 0; + sigaction(SIGUSR1, &act, 0); + + /* m_stop must be evaluated after each syscall. */ + while (!m_stop) + { + /* first try flushing the bufptr */ + if (m_buf_start != m_buf_end) + { + // TODO: take care of boundaries. + int w = write(m_fd_dest, m_buffer + m_buf_start, m_buf_end - m_buf_start); + if (w <= 0) + { + if (errno == -EINTR) + continue; + eDebug("eDVBTSRecorder *write error* - not yet handled"); + // ... we would stop the thread + } + printf("TSRECORD: wrote %d bytes\n", w); + m_buf_start += w; + continue; + } + + /* now fill our buffer. */ + m_buf_start = 0; + m_buf_end = read(m_fd_source, m_buffer, sizeof(m_buffer)); + if (m_buf_end < 0) + { + m_buf_end = 0; + if (errno == EINTR) + continue; + eDebug("eDVBTSRecorder *read error* - not yet handled"); + } + printf("TSRECORD: read %d bytes\n", m_buf_end); + } + + eDebug("RECORDING THREAD STOP"); +} + +void eDVBTSRecorderThread::start(int fd_source, int fd_dest) +{ + m_fd_source = fd_source; + m_fd_dest = fd_dest; + m_stop = 0; + run(); +} + +void eDVBTSRecorderThread::stop() +{ + m_stop = 1; + sendSignal(SIGUSR1); + kill(); +} + +eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux) +{ + m_running = 0; + m_format = 0; + m_target_fd = -1; + m_thread = new eDVBTSRecorderThread(); + m_demux->m_dvr_busy = 1; +} + +eDVBTSRecorder::~eDVBTSRecorder() +{ + stop(); + delete m_thread; + m_demux->m_dvr_busy = 0; +} + +RESULT eDVBTSRecorder::start() +{ + if (m_running) + return -1; + + if (m_target_fd == -1) + return -2; + + char filename[128]; +#if HAVE_DVB_API_VERSION < 3 + snprintf(filename, 128, "/dev/dvb/card%d/dvr%d", m_demux->adapter, m_demux->demux); +#else + snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", m_demux->adapter, m_demux->demux); +#endif + m_source_fd = ::open(filename, O_RDONLY); + + if (m_source_fd < 0) + { + eDebug("FAILED to open dvr (%s) in ts recoder (%m)", filename); + return -3; + } + + m_thread->start(m_source_fd, m_target_fd); + m_running = 1; + + for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i) + startPID(i->first); + + return 0; +} + +RESULT eDVBTSRecorder::addPID(int pid) +{ + if (m_pids.find(pid) != m_pids.end()) + return -1; + + m_pids.insert(std::pair<int,int>(pid, -1)); + if (m_running) + startPID(pid); + return 0; +} + +RESULT eDVBTSRecorder::removePID(int pid) +{ + if (m_pids.find(pid) == m_pids.end()) + return -1; + + if (m_running) + stopPID(pid); + + m_pids.erase(pid); + return 0; +} + +RESULT eDVBTSRecorder::setFormat(int format) +{ + if (m_running) + return -1; + m_format = format; + return 0; +} + +RESULT eDVBTSRecorder::setTargetFD(int fd) +{ + m_target_fd = fd; + return 0; +} + +RESULT eDVBTSRecorder::setBoundary(off_t max) +{ + return -1; // not yet implemented +} + +RESULT eDVBTSRecorder::stop() +{ + for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i) + stopPID(i->first); + + if (!m_running) + return -1; + m_thread->stop(); + + close(m_source_fd); + + return 0; +} + +RESULT eDVBTSRecorder::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn) +{ + conn = new eConnection(this, m_event.connect(event)); + return 0; +} + +RESULT eDVBTSRecorder::startPID(int pid) +{ + char filename[128]; +#if HAVE_DVB_API_VERSION < 3 + snprintf(filename, 128, "/dev/dvb/card%d/demux%d", m_demux->adapter, m_demux->demux); +#else + snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", m_demux->adapter, m_demux->demux); +#endif + int fd = ::open(filename, O_RDWR); + if (fd < 0) + { + eDebug("FAILED to open demux (%s) in ts recoder (%m)", filename); + return -1; + } + +#if HAVE_DVB_API_VERSION < 3 + dmxPesFilterParams flt; + + flt.pesType = DMX_PES_OTHER; +#else + dmx_pes_filter_params flt; + + flt.pes_type = DMX_PES_OTHER; +#endif + + flt.pid = pid; + flt.input = DMX_IN_FRONTEND; + flt.output = DMX_OUT_TS_TAP; + + flt.flags = DMX_IMMEDIATE_START; + + int res = ::ioctl(fd, DMX_SET_PES_FILTER, &flt); + if (res < 0) + { + eDebug("set pes filter failed!"); + ::close(fd); + return -1; + } + m_pids[pid] = fd; + + return 0; +} + +void eDVBTSRecorder::stopPID(int pid) +{ + ::close(m_pids[pid]); + m_pids[pid] = -1; +} diff --git a/lib/dvb/demux.h b/lib/dvb/demux.h index d8c1078e..b2d571ac 100644 --- a/lib/dvb/demux.h +++ b/lib/dvb/demux.h @@ -2,19 +2,23 @@ #define __dvb_demux_h #include <lib/dvb/idvb.h> -#include <lib/dvb/isection.h> +#include <lib/dvb/idemux.h> class eDVBDemux: public iDVBDemux { int adapter, demux; + + int m_dvr_busy; friend class eDVBSectionReader; friend class eDVBAudio; friend class eDVBVideo; + friend class eDVBTSRecorder; public: DECLARE_REF(eDVBDemux); eDVBDemux(int adapter, int demux); virtual ~eDVBDemux(); RESULT createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader); + RESULT createTSRecorder(ePtr<iDVBTSRecorder> &recorder); RESULT getMPEGDecoder(ePtr<iTSMPEGDecoder> &reader); }; @@ -38,4 +42,39 @@ public: RESULT connectRead(const Slot1<void,const __u8*> &read, ePtr<eConnection> &conn); }; +class eDVBTSRecorderThread; + +class eDVBTSRecorder: public iDVBTSRecorder, public Object +{ + DECLARE_REF(eDVBTSRecorder); +public: + eDVBTSRecorder(eDVBDemux *demux); + ~eDVBTSRecorder(); + + RESULT start(); + RESULT addPID(int pid); + RESULT removePID(int pid); + + RESULT setFormat(int pid); + + RESULT setTargetFD(int fd); + RESULT setBoundary(off_t max); + + RESULT stop(); + + RESULT connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn); +private: + RESULT startPID(int pid); + void stopPID(int pid); + + eDVBTSRecorderThread *m_thread; + + std::map<int,int> m_pids; + Signal1<void,int> m_event; + + ePtr<eDVBDemux> m_demux; + + int m_running, m_format, m_target_fd, m_source_fd; +}; + #endif diff --git a/lib/dvb/eit.h b/lib/dvb/eit.h index 7ec16bc8..a026773c 100644 --- a/lib/dvb/eit.h +++ b/lib/dvb/eit.h @@ -1,7 +1,7 @@ #ifndef __lib_dvb_eit_h #define __lib_dvb_eit_h -#include <lib/dvb/isection.h> +#include <lib/dvb/idemux.h> #include <lib/dvb/esection.h> #include <lib/dvb_si/eit.h> #include <lib/service/event.h> diff --git a/lib/dvb/esection.h b/lib/dvb/esection.h index df0b93e5..2d71eef8 100644 --- a/lib/dvb/esection.h +++ b/lib/dvb/esection.h @@ -1,7 +1,7 @@ #ifndef __esection_h #define __esection_h -#include <lib/dvb/isection.h> +#include <lib/dvb/idemux.h> #include <set> class eGTable: public iObject, public Object diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 8c4388a4..3f9ac7f7 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -44,6 +44,7 @@ void eDVBServicePMTHandler::PMTready(int error) void eDVBServicePMTHandler::PATready(int) { + eDebug("got PAT"); ePtr<eTable<ProgramAssociationTable> > ptr; if (!m_PAT.getCurrent(ptr)) { @@ -67,6 +68,7 @@ void eDVBServicePMTHandler::PATready(int) int eDVBServicePMTHandler::getProgramInfo(struct program &program) { + eDebug("got PMT"); ePtr<eTable<ProgramMapTable> > ptr; program.videoStreams.clear(); diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h index 03df198b..136c1673 100644 --- a/lib/dvb/pmt.h +++ b/lib/dvb/pmt.h @@ -3,7 +3,7 @@ #include <lib/dvb/idvb.h> #include <lib/dvb/dvb.h> -#include <lib/dvb/isection.h> +#include <lib/dvb/idemux.h> #include <lib/dvb/esection.h> #include <lib/dvb_si/pmt.h> #include <lib/dvb_si/pat.h> diff --git a/lib/dvb/scan.h b/lib/dvb/scan.h index 2f75291b..bfd3add9 100644 --- a/lib/dvb/scan.h +++ b/lib/dvb/scan.h @@ -4,7 +4,7 @@ #include <lib/dvb_si/nit.h> #include <lib/dvb_si/sdt.h> #include <lib/dvb_si/bat.h> -#include <lib/dvb/isection.h> +#include <lib/dvb/idemux.h> #include <lib/dvb/esection.h> #include <lib/dvb/db.h> diff --git a/lib/dvb/specs.h b/lib/dvb/specs.h index 1a0353e5..5c26bfad 100644 --- a/lib/dvb/specs.h +++ b/lib/dvb/specs.h @@ -2,7 +2,7 @@ #define __lib_dvb_specs_h #include <lib/dvb/idvb.h> -#include <lib/dvb/isection.h> +#include <lib/dvb/idemux.h> #include <lib/dvb_si/pmt.h> #include <lib/dvb_si/sdt.h> #include <lib/dvb_si/nit.h> |
