[MovieSelection] fix bug on MovieSelection.
[vuplus_dvbapp] / 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 eMPEGStreamInformation::eMPEGStreamInformation()
10         : m_structure_cache_entries(0), m_structure_read(0), m_structure_write(0)
11 {
12 }
13
14 eMPEGStreamInformation::~eMPEGStreamInformation()
15 {
16         readClose();
17         writeClose();
18 }
19
20 void eMPEGStreamInformation::readClose()
21 {
22         if (m_structure_read)
23         {
24                 fclose(m_structure_read);
25                 m_structure_read = 0;
26         }
27 }
28
29 void eMPEGStreamInformation::writeClose()
30 {
31         if (m_structure_write)
32         {
33                 fclose(m_structure_write);
34                 m_structure_write = 0;
35         }
36 }
37
38 int eMPEGStreamInformation::startSave(const char *filename)
39 {
40         m_filename = filename;
41         m_structure_write = fopen((m_filename + ".sc").c_str(), "wb");
42         return 0;
43 }
44
45 int eMPEGStreamInformation::stopSave(void)
46 {
47         if (m_structure_write)
48         {
49                 fclose(m_structure_write);
50                 m_structure_write = 0;
51         }
52
53         if (m_access_points.empty())
54                 return 0;
55
56         if (m_filename == "")
57                 return -1;
58         FILE *f = fopen((m_filename + ".ap").c_str(), "wb");
59         if (!f)
60                 return -1;
61         
62         for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
63         {
64                 unsigned long long d[2];
65 #if BYTE_ORDER == BIG_ENDIAN
66                 d[0] = i->first;
67                 d[1] = i->second;
68 #else
69                 d[0] = bswap_64(i->first);
70                 d[1] = bswap_64(i->second);
71 #endif
72                 fwrite(d, sizeof(d), 1, f);
73         }
74         fclose(f);
75         
76         return 0;
77 }
78
79 int eMPEGStreamInformation::load(const char *filename)
80 {
81         m_filename = filename;
82         readClose();
83         m_structure_read = fopen((std::string(m_filename) + ".sc").c_str(), "rb");
84         m_access_points.clear();
85         m_pts_to_offset.clear();
86         m_timestamp_deltas.clear();
87         FILE *f = fopen((std::string(m_filename) + ".ap").c_str(), "rb");
88         if (!f)
89                 return -1;
90         while (1)
91         {
92                 unsigned long long d[2];
93                 if (fread(d, sizeof(d), 1, f) < 1)
94                         break;
95                 
96 #if BYTE_ORDER == LITTLE_ENDIAN
97                 d[0] = bswap_64(d[0]);
98                 d[1] = bswap_64(d[1]);
99 #endif
100                 m_access_points[d[0]] = d[1];
101                 m_pts_to_offset.insert(std::pair<pts_t,off_t>(d[1], d[0]));
102         }
103         fclose(f);
104         fixupDiscontinuties();
105         return 0;
106 }
107
108 void eMPEGStreamInformation::fixupDiscontinuties()
109 {
110         m_timestamp_deltas.clear();
111         if (!m_access_points.size())
112                 return;
113                 
114 //      eDebug("Fixing discontinuities ...");
115
116                         /* if we have no delta at the beginning, extrapolate it */
117         if ((m_access_points.find(0) == m_access_points.end()) && (m_access_points.size() > 1))
118         {
119                 std::map<off_t,pts_t>::const_iterator second = m_access_points.begin();
120                 std::map<off_t,pts_t>::const_iterator first  = second++;
121                 if (first->first < second->first) /* i.e., not equal or broken */
122                 {
123                         off_t diff = second->first - first->first;
124                         pts_t tdiff = second->second - first->second;
125                         tdiff *= first->first;
126                         tdiff /= diff;
127                         m_timestamp_deltas[0] = first->second - tdiff;
128 //                      eDebug("first delta is %08llx", first->second - tdiff);
129                 }
130         }
131
132         if (m_timestamp_deltas.empty())
133                 m_timestamp_deltas[m_access_points.begin()->first] = m_access_points.begin()->second;
134
135         pts_t currentDelta = m_timestamp_deltas.begin()->second, lastpts_t = 0;
136         for (std::map<off_t,pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
137         {
138                 pts_t current = i->second - currentDelta;
139                 pts_t diff = current - lastpts_t;
140                 
141                 if (llabs(diff) > (90000*10)) // 10sec diff
142                 {
143 //                      eDebug("%llx < %llx, have discont. new timestamp is %llx (diff is %llx)!", current, lastpts_t, i->second, diff);
144                         currentDelta = i->second - lastpts_t; /* FIXME: should be the extrapolated new timestamp, based on the current rate */
145 //                      eDebug("current delta now %llx, making current to %llx", currentDelta, i->second - currentDelta);
146                         m_timestamp_deltas[i->first] = currentDelta;
147                 }
148                 lastpts_t = i->second - currentDelta;
149         }
150         
151         
152 //      eDebug("ok, found %d disconts.", m_timestamp_deltas.size());
153
154 #if 0   
155         for (off_t x=0x25807E34ULL; x < 0x25B3CF70; x+= 100000)
156         {
157                 off_t o = x;
158                 pts_t p;
159                 int r = getPTS(o, p);
160                 eDebug("%08llx -> %08llx | %08llx, %d, %08llx %08llx", x, getDelta(x), getInterpolated(x), r, o, p);
161         }
162 #endif
163 }
164
165 pts_t eMPEGStreamInformation::getDelta(off_t offset)
166 {
167         if (!m_timestamp_deltas.size())
168                 return 0;
169         std::map<off_t,pts_t>::iterator i = m_timestamp_deltas.upper_bound(offset);
170
171                 /* i can be the first when you query for something before the first PTS */
172         if (i != m_timestamp_deltas.begin())
173                 --i;
174
175         return i->second;
176 }
177
178 int eMPEGStreamInformation::fixupPTS(const off_t &offset, pts_t &ts)
179 {
180         if (!m_timestamp_deltas.size())
181                 return -1;
182
183         std::multimap<pts_t, off_t>::const_iterator 
184                 l = m_pts_to_offset.upper_bound(ts - 60 * 90000), 
185                 u = m_pts_to_offset.upper_bound(ts + 60 * 90000), 
186                 nearest = m_pts_to_offset.end();
187
188         while (l != u)
189         {
190                 if ((nearest == m_pts_to_offset.end()) || (llabs(l->first - ts) < llabs(nearest->first - ts)))
191                         nearest = l;
192                 ++l;
193         }
194         if (nearest == m_pts_to_offset.end())
195                 return 1;
196
197         ts -= getDelta(nearest->second);
198
199         return 0;
200 }
201
202 int eMPEGStreamInformation::getPTS(off_t &offset, pts_t &pts)
203 {
204         std::map<off_t,pts_t>::iterator before = m_access_points.lower_bound(offset);
205
206                 /* usually, we prefer the AP before the given offset. however if there is none, we take any. */
207         if (before != m_access_points.begin())
208                 --before;
209         
210         if (before == m_access_points.end())
211         {
212                 pts = 0;
213                 return -1;
214         }
215         
216         offset = before->first;
217         pts = before->second - getDelta(offset);
218         
219         return 0;
220 }
221
222 pts_t eMPEGStreamInformation::getInterpolated(off_t offset)
223 {
224                 /* get the PTS values before and after the offset. */
225         std::map<off_t,pts_t>::iterator before, after;
226         after = m_access_points.upper_bound(offset);
227         before = after;
228
229         if (before != m_access_points.begin())
230                 --before;
231         else    /* we query before the first known timestamp ... FIXME */
232                 return 0;
233
234                 /* empty... */
235         if (before == m_access_points.end())
236                 return 0;
237
238                 /* if after == end, then we need to extrapolate ... FIXME */
239         if ((before->first == offset) || (after == m_access_points.end()))
240                 return before->second - getDelta(offset);
241         
242         pts_t before_ts = before->second - getDelta(before->first);
243         pts_t after_ts = after->second - getDelta(after->first);
244         
245 //      eDebug("%08llx .. ? .. %08llx", before_ts, after_ts);
246 //      eDebug("%08llx .. %08llx .. %08llx", before->first, offset, after->first);
247         
248         pts_t diff = after_ts - before_ts;
249         off_t diff_off = after->first - before->first;
250         
251         diff = (offset - before->first) * diff / diff_off;
252 //      eDebug("%08llx .. %08llx .. %08llx", before_ts, before_ts + diff, after_ts);
253         return before_ts + diff;
254 }
255  
256 off_t eMPEGStreamInformation::getAccessPoint(pts_t ts, int marg)
257 {
258                 /* FIXME: more efficient implementation */
259         off_t last = 0;
260         off_t last2 = 0;
261         pts_t lastc = 0;
262         ts += 1; // Add rounding error margin
263         for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
264         {
265                 pts_t delta = getDelta(i->first);
266                 pts_t c = i->second - delta;
267                 if (c > ts) {
268                         if (marg > 0)
269                                 return (last + i->first)/376*188;
270                         else if (marg < 0)
271                                 return (last + last2)/376*188;
272                         else
273                                 return last;
274                 }
275                 lastc = c;
276                 last2 = last;
277                 last = i->first;
278         }
279         if (marg < 0)
280                 return (last + last2)/376*188;
281         else
282                 return last;
283 }
284
285 int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
286 {
287         off_t offset = getAccessPoint(start);
288         pts_t c1, c2;
289         std::map<off_t, pts_t>::const_iterator i = m_access_points.find(offset);
290         if (i == m_access_points.end())
291         {
292                 eDebug("getNextAccessPoint: initial AP not found");
293                 return -1;
294         }
295         c1 = i->second - getDelta(i->first);
296         while (direction)
297         {
298                 if (direction > 0)
299                 {
300                         if (i == m_access_points.end())
301                                 return -1;
302                         ++i;
303                         c2 = i->second - getDelta(i->first);
304                         if (c1 == c2) { // Discontinuity
305                                 ++i;
306                                 c2 = i->second - getDelta(i->first);
307                         }
308                         c1 = c2;
309                         direction--;
310                 }
311                 if (direction < 0)
312                 {
313                         if (i == m_access_points.begin())
314                         {
315                                 eDebug("at start");
316                                 return -1;
317                         }
318                         --i;
319                         c2 = i->second - getDelta(i->first);
320                         if (c1 == c2) { // Discontinuity
321                                 --i;
322                                 c2 = i->second - getDelta(i->first);
323                         }
324                         c1 = c2;
325                         direction++;
326                 }
327         }
328         ts = i->second - getDelta(i->first);
329         eDebug("fine, at %llx - %llx = %llx", ts, i->second, getDelta(i->first));
330         eDebug("fine, at %lld - %lld = %lld", ts, i->second, getDelta(i->first));
331         return 0;
332 }
333
334 void eMPEGStreamInformation::writeStructureEntry(off_t offset, structure_data data)
335 {
336         unsigned long long d[2];
337 #if BYTE_ORDER == BIG_ENDIAN
338         d[0] = offset;
339         d[1] = data;
340 #else
341         d[0] = bswap_64(offset);
342         d[1] = bswap_64(data);
343 #endif
344         if (m_structure_write)
345                 fwrite(d, sizeof(d), 1, m_structure_write);
346 }
347
348 int eMPEGStreamInformation::getStructureEntry(off_t &offset, unsigned long long &data, int get_next)
349 {
350         if (!m_structure_read)
351         {
352                 eDebug("getStructureEntry failed because of no m_structure_read");
353                 return -1;
354         }
355
356         off_t _offset = offset;
357         const int struture_cache_size = sizeof(m_structure_cache) / 16;
358         if ((m_structure_cache_entries == 0) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(m_structure_cache_entries - (get_next ? 2 : 1)) * 2] <= offset))
359         {
360                 if(update_structure_cache_entries(_offset))
361                 {
362                         return -1;
363                 }
364         }
365         
366         int i = 0;
367         while ((off_t)m_structure_cache[i * 2] <= offset)
368         {
369                 ++i;
370                 if (i == m_structure_cache_entries)
371                 {
372                         eDebug("structure data consistency fail!, we are looking for %llx, but last entry is %llx", offset, m_structure_cache[i*2-2]);
373                         return -1;
374                 }
375         }
376         if (!i)
377         {
378                 eDebug("structure data (first entry) consistency fail!");
379                 return -1;
380         }
381         
382         if (!get_next)
383                 --i;
384
385 //      eDebug("[%d] looked for %lld, found %llu=%llx", sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]);
386         offset = m_structure_cache[i * 2];
387         data = m_structure_cache[i * 2 + 1];
388         return 0;
389 }
390
391 int eMPEGStreamInformation::getStructureEntry_next(off_t &offset, unsigned long long &data)
392 {
393         if (!m_structure_read)
394         {
395                 eDebug("getStructureEntry failed because of no m_structure_read");
396                 return -1;
397         }
398
399         off_t _offset = offset;
400         if ((m_structure_cache_entries == 0) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(m_structure_cache_entries - 1)*2] <= offset))
401         {
402                 if(update_structure_cache_entries(_offset))
403                 {
404                         return -1;
405                 }
406         }
407
408         int i = 0;
409         while ((off_t)m_structure_cache[i * 2] <= offset)
410         {
411                 ++i;
412                 if (i == m_structure_cache_entries)
413                 {
414                         eDebug("structure data consistency fail!, we are looking for %llu, but last entry is %llu", offset, m_structure_cache[(m_structure_cache_entries-1)*2]);
415                         return -1;
416                 }
417         }
418         if (!i)
419         {
420                 eDebug("structure data (first entry) consistency fail!");
421                 return -1;
422         }
423
424 //      eDebug("[%d] looked for %llu, found data %llu=%llx",sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]);
425         offset = m_structure_cache[i * 2];
426         data = m_structure_cache[i * 2 + 1];
427         return 0;
428 }
429
430 int eMPEGStreamInformation::getStructureEntry_prev(off_t &offset, unsigned long long &data)
431 {
432         if (!m_structure_read)
433         {
434                 eDebug("getStructureEntry failed because of no m_structure_read");
435                 return -1;
436         }
437
438         off_t _offset = offset;
439         if ((m_structure_cache_entries == 0) || ((off_t)m_structure_cache[0] >= offset) || ((off_t)m_structure_cache[(m_structure_cache_entries - 1)*2] < offset))
440         {
441                 if(update_structure_cache_entries(_offset))
442                 {
443                         return -1;
444                 }
445         }
446
447         int i = m_structure_cache_entries-1;
448         while ((off_t)m_structure_cache[i * 2] >= offset)
449         {
450                 if (i <= 0)
451                 {
452                         eDebug("structure data consistency fail!, we are looking for %llu, but last entry is %llu", offset, m_structure_cache[i * 2]);
453                         return -1;
454                 }
455                 --i;
456         }
457         if (i == m_structure_cache_entries-1)
458         {
459                 eDebug("structure data (first entry) consistency fail!");
460                 return -1;
461         }
462
463 //      eDebug("[%d] looked for %llu, found data %llu=%llx",sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]);
464         offset = m_structure_cache[i * 2];
465         data = m_structure_cache[i * 2 + 1];
466         return 0;
467 }
468
469 int eMPEGStreamInformation::update_structure_cache_entries(off_t offset)
470 {
471         const int struture_cache_size = sizeof(m_structure_cache) / 16;
472         fseek(m_structure_read, 0, SEEK_END);
473         int l = ftell(m_structure_read);
474         unsigned long long d[2];
475         const int entry_size = sizeof d;
476
477                 /* do a binary search */
478         int count = l / entry_size;
479         int i = 0;
480
481         while (count)
482         {
483                 int step = count >> 1;
484                 fseek(m_structure_read, (i + step) * entry_size, SEEK_SET);
485                 if (!fread(d, 1, entry_size, m_structure_read))
486                 {
487                         eDebug("read error at entry %d", i);
488                         return -1;
489                 }
490 #if BYTE_ORDER != BIG_ENDIAN
491                 d[0] = bswap_64(d[0]);
492                 d[1] = bswap_64(d[1]);
493 #endif
494 //              eDebug("%d: %08llx > %llx", i, d[0], d[1]);
495                 if (d[0] < (unsigned long long)offset)
496                 {
497                         i += step + 1;
498                         count -= step + 1;
499                 } else
500                         count = step;
501         }
502         eDebug("found %d", i);
503
504         /* put that in the middle */
505         i -= struture_cache_size / 2;
506         if (i < 0)
507                 i = 0;
508         eDebug("cache starts at %d", i);
509         fseek(m_structure_read, i * entry_size, SEEK_SET);
510         int num = fread(m_structure_cache, entry_size, struture_cache_size, m_structure_read);
511         eDebug("%d entries", num);
512         for (i = 0; i < struture_cache_size; ++i)
513         {
514                 if (i < num)
515                 {
516 #if BYTE_ORDER != BIG_ENDIAN
517                         m_structure_cache[i * 2] = bswap_64(m_structure_cache[i * 2]);
518                         m_structure_cache[i * 2 + 1] = bswap_64(m_structure_cache[i * 2 + 1]);
519 #endif
520                 } else
521                 {
522                         m_structure_cache[i * 2] = 0x7fffffffffffffffULL; /* fill with harmless content */
523                         m_structure_cache[i * 2 + 1] = 0x7fffffffffffffffULL;
524                 }
525         }
526         m_structure_cache_entries = num;
527         return 0;
528 }
529
530 eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo):
531         m_streaminfo(streaminfo),
532         m_pktptr(0),
533         m_pid(-1),
534         m_need_next_packet(0),
535         m_skip(0),
536         m_last_pts_valid(0),
537         m_enable_accesspoints(true)
538 {
539 }
540
541 int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
542 {
543         if (!wantPacket(pkt))
544                 eWarning("something's wrong.");
545
546         const unsigned char *end = pkt + 188, *begin = pkt;
547         
548         int pusi = !!(pkt[1] & 0x40);
549         
550         if (!(pkt[3] & 0x10)) /* no payload? */
551                 return 0;
552
553         if (pkt[3] & 0xc0)
554         {
555                 /* scrambled stream, we cannot parse pts */
556                 return 0;
557         }
558
559         if (pkt[3] & 0x20) // adaptation field present?
560                 pkt += pkt[4] + 4 + 1;  /* skip adaptation field and header */
561         else
562                 pkt += 4; /* skip header */
563
564         if (pkt > end)
565         {
566                 eWarning("[TSPARSE] dropping huge adaption field");
567                 return 0;
568         }
569
570         pts_t pts = 0;
571         int ptsvalid = 0;
572         
573         if (pusi)
574         {
575                         // ok, we now have the start of the payload, aligned with the PES packet start.
576                 if (pkt[0] || pkt[1] || (pkt[2] != 1))
577                 {
578                         eWarning("broken startcode");
579                         return 0;
580                 }
581
582                 if (pkt[7] & 0x80) // PTS present?
583                 {
584                         pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
585                         pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
586                         pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
587                         pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
588                         pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
589                         ptsvalid = 1;
590                         
591                         m_last_pts = pts;
592                         m_last_pts_valid = 1;
593
594         #if 0           
595                         int sec = pts / 90000;
596                         int frm = pts % 90000;
597                         int min = sec / 60;
598                         sec %= 60;
599                         int hr = min / 60;
600                         min %= 60;
601                         int d = hr / 24;
602                         hr %= 24;
603                         
604                         eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
605         #endif
606                 }
607                 
608                         /* advance to payload */
609                 pkt += pkt[8] + 9;
610         }
611
612         while (pkt < (end-4))
613         {
614                 int pkt_offset = pkt - begin;
615                 if (!(pkt[0] || pkt[1] || (pkt[2] != 1)))
616                 {
617 //                      eDebug("SC %02x %02x %02x %02x, %02x", pkt[0], pkt[1], pkt[2], pkt[3], pkt[4]);
618                         int sc = pkt[3];
619                         
620                         if (m_streamtype == 0) /* mpeg2 */
621                         {
622                                 if ((sc == 0x00) || (sc == 0xb3) || (sc == 0xb8)) /* picture, sequence, group start code */
623                                 {
624                                         unsigned long long data = sc | (pkt[4] << 8) | (pkt[5] << 16) | (pkt[6] << 24);
625                                         m_streaminfo.writeStructureEntry(offset + pkt_offset, data  & 0xFFFFFFFFULL);
626                                 }
627                                 if (m_enable_accesspoints)
628                                 {
629                                         if (pkt[3] == 0xb3) /* sequence header */
630                                         {
631                                                 if (ptsvalid)
632                                                 {
633                                                         m_streaminfo.m_access_points[offset] = pts;
634                 //                                      eDebug("Sequence header at %llx, pts %llx", offset, pts);
635                                                 } else
636                                                         /*eDebug("Sequence header but no valid PTS value.")*/;
637                                         }
638                                 }
639                         }
640
641                         if (m_streamtype == 1) /* H.264 */
642                         {
643                                 if (sc == 0x09)
644                                 {
645                                                 /* store image type */
646                                         unsigned long long data = sc | (pkt[4] << 8);
647                                         m_streaminfo.writeStructureEntry(offset + pkt_offset, data);
648                                 }
649                                 if (m_enable_accesspoints)
650                                 {
651                                         if (pkt[3] == 0x09 &&   /* MPEG4 AVC NAL unit access delimiter */
652                                                  (pkt[4] >> 5) == 0) /* and I-frame */
653                                         {
654                                                 if (ptsvalid)
655                                                 {
656                                                         m_streaminfo.m_access_points[offset] = pts;
657                 //                              eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts);
658                                                 } else
659                                                         /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/;
660                                         }
661                                 }
662                         }
663                         if (m_streamtype == 6) /* H.265 */
664                         {
665                                 int nal_unit_type = (sc >> 1);
666                                 if (nal_unit_type == 35) /* H265 NAL unit access delimiter */
667                                 {
668                                         unsigned long long data = sc | (pkt[5] << 8);
669                                         m_streaminfo.writeStructureEntry(offset + pkt_offset, data);
670
671                                         if (m_enable_accesspoints)
672                                         {
673                                                 if ((pkt[5] >> 5) == 0) /* check pic_type for I-frame */
674                                                 {
675                                                         if (ptsvalid)
676                                                         {
677                                                                 m_streaminfo.m_access_points[offset] = pts;
678                                                         }
679                                                 }
680                                         }
681                                 }
682                         }
683                 }
684                 ++pkt;
685         }
686         return 0;
687 }
688
689 inline int eMPEGStreamParserTS::wantPacket(const unsigned char *hdr) const
690 {
691         if (hdr[0] != 0x47)
692         {
693                 eDebug("missing sync!");
694                 return 0;
695         }
696         int ppid = ((hdr[1]&0x1F) << 8) | hdr[2];
697
698         if (ppid != m_pid)
699                 return 0;
700                 
701         if (m_need_next_packet)  /* next packet (on this pid) was required? */
702                 return 1;
703         
704         if (hdr[1] & 0x40)       /* pusi set: yes. */
705                 return 1;
706
707         return m_streamtype == 0; /* we need all packets for MPEG2, but only PUSI packets for H.264 */
708 }
709
710 void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int len)
711 {
712         const unsigned char *packet = (const unsigned char*)data;
713         const unsigned char *packet_start = packet;
714         
715                         /* sorry for the redundant code here, but there are too many special cases... */
716         while (len)
717         {
718                         /* emergency resync. usually, this should not happen, because the data should 
719                            be sync-aligned.
720                            
721                            to make this code work for non-strictly-sync-aligned data, (for example, bad 
722                            files) we fix a possible resync here by skipping data until the next 0x47.
723                            
724                            if this is a false 0x47, the packet will be dropped by wantPacket, and the
725                            next time, sync will be re-established. */
726                 int skipped = 0;
727                 while (!m_pktptr && len)
728                 {
729                         if (packet[0] == 0x47)
730                                 break;
731                         len--;
732                         packet++;
733                         skipped++;
734                 }
735                 
736                 if (skipped)
737                         eDebug("SYNC LOST: skipped %d bytes.", skipped);
738                 
739                 if (!len)
740                         break;
741                 
742                 if (m_pktptr)
743                 {
744                                 /* skip last packet */
745                         if (m_pktptr < 0)
746                         {
747                                 unsigned int skiplen = -m_pktptr;
748                                 if (skiplen > len)
749                                         skiplen = len;
750                                 packet += skiplen;
751                                 len -= skiplen;
752                                 m_pktptr += skiplen;
753                                 continue;
754                         } else if (m_pktptr < 4) /* header not complete, thus we don't know if we want this packet */
755                         {
756                                 unsigned int storelen = 4 - m_pktptr;
757                                 if (storelen > len)
758                                         storelen = len;
759                                 memcpy(m_pkt + m_pktptr, packet,  storelen);
760                                 
761                                 m_pktptr += storelen;
762                                 len -= storelen;
763                                 packet += storelen;
764                                 
765                                 if (m_pktptr == 4)
766                                         if (!wantPacket(m_pkt))
767                                         {
768                                                         /* skip packet */
769                                                 packet += 184;
770                                                 len -= 184;
771                                                 m_pktptr = 0;
772                                                 continue;
773                                         }
774                         }
775                                 /* otherwise we complete up to the full packet */
776                         unsigned int storelen = 188 - m_pktptr;
777                         if (storelen > len)
778                                 storelen = len;
779                         memcpy(m_pkt + m_pktptr, packet,  storelen);
780                         m_pktptr += storelen;
781                         len -= storelen;
782                         packet += storelen;
783                         
784                         if (m_pktptr == 188)
785                         {
786                                 m_need_next_packet = processPacket(m_pkt, offset + (packet - packet_start));
787                                 m_pktptr = 0;
788                         }
789                 } else if (len >= 4)  /* if we have a full header... */
790                 {
791                         if (wantPacket(packet))  /* decide wheter we need it ... */
792                         {
793                                 if (len >= 188)          /* packet complete? */
794                                 {
795                                         m_need_next_packet = processPacket(packet, offset + (packet - packet_start)); /* process it now. */
796                                 } else
797                                 {
798                                         memcpy(m_pkt, packet, len);  /* otherwise queue it up */
799                                         m_pktptr = len;
800                                 }
801                         }
802
803                                 /* skip packet */
804                         int sk = len;
805                         if (sk >= 188)
806                                 sk = 188;
807                         else if (!m_pktptr) /* we dont want this packet, otherwise m_pktptr = sk (=len) > 4 */
808                                 m_pktptr = sk - 188;
809
810                         len -= sk;
811                         packet += sk;
812                 } else             /* if we don't have a complete header */
813                 {
814                         memcpy(m_pkt, packet, len);   /* complete header next time */
815                         m_pktptr = len;
816                         packet += len;
817                         len = 0;
818                 }
819         }
820 }
821
822 void eMPEGStreamParserTS::setPid(int _pid, int type)
823 {
824         m_pktptr = 0;
825         m_pid = _pid;
826         m_streamtype = type;
827 }
828
829 int eMPEGStreamParserTS::getLastPTS(pts_t &last_pts)
830 {
831         if (!m_last_pts_valid)
832         {
833                 last_pts = 0;
834                 return -1;
835         }
836         last_pts = m_last_pts;
837         return 0;
838 }
839