5d30137340c69b990ae9e7386d7615f558f15aeb
[enigma2.git] / lib / dvb / pvrparse.cpp
1 #include <lib/dvb/pvrparse.h>
2 #include <lib/base/eerror.h>
3 #include <byteswap.h>
4
5 #ifndef BYTE_ORDER
6 #error no byte order defined!
7 #endif
8
9 int eMPEGStreamInformation::save(const char *filename)
10 {
11         FILE *f = fopen(filename, "wb");
12         if (!f)
13                 return -1;
14         
15         for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
16         {
17                 unsigned long long d[2];
18 #if BYTE_ORDER == BIG_ENDIAN
19                 d[0] = i->first;
20                 d[1] = i->second;
21 #else
22                 d[0] = bswap_64(i->first);
23                 d[1] = bswap_64(i->second);
24 #endif
25                 fwrite(d, sizeof(d), 1, f);
26         }
27         fclose(f);
28         
29         return 0;
30 }
31
32 int eMPEGStreamInformation::load(const char *filename)
33 {
34         FILE *f = fopen(filename, "rb");
35         if (!f)
36                 return -1;
37         m_access_points.clear();
38         while (1)
39         {
40                 unsigned long long d[2];
41                 if (fread(d, sizeof(d), 1, f) < 1)
42                         break;
43                 
44 #if BYTE_ORDER == LITTLE_ENDIAN
45                 d[0] = bswap_64(d[0]);
46                 d[1] = bswap_64(d[1]);
47 #endif
48                 m_access_points[d[0]] = d[1];
49         }
50         fclose(f);
51         fixupDiscontinuties();
52         return 0;
53 }
54
55 bool eMPEGStreamInformation::empty()
56 {
57         return m_access_points.empty();
58 }
59
60 void eMPEGStreamInformation::fixupDiscontinuties()
61 {
62         m_timestamp_deltas.clear();
63         if (!m_access_points.size())
64                 return;
65                 
66         int first_is_unreliable = 0;
67         eDebug("Fixing discontinuities ...");
68
69                         /* if we have no delta at the beginning, extrapolate it */
70         if ((m_access_points.find(0) == m_access_points.end()) && (m_access_points.size() > 1))
71         {
72                 std::map<off_t,pts_t>::const_iterator second = m_access_points.begin();
73                 std::map<off_t,pts_t>::const_iterator first  = second++;
74                 if (first->first < second->first) /* i.e., not equal or broken */
75                 {
76                         off_t diff = second->first - first->first;
77                         pts_t tdiff = second->second - first->second;
78                         tdiff *= first->first;
79                         tdiff /= diff;
80                         m_timestamp_deltas[0] = first->second - tdiff;
81                         first_is_unreliable = 1;
82                         eDebug("first delta is %08llx", first->second - tdiff);
83                 }
84         }
85
86         if (m_timestamp_deltas.empty())
87                 m_timestamp_deltas[m_access_points.begin()->first] = m_access_points.begin()->second;
88
89         pts_t currentDelta = m_timestamp_deltas.begin()->second, lastpts_t = 0;
90         for (std::map<off_t,pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
91         {
92                 pts_t current = i->second - currentDelta;
93                 pts_t diff = current - lastpts_t;
94                 if ((first_is_unreliable) || (diff > (90000*5))) // 5sec diff
95                 {
96                         first_is_unreliable = 0;
97                         eDebug("%llx < %llx, have discont. new timestamp is %llx (diff is %llx)!", current, lastpts_t, i->second, diff);
98                         currentDelta = i->second - lastpts_t; /* FIXME: should be the extrapolated new timestamp, based on the current rate */
99                         eDebug("current delta now %llx, making current to %llx", currentDelta, i->second - currentDelta);
100                         m_timestamp_deltas[i->first] = currentDelta;
101                 }
102                 lastpts_t = i->second - currentDelta;
103         }
104         
105         
106         eDebug("ok, found %d disconts.", m_timestamp_deltas.size());
107         
108         
109         for (off_t x=0; x < 1000000; x+= 100000)
110         {
111                 eDebug("%08llx -> %08llx | %08llx", x, getDelta(x), getInterpolated(x));
112         }
113 }
114
115 pts_t eMPEGStreamInformation::getDelta(off_t offset)
116 {
117         if (!m_timestamp_deltas.size())
118                 return 0;
119         std::map<off_t,pts_t>::iterator i = m_timestamp_deltas.upper_bound(offset);
120
121                 /* i can be the first when you query for something before the first PTS */
122         if (i != m_timestamp_deltas.begin())
123                 --i;
124         
125         return i->second;
126 }
127
128 pts_t eMPEGStreamInformation::fixuppts_t(off_t offset, pts_t ts)
129 {
130         if (!m_timestamp_deltas.size())
131                 return 0;
132         std::map<off_t, pts_t>::const_iterator i = m_access_points.upper_bound(offset - 1024 * 1024), nearest = m_access_points.end();
133         
134         while (i != m_access_points.end())
135         {
136                 if ((nearest == m_access_points.end()) || (llabs(i->second - ts) < llabs(nearest->second - ts)))
137                         nearest = i;
138                 ++i;
139         }
140         if (nearest == m_access_points.end())
141                 return 0;
142         return ts - getDelta(nearest->first);
143 }
144
145 pts_t eMPEGStreamInformation::getInterpolated(off_t offset)
146 {
147                 /* get the PTS values before and after the offset. */
148         std::map<off_t,pts_t>::iterator before, after;
149         
150         after = m_access_points.upper_bound(offset);
151         before = after;
152
153         if (before != m_access_points.begin())
154                 --before;
155         else    /* we query before the first known timestamp ... FIXME */
156                 return 0;
157
158                 /* empty... */
159         if (before == m_access_points.end())
160                 return 0;
161
162                 /* if after == end, then we need to extrapolate ... FIXME */
163         if ((before->first == offset) || (after == m_access_points.end()))
164                 return before->second - getDelta(offset);
165         
166         pts_t before_ts = before->second - getDelta(before->first);
167         pts_t after_ts = after->second - getDelta(after->first);
168         
169 //      eDebug("%08llx .. ? .. %08llx", before_ts, after_ts);
170 //      eDebug("%08llx .. %08llx .. %08llx", before->first, offset, after->first);
171         
172         pts_t diff = after_ts - before_ts;
173         off_t diff_off = after->first - before->first;
174         
175         diff = (offset - before->first) * diff / diff_off;
176 //      eDebug("%08llx .. %08llx .. %08llx", before_ts, before_ts + diff, after_ts);
177         return before_ts + diff;
178 }
179  
180 off_t eMPEGStreamInformation::getAccessPoint(pts_t ts)
181 {
182                 /* FIXME: more efficient implementation */
183         pts_t delta = 0;
184         off_t last = 0;
185         for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
186         {
187                 std::map<off_t, pts_t>::const_iterator d = m_timestamp_deltas.find(i->first);
188                 if (d != m_timestamp_deltas.end())
189                         delta = d->second;
190                 pts_t c = i->second - delta;
191                 if (c > ts)
192                         break;
193                 last = i->first;
194         }
195         return last;
196 }
197
198 eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): m_streaminfo(streaminfo), m_pktptr(0), m_pid(-1), m_need_next_packet(0), m_skip(0)
199 {
200 }
201
202 int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
203 {
204         if (!wantPacket(pkt))
205                 printf("ne irgendwas ist da falsch\n");
206
207         const unsigned char *end = pkt + 188;
208         
209         if (!(pkt[3] & 0x10))
210         {
211                 eWarning("[TSPARSE] PUSI set but no payload.");
212                 return 0;
213         }
214         
215         if (pkt[3] & 0x20) // adaption field present?
216                 pkt += pkt[4] + 4 + 1;  /* skip adaption field and header */
217         else
218                 pkt += 4; /* skip header */
219
220         if (pkt > end)
221         {
222                 eWarning("[TSPARSE] dropping huge adaption field");
223                 return 0;
224         }
225         
226                 // ok, we now have the start of the payload, aligned with the PES packet start.
227         if (pkt[0] || pkt[1] || (pkt[2] != 1))
228         {
229                 eWarning("broken startcode");
230                 return 0;
231         }
232         
233         
234         pts_t pts = 0;
235         int ptsvalid = 0;
236         
237         if (pkt[7] & 0x80) // PTS present?
238         {
239                 pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
240                 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
241                 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
242                 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
243                 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
244                 ptsvalid = 1;
245
246 #if 0           
247                 int sec = pts / 90000;
248                 int frm = pts % 90000;
249                 int min = sec / 60;
250                 sec %= 60;
251                 int hr = min / 60;
252                 min %= 60;
253                 int d = hr / 24;
254                 hr %= 24;
255                 
256                 eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
257 #endif
258         }
259         
260                 /* advance to payload */
261         pkt += pkt[8] + 9;
262         
263                 /* if startcode found */
264         if (!(pkt[0] || pkt[1] || (pkt[2] != 1)))
265         {
266                 if (pkt[3] == 0xb3) /* sequence header */
267                 {
268                         if (ptsvalid)
269                         {
270                                 m_streaminfo.m_access_points[offset] = pts;
271                                 eDebug("Sequence header at %llx, pts %llx", offset, pts);
272                         } else
273                                 eDebug("Sequence header but no valid PTS value.");
274                 }
275         }
276         return 0;
277 }
278
279 inline int eMPEGStreamParserTS::wantPacket(const unsigned char *hdr) const
280 {
281         if (hdr[0] != 0x47)
282         {
283                 eDebug("missing sync!");
284                 return 0;
285         }
286         int ppid = ((hdr[1]&0x1F) << 8) | hdr[2];
287
288         if (ppid != m_pid)
289                 return 0;
290                 
291         if (m_need_next_packet)  /* next packet (on this pid) was required? */
292                 return 1;
293         
294         if (hdr[1] & 0x40)       /* pusi set: yes. */
295                 return 1;
296
297         return 0;
298 }
299
300 void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int len)
301 {
302         const unsigned char *packet = (const unsigned char*)data;
303         const unsigned char *packet_start = packet;
304         
305                         /* sorry for the redundant code here, but there are too many special cases... */
306         while (len)
307         {
308                 if (m_pktptr)
309                 {
310                                 /* skip last packet */
311                         if (m_pktptr < 0)
312                         {
313                                 unsigned int skiplen = -m_pktptr;
314                                 if (skiplen > len)
315                                         skiplen = len;
316                                 packet += skiplen;
317                                 len -= skiplen;
318                                 m_pktptr += skiplen;
319                                 continue;
320                         } else if (m_pktptr < 4) /* header not complete, thus we don't know if we want this packet */
321                         {
322                                 unsigned int storelen = 4 - m_pktptr;
323                                 if (storelen > len)
324                                         storelen = len;
325                                 memcpy(m_pkt + m_pktptr, packet,  storelen);
326                                 
327                                 m_pktptr += storelen;
328                                 len -= storelen;
329                                 packet += storelen;
330                                 
331                                 if (m_pktptr == 4)
332                                         if (!wantPacket(m_pkt))
333                                         {
334                                                         /* skip packet */
335                                                 packet += 184;
336                                                 len -= 184;
337                                                 m_pktptr = 0;
338                                                 continue;
339                                         }
340                         }
341                                 /* otherwise we complete up to the full packet */
342                         unsigned int storelen = 188 - m_pktptr;
343                         if (storelen > len)
344                                 storelen = len;
345                         memcpy(m_pkt + m_pktptr, packet,  storelen);
346                         m_pktptr += storelen;
347                         len -= storelen;
348                         packet += storelen;
349                         
350                         if (m_pktptr == 188)
351                         {
352                                 m_need_next_packet = processPacket(m_pkt, offset + (packet - packet_start));
353                                 m_pktptr = 0;
354                         }
355                 } else if (len >= 4)  /* if we have a full header... */
356                 {
357                         if (wantPacket(packet))  /* decide wheter we need it ... */
358                         {
359                                 if (len >= 188)          /* packet complete? */
360                                 {
361                                         m_need_next_packet = processPacket(packet, offset + (packet - packet_start)); /* process it now. */
362                                 } else
363                                 {
364                                         memcpy(m_pkt, packet, len);  /* otherwise queue it up */
365                                         m_pktptr = len;
366                                 }
367                         }
368
369                                 /* skip packet */
370                         int sk = len;
371                         if (sk >= 188)
372                                 sk = 188;
373                         else if (!m_pktptr) /* we dont want this packet, otherwise m_pktptr = sk (=len) > 4 */
374                                 m_pktptr = sk - 188;
375
376                         len -= sk;
377                         packet += sk;
378                 } else             /* if we don't have a complete header */
379                 {
380                         memcpy(m_pkt, packet, len);   /* complete header next time */
381                         m_pktptr = len;
382                         packet += len;
383                         len = 0;
384                 }
385         }
386 }
387
388 void eMPEGStreamParserTS::setPid(int _pid)
389 {
390         m_pktptr = 0;
391         m_pid = _pid;
392 }