#ifndef __esection_h #define __esection_h #include #include #define TABLE_eDebug(x...) do { if (m_debug) eDebug(x); } while(0) #define TABLE_eDebugNoNewLine(x...) do { if (m_debug) eDebugNoNewLine(x); } while(0) class eGTable: public iObject, public Object { DECLARE_REF(eGTable); ePtr m_reader; eDVBTableSpec m_table; unsigned int m_tries; ePtr m_timeout; void sectionRead(const __u8 *data); void timeout(); ePtr m_sectionRead_conn; protected: bool m_debug; virtual int createTable(unsigned int nr, const __u8 *data, unsigned int max)=0; public: Signal1 tableReady; eGTable(bool debug=true); RESULT start(iDVBSectionReader *reader, const eDVBTableSpec &table); RESULT start(iDVBDemux *reader, const eDVBTableSpec &table); RESULT getSpec(eDVBTableSpec &spec) { spec = m_table; return 0; } virtual ~eGTable(); int error; int ready; }; template class eTable: public eGTable { private: std::vector sections; std::set avail; protected: int createTable(unsigned int nr, const __u8 *data, unsigned int max) { unsigned int ssize = sections.size(); if (max < ssize || nr >= max) { TABLE_eDebug("kaputt max(%d) < ssize(%d) || nr(%d) >= max(%d)", max, ssize, nr, max); return 0; } if (avail.find(nr) != avail.end()) delete sections[nr]; sections.resize(max); sections[nr] = new Section(data); avail.insert(nr); for (unsigned int i = 0; i < max; ++i) if (avail.find(i) != avail.end()) TABLE_eDebugNoNewLine("+"); else TABLE_eDebugNoNewLine("-"); TABLE_eDebug(" %d/%d TID %02x", avail.size(), max, data[0]); if (avail.size() == max) { TABLE_eDebug("done!"); return 1; } else return 0; } public: std::vector &getSections() { return sections; } eTable(bool debug=true): eGTable(debug) { } ~eTable() { for (std::set::iterator i(avail.begin()); i != avail.end(); ++i) delete sections[*i]; } }; class eAUGTable: public Object { protected: void slotTableReady(int); public: Signal1 tableReady; virtual void getNext(int err)=0; }; template class eAUTable: public eAUGTable { ePtr current, next; // current is READY AND ERRORFREE, next is not yet ready int first; ePtr m_demux; eMainloop *ml; /* needed to detect broken table version handling (seen on some m2ts files) */ struct timespec m_prev_table_update; int m_table_cnt; public: eAUTable() { } ~eAUTable() { stop(); } void stop() { current = next = 0; m_demux = 0; } int begin(eMainloop *m, const eDVBTableSpec &spec, ePtr demux) { m_table_cnt = 0; ml = m; m_demux = demux; first= 1; current = 0; next = new Table(); CONNECT(next->tableReady, eAUTable::slotTableReady); next->start(demux, spec); return 0; } int get() { if (current) { /*emit*/ tableReady(0); return 0; } else if (!next) { /*emit*/ tableReady(-1); return 0; } else return 1; } RESULT getCurrent(ePtr
&ptr) { if (!current) return -1; ptr = current; return 0; } #if 0 void abort() { eDebug("eAUTable: aborted!"); if (next) next->abort(); delete next; next=0; } #endif int ready() { return !!current; } void inject(Table *t) { next=t; getNext(0); } void getNext(int error) { current = 0; if (error) { next=0; if (first) /*emit*/ tableReady(error); first=0; return; } else current=next; next=0; first=0; ASSERT(current->ready); /*emit*/ tableReady(0); eDVBTableSpec spec; if (current && (!current->getSpec(spec))) { /* detect broken table version handling (seen on some m2ts files) */ if (m_table_cnt) { if (abs(timeout_usec(m_prev_table_update)) > 500000) m_table_cnt = -1; else if (m_table_cnt > 1) // two pmt update within one second { eDebug("Seen two consecutive table version changes within 500ms. " "This seems broken, so auto update for pid %04x, table %02x is now disabled!!", spec.pid, spec.tid); m_table_cnt = 0; return; } } ++m_table_cnt; clock_gettime(CLOCK_MONOTONIC, &m_prev_table_update); next = new Table(); CONNECT(next->tableReady, eAUTable::slotTableReady); spec.flags &= ~(eDVBTableSpec::tfAnyVersion|eDVBTableSpec::tfThisVersion|eDVBTableSpec::tfHaveTimeout); next->eGTable::start(m_demux, spec); } } }; #endif