Merge branch 'bug_241_EOFrestart' into experimental
[vuplus_dvbapp] / lib / dvb / esection.h
1 #ifndef __esection_h
2 #define __esection_h
3
4 #include <lib/dvb/idemux.h>
5 #include <set>
6
7 #define TABLE_eDebug(x...) do { if (m_debug) eDebug(x); } while(0)
8 #define TABLE_eDebugNoNewLine(x...) do { if (m_debug) eDebugNoNewLine(x); } while(0)
9
10 class eGTable: public iObject, public Object
11 {
12         DECLARE_REF(eGTable);
13         ePtr<iDVBSectionReader> m_reader;
14         eDVBTableSpec m_table;
15         
16         unsigned int m_tries;
17         
18         ePtr<eTimer> m_timeout;
19
20         void sectionRead(const __u8 *data);
21         void timeout();
22         ePtr<eConnection> m_sectionRead_conn;
23 protected:
24         bool m_debug;
25         virtual int createTable(unsigned int nr, const __u8 *data, unsigned int max)=0;
26 public:
27         Signal1<void, int> tableReady;
28         eGTable(bool debug=true);
29         RESULT start(iDVBSectionReader *reader, const eDVBTableSpec &table);
30         RESULT start(iDVBDemux *reader, const eDVBTableSpec &table);
31         RESULT getSpec(eDVBTableSpec &spec) { spec = m_table; return 0; }
32         virtual ~eGTable();
33         int error;
34         int ready;
35 };
36
37 template <class Section>
38 class eTable: public eGTable
39 {
40 private:
41         std::vector<Section*> sections;
42         std::set<int> avail;
43 protected:
44         int createTable(unsigned int nr, const __u8 *data, unsigned int max)
45         {
46                 unsigned int ssize = sections.size();
47                 if (max < ssize || nr >= max)
48                 {
49                         TABLE_eDebug("kaputt max(%d) < ssize(%d) || nr(%d) >= max(%d)",
50                                 max, ssize, nr, max);
51                         return 0;
52                 }
53                 if (avail.find(nr) != avail.end())
54                         delete sections[nr];
55
56                 sections.resize(max);
57                 sections[nr] = new Section(data);
58                 avail.insert(nr);
59
60                 for (unsigned int i = 0; i < max; ++i)
61                         if (avail.find(i) != avail.end())
62                                 TABLE_eDebugNoNewLine("+");
63                         else
64                                 TABLE_eDebugNoNewLine("-");
65                                 
66                 TABLE_eDebug(" %zd/%d TID %02x", avail.size(), max, data[0]);
67
68                 if (avail.size() == max)
69                 {
70                         TABLE_eDebug("done!");
71                         return 1;
72                 } else
73                         return 0;
74         }
75 public:
76         std::vector<Section*> &getSections() { return sections; }
77         eTable(bool debug=true): eGTable(debug)
78         {
79         }
80         ~eTable()
81         {
82                 for (std::set<int>::iterator i(avail.begin()); i != avail.end(); ++i)
83                         delete sections[*i];
84         }
85 };
86
87 class eAUGTable: public Object
88 {
89 protected:
90         void slotTableReady(int);
91 public:
92         Signal1<void, int> tableReady;
93         virtual void getNext(int err)=0;
94 };
95
96 template <class Table>
97 class eAUTable: public eAUGTable
98 {
99         ePtr<Table> current, next;              // current is READY AND ERRORFREE, next is not yet ready
100         int first;
101         ePtr<iDVBDemux> m_demux;
102         eMainloop *ml;
103
104         /* needed to detect broken table version handling (seen on some m2ts files) */
105         struct timespec m_prev_table_update;
106         int m_table_cnt;
107 public:
108
109         eAUTable()
110         {
111         }
112
113         ~eAUTable()
114         {
115                 stop();
116         }
117         
118         void stop()
119         {
120                 current = next = 0;
121                 m_demux = 0;
122         }
123         
124         int begin(eMainloop *m, const eDVBTableSpec &spec, ePtr<iDVBDemux> demux)
125         {
126                 m_table_cnt = 0;
127                 ml = m;
128                 m_demux = demux;
129                 first= 1;
130                 current = 0;
131                 next = new Table();
132                 CONNECT(next->tableReady, eAUTable::slotTableReady);
133                 next->start(demux, spec);
134                 return 0;
135         }
136         
137         int get()
138         {
139                 if (current)
140                 {
141                         /*emit*/ tableReady(0);
142                         return 0;
143                 } else if (!next)
144                 {
145                         /*emit*/ tableReady(-1);
146                         return 0;
147                 } else
148                         return 1;
149         }
150         
151         RESULT getCurrent(ePtr<Table> &ptr)
152         {
153                 if (!current)
154                         return -1;
155                 ptr = current;
156                 return 0;
157         }
158
159 #if 0   
160         void abort()
161         {
162                 eDebug("eAUTable: aborted!");
163                 if (next)
164                         next->abort();
165                 delete next;
166                 next=0;
167         }
168 #endif
169
170         int ready()
171         {
172                 return !!current;
173         }
174         
175         void inject(Table *t)
176         {
177                 next=t;
178                 getNext(0);
179         }
180
181         void getNext(int error)
182         {
183                 current = 0;
184                 if (error)
185                 {
186                         next=0;
187                         if (first)
188                                 /*emit*/ tableReady(error);
189                         first=0;
190                         return;
191                 } else
192                         current=next;
193
194                 next=0;
195                 first=0;
196                 
197                 ASSERT(current->ready);
198                         
199                 /*emit*/ tableReady(0);
200                 
201                 eDVBTableSpec spec;
202
203                 if (current && (!current->getSpec(spec)))
204                 {
205                         /* detect broken table version handling (seen on some m2ts files) */
206                         if (m_table_cnt)
207                         {
208                                 if (abs(timeout_usec(m_prev_table_update)) > 500000)
209                                         m_table_cnt = -1;
210                                 else if (m_table_cnt > 1) // two pmt update within one second
211                                 {
212                                         eDebug("Seen two consecutive table version changes within 500ms. "
213                                             "This seems broken, so auto update for pid %04x, table %02x is now disabled!!",
214                                             spec.pid, spec.tid);
215                                         m_table_cnt = 0;
216                                         return;
217                                 }
218                         }
219
220                         ++m_table_cnt;
221                         clock_gettime(CLOCK_MONOTONIC, &m_prev_table_update);
222
223                         next = new Table();
224                         CONNECT(next->tableReady, eAUTable::slotTableReady);
225                         spec.flags &= ~(eDVBTableSpec::tfAnyVersion|eDVBTableSpec::tfThisVersion|eDVBTableSpec::tfHaveTimeout);
226                         next->eGTable::start(m_demux, spec);
227                 }
228         }
229 };
230
231 #endif