X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/6a1fc924eb21f22f9b522df233a9a98d4c5bdca7..83719a3213fabed7843cb03ee01533fc63432531:/lib/dvb/demux.cpp diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp index d2a2a545..0fbd6fbd 100644 --- a/lib/dvb/demux.cpp +++ b/lib/dvb/demux.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -6,14 +5,39 @@ #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" @@ -24,6 +48,7 @@ #include #include #include +#include eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux) { @@ -49,18 +74,29 @@ DEFINE_REF(eDVBDemux) RESULT eDVBDemux::setSourceFrontend(int fenum) { +#if HAVE_DVB_API_VERSION >= 3 int fd = openDemux(); - int res = ::ioctl(fd, DMX_SET_SOURCE, DMX_SOURCE_FRONT0 + fenum); + + 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 res = ::ioctl(fd, DMX_SET_SOURCE, DMX_SOURCE_DVR0 + pvrnum); + 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) @@ -72,6 +108,15 @@ RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr &reader) +{ + RESULT res; + reader = new eDVBPESReader(this, context, res); + if (res) + reader = 0; + return res; +} + RESULT eDVBDemux::createTSRecorder(ePtr &recorder) { if (m_dvr_busy) @@ -80,13 +125,13 @@ RESULT eDVBDemux::createTSRecorder(ePtr &recorder) return 0; } -RESULT eDVBDemux::getMPEGDecoder(ePtr &decoder) +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) +RESULT eDVBDemux::getSTC(pts_t &pts, int num) { int fd = openDemux(); @@ -94,7 +139,7 @@ RESULT eDVBDemux::getSTC(pts_t &pts) return -ENODEV; struct dmx_stc stc; - stc.num = 0; + stc.num = num; stc.base = 1; if (ioctl(fd, DMX_GET_STC, &stc) < 0) @@ -246,22 +291,170 @@ RESULT eDVBSectionReader::connectRead(const Slot1 &r, ePtropenDemux(); + + if (m_fd >= 0) + { + ::ioctl(m_fd, DMX_SET_BUFFER_SIZE, 64*1024); + ::fcntl(m_fd, F_SETFL, O_NONBLOCK); + m_notifier = new eSocketNotifier(context, m_fd, eSocketNotifier::Read, false); + CONNECT(m_notifier->activated, eDVBPESReader::data); + res = 0; + } else + { + perror(filename); + res = errno; + } +} + +DEFINE_REF(eDVBPESReader) + +eDVBPESReader::~eDVBPESReader() +{ + if (m_notifier) + delete m_notifier; + if (m_fd >= 0) + ::close(m_fd); +} + +RESULT eDVBPESReader::start(int pid) +{ + RESULT res; + if (m_fd < 0) + return -ENODEV; + + m_notifier->start(); + +#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_TAP; + + flt.flags = DMX_IMMEDIATE_START; + + res = ::ioctl(m_fd, DMX_SET_PES_FILTER, &flt); + + if (res) + eWarning("PES filter: DMX_SET_PES_FILTER - %m"); + if (!res) + m_active = 1; + return res; +} + +RESULT eDVBPESReader::stop() +{ + if (!m_active) + return -1; + + m_active=0; + ::ioctl(m_fd, DMX_STOP); + m_notifier->stop(); + + return 0; +} + +RESULT eDVBPESReader::connectRead(const Slot2 &r, ePtr &conn) +{ + conn = new eConnection(this, m_read.connect(r)); + return 0; +} + +class eDVBRecordFileThread: public eFilePushThread +{ +public: + eDVBRecordFileThread(); + void setTimingPID(int pid); + + void saveTimingInformation(const std::string &filename); +protected: + void filterRecordData(const unsigned char *data, int len); +private: + eMPEGStreamParserTS m_ts_parser; + eMPEGStreamInformation m_stream_info; + off_t m_current_offset; + int m_pid; +}; + +eDVBRecordFileThread::eDVBRecordFileThread() + :eFilePushThread(IOPRIO_CLASS_RT, 7), m_ts_parser(m_stream_info) +{ + m_current_offset = 0; +} + +void eDVBRecordFileThread::setTimingPID(int pid) +{ + m_ts_parser.setPid(pid); +} + +void eDVBRecordFileThread::saveTimingInformation(const std::string &filename) +{ + m_stream_info.save(filename.c_str()); +} + +void eDVBRecordFileThread::filterRecordData(const unsigned char *data, int len) +{ + m_ts_parser.parseData(m_current_offset, data, len); + + m_current_offset += len; +} + DEFINE_REF(eDVBTSRecorder); eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux) { m_running = 0; - m_format = 0; m_target_fd = -1; - m_thread = new eFilePushThread(); + m_thread = new eDVBRecordFileThread(); +#ifndef HAVE_ADD_PID m_demux->m_dvr_busy = 1; +#endif } eDVBTSRecorder::~eDVBTSRecorder() { stop(); delete m_thread; +#ifndef HAVE_ADD_PID m_demux->m_dvr_busy = 0; +#endif } RESULT eDVBTSRecorder::start() @@ -271,8 +464,9 @@ RESULT eDVBTSRecorder::start() 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 @@ -285,6 +479,36 @@ RESULT eDVBTSRecorder::start() 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; @@ -318,11 +542,11 @@ RESULT eDVBTSRecorder::removePID(int pid) return 0; } -RESULT eDVBTSRecorder::setFormat(int format) +RESULT eDVBTSRecorder::setTimingPID(int pid) { if (m_running) return -1; - m_format = format; + m_thread->setTimingPID(pid); return 0; } @@ -332,6 +556,12 @@ RESULT eDVBTSRecorder::setTargetFD(int 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 @@ -347,6 +577,10 @@ RESULT eDVBTSRecorder::stop() m_thread->stop(); close(m_source_fd); + m_source_fd = -1; + + if (m_target_filename != "") + m_thread->saveTimingInformation(m_target_filename + ".ap"); return 0; } @@ -359,6 +593,7 @@ RESULT eDVBTSRecorder::connectEvent(const Slot1 &event, ePtropenDemux(); if (fd < 0) { @@ -390,12 +625,26 @@ RESULT eDVBTSRecorder::startPID(int pid) 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) { - ::close(m_pids[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; }