X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fdvb%2Fdemux.cpp;h=f4d86185b508a03461075f17bd119cd911005e60;hp=b0d9b400ac8448e80b0e66a371b08695853c218f;hb=a995c63c0d6c24bbe23935b901bf735c18833adb;hpb=9c3098c8667241d18d2551a9a37ce7fbce396b71;ds=sidebyside diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp index b0d9b40..f4d8618 100644 --- a/lib/dvb/demux.cpp +++ b/lib/dvb/demux.cpp @@ -5,6 +5,13 @@ #include #include +// #define FUZZING 1 + +#if FUZZING + /* change every 1:FUZZING_PROPABILITY byte */ +#define FUZZING_PROPABILITY 100 +#endif + #if HAVE_DVB_API_VERSION < 3 #include @@ -28,6 +35,13 @@ #define HAVE_ADD_PID #ifdef HAVE_ADD_PID + +#if HAVE_DVB_API_VERSION > 3 +#ifndef DMX_ADD_PID +#define DMX_ADD_PID _IOW('o', 51, __u16) +#define DMX_REMOVE_PID _IOW('o', 52, __u16) +#endif +#else #define DMX_ADD_PID _IO('o', 51) #define DMX_REMOVE_PID _IO('o', 52) @@ -35,6 +49,7 @@ typedef enum { DMX_TAP_TS = 0, DMX_TAP_PES = DMX_PES_OTHER, /* for backward binary compat. */ } dmx_tap_type_t; +#endif #endif @@ -70,17 +85,25 @@ int eDVBDemux::openDemux(void) return ::open(filename, O_RDWR); } +int eDVBDemux::openDVR(int flags) +{ + char filename[128]; + snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", adapter, demux); + return ::open(filename, flags); +} + 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"); + else + source = fenum; ::close(fd); return res; #endif @@ -93,6 +116,7 @@ RESULT eDVBDemux::setSourcePVR(int pvrnum) int fd = openDemux(); int n = DMX_SOURCE_DVR0 + pvrnum; int res = ::ioctl(fd, DMX_SET_SOURCE, &n); + source = -1; ::close(fd); return res; #endif @@ -144,12 +168,15 @@ RESULT eDVBDemux::getSTC(pts_t &pts, int num) if (ioctl(fd, DMX_GET_STC, &stc) < 0) { + eDebug("DMX_GET_STC failed!"); ::close(fd); return -1; } pts = stc.stc; + eDebug("DMX_GET_STC - %lld", pts); + ::close(fd); return 0; } @@ -173,6 +200,14 @@ void eDVBSectionReader::data(int) __u8 data[4096]; // max. section size int r; r = ::read(fd, data, 4096); +#if FUZZING + int j; + for (j = 0; j < r; ++j) + { + if (!(rand()%FUZZING_PROPABILITY)) + data[j] ^= rand(); + } +#endif if(r < 0) { eWarning("ERROR reading section - %m\n"); @@ -201,7 +236,7 @@ eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESUL if (fd >= 0) { - notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read, false); + notifier=eSocketNotifier::create(context, fd, eSocketNotifier::Read, false); CONNECT(notifier->activated, eDVBSectionReader::data); res = 0; } else @@ -215,12 +250,18 @@ DEFINE_REF(eDVBSectionReader) eDVBSectionReader::~eDVBSectionReader() { - if (notifier) - delete notifier; if (fd >= 0) ::close(fd); } +RESULT eDVBSectionReader::setBufferSize(int size) +{ + int res=::ioctl(fd, DMX_SET_BUFFER_SIZE, size); + if (res < 0) + eDebug("eDVBSectionReader DMX_SET_BUFFER_SIZE failed(%m)"); + return res; +} + RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask) { RESULT res; @@ -240,19 +281,20 @@ RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask) #else sct.flags = DMX_IMMEDIATE_START; #endif +#if !FUZZING if (mask.flags & eDVBSectionFilterMask::rfCRC) { sct.flags |= DMX_CHECK_CRC; checkcrc = 1; } else +#endif checkcrc = 0; memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE); 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)"); + setBufferSize(8192*8); #endif res = ::ioctl(fd, DMX_SET_FILTER, &sct); @@ -302,7 +344,7 @@ void eDVBPESReader::data(int) return; if(r < 0) { - if (errno == EAGAIN) /* ok */ + if (errno == EAGAIN || errno == EINTR) /* ok */ return; eWarning("ERROR reading PES (fd=%d) - %m", m_fd); return; @@ -312,6 +354,8 @@ void eDVBPESReader::data(int) m_read(buffer, r); else eWarning("PES reader not active"); + if (r != 16384) + break; } } @@ -322,9 +366,9 @@ eDVBPESReader::eDVBPESReader(eDVBDemux *demux, eMainloop *context, RESULT &res): if (m_fd >= 0) { - ::ioctl(m_fd, DMX_SET_BUFFER_SIZE, 64*1024); + setBufferSize(64*1024); ::fcntl(m_fd, F_SETFL, O_NONBLOCK); - m_notifier = new eSocketNotifier(context, m_fd, eSocketNotifier::Read, false); + m_notifier = eSocketNotifier::create(context, m_fd, eSocketNotifier::Read, false); CONNECT(m_notifier->activated, eDVBPESReader::data); res = 0; } else @@ -334,12 +378,18 @@ eDVBPESReader::eDVBPESReader(eDVBDemux *demux, eMainloop *context, RESULT &res): } } +RESULT eDVBPESReader::setBufferSize(int size) +{ + int res = ::ioctl(m_fd, DMX_SET_BUFFER_SIZE, size); + if (res < 0) + eDebug("eDVBPESReader DMX_SET_BUFFER_SIZE failed(%m)"); + return res; +} + DEFINE_REF(eDVBPESReader) eDVBPESReader::~eDVBPESReader() { - if (m_notifier) - delete m_notifier; if (m_fd >= 0) ::close(m_fd); } @@ -399,15 +449,18 @@ class eDVBRecordFileThread: public eFilePushThread { public: eDVBRecordFileThread(); - void setTimingPID(int pid); + void setTimingPID(int pid, int type); - void saveTimingInformation(const std::string &filename); + void startSaveMetaInformation(const std::string &filename); + void stopSaveMetaInformation(); + int getLastPTS(pts_t &pts); protected: - void filterRecordData(const unsigned char *data, int len); + int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining); private: eMPEGStreamParserTS m_ts_parser; eMPEGStreamInformation m_stream_info; off_t m_current_offset; + pts_t m_last_pcr; /* very approximate.. */ int m_pid; }; @@ -417,21 +470,33 @@ eDVBRecordFileThread::eDVBRecordFileThread() m_current_offset = 0; } -void eDVBRecordFileThread::setTimingPID(int pid) +void eDVBRecordFileThread::setTimingPID(int pid, int type) +{ + m_ts_parser.setPid(pid, type); +} + +void eDVBRecordFileThread::startSaveMetaInformation(const std::string &filename) +{ + m_stream_info.startSave(filename.c_str()); +} + +void eDVBRecordFileThread::stopSaveMetaInformation() { - m_ts_parser.setPid(pid); + m_stream_info.stopSave(); } -void eDVBRecordFileThread::saveTimingInformation(const std::string &filename) +int eDVBRecordFileThread::getLastPTS(pts_t &pts) { - m_stream_info.save(filename.c_str()); + return m_ts_parser.getLastPTS(pts); } -void eDVBRecordFileThread::filterRecordData(const unsigned char *data, int len) +int eDVBRecordFileThread::filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining) { m_ts_parser.parseData(m_current_offset, data, len); m_current_offset += len; + + return len; } DEFINE_REF(eDVBTSRecorder); @@ -441,6 +506,7 @@ eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux) m_running = 0; m_target_fd = -1; m_thread = new eDVBRecordFileThread(); + CONNECT(m_thread->m_event, eDVBTSRecorder::filepushEvent); #ifndef HAVE_ADD_PID m_demux->m_dvr_busy = 1; #endif @@ -457,12 +523,17 @@ eDVBTSRecorder::~eDVBTSRecorder() RESULT eDVBTSRecorder::start() { + std::map::iterator i(m_pids.begin()); + if (m_running) return -1; if (m_target_fd == -1) return -2; + if (i == m_pids.end()) + return -3; + char filename[128]; #ifndef HAVE_ADD_PID #if HAVE_DVB_API_VERSION < 3 @@ -487,14 +558,20 @@ RESULT eDVBTSRecorder::start() eDebug("FAILED to open demux (%s) in ts recoder (%m)", filename); return -3; } - - ::ioctl(m_source_fd, DMX_SET_BUFFER_SIZE, 1024*1024); + + setBufferSize(1024*1024); dmx_pes_filter_params flt; +#if HAVE_DVB_API_VERSION > 3 + flt.pes_type = DMX_PES_OTHER; + flt.output = DMX_OUT_TSDEMUX_TAP; +#else flt.pes_type = (dmx_pes_type_t)DMX_TAP_TS; - flt.pid = (__u16)-1; - flt.input = DMX_IN_FRONTEND; flt.output = DMX_OUT_TAP; +#endif + flt.pid = i->first; + ++i; + flt.input = DMX_IN_FRONTEND; flt.flags = 0; int res = ::ioctl(m_source_fd, DMX_SET_PES_FILTER, &flt); if (res) @@ -507,16 +584,29 @@ RESULT eDVBTSRecorder::start() ::ioctl(m_source_fd, DMX_START); #endif + + if (m_target_filename != "") + m_thread->startSaveMetaInformation(m_target_filename); 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) + + while (i != m_pids.end()) { startPID(i->first); - + ++i; + } + return 0; } +RESULT eDVBTSRecorder::setBufferSize(int size) +{ + int res = ::ioctl(m_source_fd, DMX_SET_BUFFER_SIZE, size); + if (res < 0) + eDebug("eDVBTSRecorder DMX_SET_BUFFER_SIZE failed(%m)"); + return res; +} + RESULT eDVBTSRecorder::addPID(int pid) { if (m_pids.find(pid) != m_pids.end()) @@ -540,11 +630,9 @@ RESULT eDVBTSRecorder::removePID(int pid) return 0; } -RESULT eDVBTSRecorder::setTimingPID(int pid) +RESULT eDVBTSRecorder::setTimingPID(int pid, int type) { - if (m_running) - return -1; - m_thread->setTimingPID(pid); + m_thread->setTimingPID(pid, type); return 0; } @@ -567,22 +655,51 @@ RESULT eDVBTSRecorder::setBoundary(off_t max) RESULT eDVBTSRecorder::stop() { + int state=3; + for (std::map::iterator i(m_pids.begin()); i != m_pids.end(); ++i) stopPID(i->first); if (!m_running) return -1; + +#if HAVE_DVB_API_VERSION >= 5 + /* workaround for record thread stop */ + if (::ioctl(m_source_fd, DMX_STOP) < 0) + perror("DMX_STOP"); + else + state &= ~1; + + if (::close(m_source_fd) < 0) + perror("close"); + else + state &= ~2; +#endif + m_thread->stop(); - - close(m_source_fd); + + if (state & 3) + ::close(m_source_fd); + + m_running = 0; m_source_fd = -1; - - if (m_target_filename != "") - m_thread->saveTimingInformation(m_target_filename + ".ap"); - + + m_thread->stopSaveMetaInformation(); return 0; } +RESULT eDVBTSRecorder::getCurrentPCR(pts_t &pcr) +{ + if (!m_running) + return 0; + if (!m_thread) + return 0; + /* XXX: we need a lock here */ + + /* we don't filter PCR data, so just use the last received PTS, which is not accurate, but better than nothing */ + return m_thread->getLastPTS(pcr); +} + RESULT eDVBTSRecorder::connectEvent(const Slot1 &event, ePtr &conn) { conn = new eConnection(this, m_event.connect(event)); @@ -624,10 +741,22 @@ RESULT eDVBTSRecorder::startPID(int pid) } m_pids[pid] = fd; #else - if (::ioctl(m_source_fd, DMX_ADD_PID, pid)) - perror("DMX_ADD_PID"); - else - m_pids[pid] = 1; + while(true) { +#if HAVE_DVB_API_VERSION > 3 + __u16 p = pid; + if (::ioctl(m_source_fd, DMX_ADD_PID, &p) < 0) { +#else + if (::ioctl(m_source_fd, DMX_ADD_PID, pid) < 0) { +#endif + perror("DMX_ADD_PID"); + if (errno == EAGAIN || errno == EINTR) { + eDebug("retry!"); + continue; + } + } else + m_pids[pid] = 1; + break; + } #endif return 0; } @@ -640,9 +769,32 @@ void eDVBTSRecorder::stopPID(int pid) #else if (m_pids[pid] != -1) { - if (::ioctl(m_source_fd, DMX_REMOVE_PID, pid)) - perror("DMX_REMOVE_PID"); + while(true) { +#if HAVE_DVB_API_VERSION > 3 + __u16 p = pid; + if (::ioctl(m_source_fd, DMX_REMOVE_PID, &p) < 0) { +#else + if (::ioctl(m_source_fd, DMX_REMOVE_PID, pid) < 0) { +#endif + perror("DMX_REMOVE_PID"); + if (errno == EAGAIN || errno == EINTR) { + eDebug("retry!"); + continue; + } + } + break; + } } #endif m_pids[pid] = -1; } + +void eDVBTSRecorder::filepushEvent(int event) +{ + switch (event) + { + case eFilePushThread::evtWriteError: + m_event(eventWriteError); + break; + } +}