X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/9a236ba05f412b3f6853f54c5665cf0e5398d7d3..3f9644531fb06a71290b65fbc97f9a8f29fd8076:/lib/dvb/demux.cpp diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp index f24fcddc..f277468d 100644 --- a/lib/dvb/demux.cpp +++ b/lib/dvb/demux.cpp @@ -1,37 +1,104 @@ -#include #include #include #include #include #include +#include #if HAVE_DVB_API_VERSION < 3 #include + #ifndef DMX_SET_NEGFILTER_MASK #define DMX_SET_NEGFILTER_MASK _IOW('o',48,uint8_t *) #endif + +#ifndef DMX_GET_STC + struct dmx_stc + { + unsigned int num; /* input : which STC? O..N */ + unsigned int base; /* output: divisor for stc to get 90 kHz clock */ + unsigned long long stc; /* output: src in 'base'*90 kHz units */ + }; + #define DMX_GET_STC _IOR('o', 50, struct dmx_stc) +#endif + #else #include + +#define HAVE_ADD_PID + +#ifdef HAVE_ADD_PID +#define DMX_ADD_PID _IO('o', 51) +#define DMX_REMOVE_PID _IO('o', 52) + +typedef enum { + DMX_TAP_TS = 0, + DMX_TAP_PES = DMX_PES_OTHER, /* for backward binary compat. */ +} dmx_tap_type_t; + +#endif + #endif #include "crc32.h" #include +#include #include #include #include #include +#include eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux) { + m_dvr_busy = 0; } eDVBDemux::~eDVBDemux() { } +int eDVBDemux::openDemux(void) +{ + char filename[128]; +#if HAVE_DVB_API_VERSION < 3 + snprintf(filename, 128, "/dev/dvb/card%d/demux%d", adapter, demux); +#else + snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", adapter, demux); +#endif + return ::open(filename, O_RDWR); +} + DEFINE_REF(eDVBDemux) +RESULT eDVBDemux::setSourceFrontend(int fenum) +{ +#if HAVE_DVB_API_VERSION >= 3 + int fd = openDemux(); + + int n = DMX_SOURCE_FRONT0 + fenum; + int res = ::ioctl(fd, DMX_SET_SOURCE, &n); + if (res) + eDebug("DMX_SET_SOURCE failed! - %m"); + ::close(fd); + return res; +#endif + return 0; +} + +RESULT eDVBDemux::setSourcePVR(int pvrnum) +{ +#if HAVE_DVB_API_VERSION >= 3 + int fd = openDemux(); + int n = DMX_SOURCE_DVR0 + pvrnum; + int res = ::ioctl(fd, DMX_SET_SOURCE, &n); + ::close(fd); + return res; +#endif + return 0; +} + RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr &reader) { RESULT res; @@ -41,9 +108,54 @@ RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr &decoder) +RESULT eDVBDemux::createTSRecorder(ePtr &recorder) +{ + if (m_dvr_busy) + return -EBUSY; + recorder = new eDVBTSRecorder(this); + return 0; +} + +RESULT eDVBDemux::getMPEGDecoder(ePtr &decoder, int primary) { - decoder = new eTSMPEGDecoder(this, 0); + decoder = new eTSMPEGDecoder(this, primary ? 0 : 1); + return 0; +} + +RESULT eDVBDemux::getSTC(pts_t &pts, int num) +{ + int fd = openDemux(); + + if (fd < 0) + return -ENODEV; + + struct dmx_stc stc; + stc.num = num; + stc.base = 1; + + if (ioctl(fd, DMX_GET_STC, &stc) < 0) + { + ::close(fd); + return -1; + } + + pts = stc.stc; + + ::close(fd); + return 0; +} + +RESULT eDVBDemux::flush() +{ + // FIXME: implement flushing the PVR queue here. + + m_event(evtFlush); + return 0; +} + +RESULT eDVBDemux::connectEvent(const Slot1 &event, ePtr &conn) +{ + conn = new eConnection(this, m_event.connect(event)); return 0; } @@ -62,26 +174,25 @@ void eDVBSectionReader::data(int) // this check should never happen unless the driver is crappy! unsigned int c; if ((c = crc32((unsigned)-1, data, r))) - eFatal("crc32 failed! is %x\n", c); + { + eDebug("crc32 failed! is %x\n", c); + return; + } } - read(data); + if (active) + read(data); + else + eDebug("data.. but not active"); } eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): demux(demux) { char filename[128]; -#if HAVE_DVB_API_VERSION < 3 - sprintf(filename, "/dev/dvb/card%d/demux%d", demux->adapter, demux->demux); -#else - sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux); -#endif - fd = ::open(filename, O_RDWR); - - eDebug("eDVBSectionReader has fd %d", fd); + fd = demux->openDemux(); if (fd >= 0) { - notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read); + notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read, false); CONNECT(notifier->activated, eDVBSectionReader::data); res = 0; } else @@ -107,6 +218,7 @@ RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask) if (fd < 0) return -ENODEV; + notifier->start(); #if HAVE_DVB_API_VERSION < 3 dmxSctFilterParams sct; #else @@ -130,6 +242,8 @@ RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask) memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE); #if HAVE_DVB_API_VERSION >= 3 memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE); + if (::ioctl(fd, DMX_SET_BUFFER_SIZE, 8192*8) < 0) + eDebug("DMX_SET_BUFFER_SIZE failed(%m)"); #endif res = ::ioctl(fd, DMX_SET_FILTER, &sct); @@ -154,9 +268,11 @@ RESULT eDVBSectionReader::stop() { if (!active) return -1; - + + active=0; ::ioctl(fd, DMX_STOP); - + notifier->stop(); + return 0; } @@ -165,3 +281,255 @@ RESULT eDVBSectionReader::connectRead(const Slot1 &r, ePtrm_dvr_busy = 1; +#endif +} + +eDVBTSRecorder::~eDVBTSRecorder() +{ + stop(); + delete m_thread; +#ifndef HAVE_ADD_PID + m_demux->m_dvr_busy = 0; +#endif +} + +RESULT eDVBTSRecorder::start() +{ + if (m_running) + return -1; + + if (m_target_fd == -1) + return -2; + + char filename[128]; +#ifndef HAVE_ADD_PID +#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; + } +#else + snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", m_demux->adapter, m_demux->demux); + + m_source_fd = ::open(filename, O_RDONLY); + + if (m_source_fd < 0) + { + eDebug("FAILED to open demux (%s) in ts recoder (%m)", filename); + return -3; + } + + ::ioctl(m_source_fd, DMX_SET_BUFFER_SIZE, 1024*1024); + + dmx_pes_filter_params flt; + flt.pes_type = (dmx_pes_type_t)DMX_TAP_TS; + flt.pid = (__u16)-1; + flt.input = DMX_IN_FRONTEND; + flt.output = DMX_OUT_TAP; + flt.flags = 0; + int res = ::ioctl(m_source_fd, DMX_SET_PES_FILTER, &flt); + if (res) + { + eDebug("DMX_SET_PES_FILTER: %m"); + ::close(m_source_fd); + return -3; + } + + ::ioctl(m_source_fd, DMX_START); + +#endif + + m_thread->start(m_source_fd, m_target_fd); + m_running = 1; + + for (std::map::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(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::setTimingPID(int pid) +{ + if (m_running) + return -1; + m_thread->setTimingPID(pid); + return 0; +} + +RESULT eDVBTSRecorder::setTargetFD(int fd) +{ + m_target_fd = fd; + return 0; +} + +RESULT eDVBTSRecorder::setTargetFilename(const char *filename) +{ + m_target_filename = filename; + return 0; +} + +RESULT eDVBTSRecorder::setBoundary(off_t max) +{ + return -1; // not yet implemented +} + +RESULT eDVBTSRecorder::stop() +{ + for (std::map::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); + m_source_fd = -1; + + if (m_target_filename != "") + m_thread->saveTimingInformation(m_target_filename + ".ap"); + + return 0; +} + +RESULT eDVBTSRecorder::connectEvent(const Slot1 &event, ePtr &conn) +{ + conn = new eConnection(this, m_event.connect(event)); + return 0; +} + +RESULT eDVBTSRecorder::startPID(int pid) +{ +#ifndef HAVE_ADD_PID + int fd = m_demux->openDemux(); + if (fd < 0) + { + eDebug("FAILED to open demux in ts recoder (%m)"); + 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; +#else + if (::ioctl(m_source_fd, DMX_ADD_PID, pid)) + perror("DMX_ADD_PID"); + else + m_pids[pid] = 1; +#endif + return 0; +} + +void eDVBTSRecorder::stopPID(int pid) +{ +#ifndef HAVE_ADD_PID + if (m_pids[pid] != -1) + ::close(m_pids[pid]); +#else + if (m_pids[pid] != -1) + { + if (::ioctl(m_source_fd, DMX_REMOVE_PID, pid)) + perror("DMX_REMOVE_PID"); + } +#endif + m_pids[pid] = -1; +}