87fbfa39c345477e3e5f9e14253ed225b8343bf0
[openblackhole/openblackhole-enigma2.git] / lib / dvb / tstools.cpp
1 #include <lib/dvb/tstools.h>
2 #include <lib/dvb/specs.h>
3 #include <lib/base/eerror.h>
4 #include <lib/base/cachedtssource.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7
8 #include <stdio.h>
9
10 static const int m_maxrange = 256*1024;
11
12 DEFINE_REF(eTSFileSectionReader);
13
14 eTSFileSectionReader::eTSFileSectionReader(eMainloop *context)
15 {
16         sectionSize = 0;
17 }
18
19 eTSFileSectionReader::~eTSFileSectionReader()
20 {
21 }
22
23 void eTSFileSectionReader::data(unsigned char *packet, unsigned int size)
24 {
25         if (sectionSize + size <= sizeof(sectionData))
26         {
27                 memcpy(&sectionData[sectionSize], packet, size);
28                 sectionSize += size;
29         }
30         if (sectionSize >= (unsigned int)(3 + ((sectionData[1] & 0x0f) << 8) + sectionData[2]))
31         {
32                 sectionSize = 0;
33                 read(sectionData);
34         }
35 }
36
37 RESULT eTSFileSectionReader::start(const eDVBSectionFilterMask &mask)
38 {
39         sectionSize = 0;
40         return 0;
41 }
42
43 RESULT eTSFileSectionReader::stop()
44 {
45         sectionSize = 0;
46         return 0;
47 }
48
49 RESULT eTSFileSectionReader::connectRead(const Slot1<void,const uint8_t*> &r, ePtr<eConnection> &conn)
50 {
51         conn = new eConnection(this, read.connect(r));
52         return 0;
53 }
54
55 eDVBTSTools::eDVBTSTools():
56         m_pid(-1),
57         m_begin_valid (0),
58         m_end_valid(0),
59         m_samples_taken(0),
60         m_last_filelength(0),
61         m_futile(0)
62 {
63 }
64
65 void eDVBTSTools::closeSource()
66 {
67         m_source = NULL;
68 }
69
70 eDVBTSTools::~eDVBTSTools()
71 {
72         closeSource();
73 }
74
75 int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
76 {
77         eRawFile *f = new eRawFile();
78         ePtr<iTsSource> src = f;
79
80         if (f->open(filename) < 0)
81                 return -1;
82
83         src = new eCachedSource(src);
84
85         setSource(src, nostreaminfo ? NULL : filename);
86
87         return 0;
88 }
89
90 void eDVBTSTools::setSource(ePtr<iTsSource> &source, const char *stream_info_filename)
91 {
92         closeSource();
93         m_source = source;
94         if (stream_info_filename)
95         {
96                 eDebug("[eDVBTSTools] setSource loading streaminfo for %s", stream_info_filename);
97                 m_streaminfo.load(stream_info_filename);
98         }
99         m_samples_taken = 0;
100 }
101
102         /* getPTS extracts a pts value from any PID at a given offset. */
103 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
104 {
105         if (m_streaminfo.getPTS(offset, pts) == 0)
106                 return 0; // Okay, the cache had it
107
108         if (m_streaminfo.hasStructure())
109         {
110                 off_t local_offset = offset;
111                 unsigned long long data;
112                 if (m_streaminfo.getStructureEntryFirst(local_offset, data) == 0)
113                 {
114                         for(int retries = 8; retries != 0; --retries)
115                         {
116                                 if ((data & 0x1000000) != 0)
117                                 {
118                                         pts = data >> 31;
119                                         if (pts == 0)
120                                         {
121                                                 // obsolete data that happens to have a '1' there
122                                                 continue;
123                                         }
124                                         eDebug("[eDVBTSTools] getPTS got it from sc file offset=%llu pts=%llu", local_offset, pts);
125                                         if (fixed && fixupPTS(local_offset, pts))
126                                         {
127                                                 eDebug("[eDVBTSTools]    But failed to fixup!");
128                                                 break;
129                                         }
130                                         offset = local_offset;
131                                         return 0;
132                                 }
133                                 else
134                                 {
135                                         eDebug("[eDVBTSTools] getPTS No PTS, try next");
136                                 }
137                                 if (m_streaminfo.getStructureEntryNext(local_offset, data, 1) != 0)
138                                 {
139                                         eDebug("[eDVBTSTools] getPTS Cannot find next structure entry");
140                                         break;
141                                 }
142                         }
143                 }
144         }
145         if (!m_source || !m_source->valid())
146                 return -1;
147
148         offset -= offset % 188;
149
150         int left = m_maxrange;
151         int resync_failed_counter = 64;
152
153         while (left >= 188)
154         {
155                 unsigned char packet[188];
156                 if (m_source->read(offset, packet, 188) != 188)
157                 {
158                         eDebug("[eDVBTSTools] getPTS read error");
159                         return -1;
160                 }
161                 left -= 188;
162                 offset += 188;
163
164                 if (packet[0] != 0x47)
165                 {
166                         const unsigned char* match = (const unsigned char*)memchr(packet+1, 0x47, 188-1);
167                         if (match != NULL)
168                         {
169                                 eDebug("[eDVBTSTools] getPTS resync %d", match - packet);
170                                 offset += (match - packet) - 188;
171                         }
172                         else
173                         {
174                                 eDebug("[eDVBTSTools] getPTS resync failed");
175                                 if (resync_failed_counter == 0)
176                                 {
177                                         eDebug("[eDVBTSTools] getPTS Too many resync failures, probably not a valid stream");
178                                         return -1;
179                                 }
180                                 --resync_failed_counter;
181                         }
182                         continue;
183                 }
184
185                 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
186                 int pusi = !!(packet[1] & 0x40);
187
188 //              printf("PID %04x, PUSI %d\n", pid, pusi);
189
190                 unsigned char *payload;
191
192                         /* check for adaption field */
193                 if (packet[3] & 0x20)
194                 {
195                         if (packet[4] >= 183)
196                                 continue;
197                         if (packet[4])
198                         {
199                                 if (packet[5] & 0x10) /* PCR present */
200                                 {
201                                         pts  = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
202                                         pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
203                                         pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
204                                         pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
205                                         pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
206                                         offset -= 188;
207                                         eDebug("[eDVBTSTools] getPTS PCR %16llx found at %lld pid %02x (%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x)", pts, offset, pid, packet[0], packet[1], packet[2], packet[3], packet[4], packet[5], packet[6], packet[7], packet[8], packet[9], packet[10]);
208                                         if (fixed && fixupPTS(offset, pts))
209                                                 return -1;
210                                         return 0;
211                                 }
212                         }
213                         payload = packet + packet[4] + 4 + 1;
214                 } else
215                         payload = packet + 4;
216
217 /*              if (m_pid >= 0)
218                         if (pid != m_pid)
219                                 continue; */
220                 if (!pusi)
221                         continue;
222
223                         /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
224                 if (payload[0] || payload[1] || (payload[2] != 1))
225                         continue;
226
227                 if (payload[3] == 0xFD)
228                 { // stream use extension mechanism defined in ISO 13818-1 Amendment 2
229                         if (payload[7] & 1) // PES extension flag
230                         {
231                                 int offs = 0;
232                                 if (payload[7] & 0x80) // pts avail
233                                         offs += 5;
234                                 if (payload[7] & 0x40) // dts avail
235                                         offs += 5;
236                                 if (payload[7] & 0x20) // escr avail
237                                         offs += 6;
238                                 if (payload[7] & 0x10) // es rate
239                                         offs += 3;
240                                 if (payload[7] & 0x8) // dsm trickmode
241                                         offs += 1;
242                                 if (payload[7] & 0x4) // additional copy info
243                                         offs += 1;
244                                 if (payload[7] & 0x2) // crc
245                                         offs += 2;
246                                 if (payload[8] < offs)
247                                         continue;
248                                 uint8_t pef = payload[9+offs++]; // pes extension field
249                                 if (pef & 1) // pes extension flag 2
250                                 {
251                                         if (pef & 0x80) // private data flag
252                                                 offs += 16;
253                                         if (pef & 0x40) // pack header field flag
254                                                 offs += 1;
255                                         if (pef & 0x20) // program packet sequence counter flag
256                                                 offs += 2;
257                                         if (pef & 0x10) // P-STD buffer flag
258                                                 offs += 2;
259                                         if (payload[8] < offs)
260                                                 continue;
261                                         uint8_t stream_id_extension_len = payload[9+offs++] & 0x7F;
262                                         if (stream_id_extension_len >= 1)
263                                         {
264                                                 if (payload[8] < (offs + stream_id_extension_len) )
265                                                         continue;
266                                                 if (payload[9+offs] & 0x80) // stream_id_extension_bit (should not set)
267                                                         continue;
268                                                 switch (payload[9+offs])
269                                                 {
270                                                 case 0x55 ... 0x5f: // VC-1
271                                                         break;
272                                                 case 0x71: // AC3 / DTS
273                                                         break;
274                                                 case 0x72: // DTS - HD
275                                                         break;
276                                                 default:
277                                                         eDebug("[eDVBTSTools] getPTS skip unknown stream_id_extension %02x\n", payload[9+offs]);
278                                                         continue;
279                                                 }
280                                         }
281                                         else
282                                                 continue;
283                                 }
284                                 else
285                                         continue;
286                         }
287                         else
288                                 continue;
289                 }
290                         /* drop non-audio, non-video packets because other streams
291                            can be non-compliant.*/
292                 else if (((payload[3] & 0xE0) != 0xC0) &&  // audio
293                         ((payload[3] & 0xF0) != 0xE0)) // video
294                         continue;
295
296                 if (payload[7] & 0x80) /* PTS */
297                 {
298                         pts  = ((unsigned long long)(payload[ 9]&0xE))  << 29;
299                         pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
300                         pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
301                         pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
302                         pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
303                         offset -= 188;
304
305                         eDebug("[eDVBTSTools] getPTS PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
306
307                                 /* convert to zero-based */
308                         if (fixed && fixupPTS(offset, pts))
309                                 return -1;
310                         return 0;
311                 }
312         }
313
314         return -1;
315 }
316
317 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
318 {
319         if (m_streaminfo.fixupPTS(offset, now) == 0)
320         {
321                 return 0;
322         }
323         else
324         {
325                         /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
326                 calcBegin();
327                 if (!m_begin_valid)
328                 {
329                         eDebug("[eDVBTSTools] fixupPTS begin not valid, can't fixup");
330                         return -1;
331                 }
332
333                 pts_t pos = m_pts_begin;
334                 if ((now < pos) && ((pos - now) < 90000 * 10))
335                 {
336                         pos = 0;
337                         return 0;
338                 }
339
340                 if (now < pos) /* wrap around */
341                         now = now + 0x200000000LL - pos;
342                 else
343                         now -= pos;
344                 return 0;
345         }
346         eDebug("[eDVBTSTools] fixupPTS failed!");
347         return -1;
348 }
349
350 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
351 {
352         if (m_streaminfo.hasAccessPoints())
353         {
354                 if ((pts >= m_pts_end) && (marg > 0) && m_end_valid)
355                         offset = m_offset_end;
356                 else
357                         offset = m_streaminfo.getAccessPoint(pts, marg);
358                 return 0;
359         }
360         else
361         {
362                 calcBeginAndEnd();
363                 if (!m_begin_valid)
364                         return -1;
365                 if (!m_end_valid)
366                         return -1;
367
368                 if (!m_samples_taken)
369                         takeSamples();
370
371                 if (!m_samples.empty())
372                 {
373                         int maxtries = 5;
374                         pts_t p = -1;
375
376                         while (maxtries--)
377                         {
378                                         /* search entry before and after */
379                                 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
380                                 std::map<pts_t, off_t>::const_iterator u = l;
381
382                                 if (l != m_samples.begin())
383                                         --l;
384
385                                         /* we could have seeked beyond the end */
386                                 if (u == m_samples.end())
387                                 {
388                                                 /* use last segment for interpolation. */
389                                         if (l != m_samples.begin())
390                                         {
391                                                 --u;
392                                                 --l;
393                                         }
394                                 }
395
396                                         /* if we don't have enough points */
397                                 if (u == m_samples.end())
398                                         break;
399
400                                 pts_t pts_diff = u->first - l->first;
401                                 off_t offset_diff = u->second - l->second;
402
403                                 if (offset_diff < 0)
404                                 {
405                                         eDebug("[eDVBTSTools] getOffset something went wrong when taking samples.");
406                                         m_samples.clear();
407                                         takeSamples();
408                                         continue;
409                                 }
410
411                                 eDebug("[eDVBTSTools] getOffset using: %llu:%llu -> %llu:%llu", l->first, u->first, l->second, u->second);
412
413                                 int bitrate;
414
415                                 if (pts_diff)
416                                         bitrate = offset_diff * 90000 * 8 / pts_diff;
417                                 else
418                                         bitrate = 0;
419
420                                 offset = l->second;
421                                 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
422                                 offset -= offset % 188;
423                                 if (offset > m_offset_end)
424                                 {
425                                         /*
426                                          * NOTE: the bitrate calculation can be way off, especially when the pts difference is small.
427                                          * So the calculated offset might be far ahead of the end of the file.
428                                          * When that happens, avoid poisoning our sample list (m_samples) with an invalid value,
429                                          * which could eventually cause (timeshift) playback to be stopped.
430                                          * Because the file could be growing (timeshift), instead of returning the currently known end
431                                          * of file offset, we return an offset 1MB ahead of the end of the file.
432                                          * This allows jumping to the live point of the timeshift, for instance.
433                                          */
434                                         offset = m_offset_end + 1024 * 1024;
435                                         return 0;
436                                 }
437
438                                 p = pts;
439
440                                 if (!takeSample(offset, p))
441                                 {
442                                         int diff = (p - pts) / 90;
443
444                                         eDebug("[eDVBTSTools] getOffset calculated diff %d ms", diff);
445                                         if (abs(diff) > 300)
446                                         {
447                                                 eDebug("[eDVBTSTools] getOffset diff to big, refining");
448                                                 continue;
449                                         }
450                                 } else
451                                         eDebug("[eDVBTSTools] getOffset no sample taken, refinement not possible.");
452
453                                 break;
454                         }
455
456                                 /* if even the first sample couldn't be taken, fall back. */
457                                 /* otherwise, return most refined result. */
458                         if (p != -1)
459                         {
460                                 pts = p;
461                                 eDebug("[eDVBTSTools] getOffset aborting. Taking %llu as offset for %lld", offset, pts);
462                                 return 0;
463                         }
464                 }
465
466                 int bitrate = calcBitrate();
467                 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
468                 eDebug("[eDVBTSTools] getOffset fallback, bitrate=%d, results in %016llx", bitrate, offset);
469                 offset -= offset % 188;
470                 return 0;
471         }
472 }
473
474 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
475 {
476         return m_streaminfo.getNextAccessPoint(ts, start, direction);
477 }
478
479 void eDVBTSTools::calcBegin()
480 {
481         if (!m_source || !m_source->valid())
482                 return;
483
484         if (!(m_begin_valid || m_futile))
485         {
486                 // Just ask streaminfo
487                 if (m_streaminfo.getFirstFrame(m_offset_begin, m_pts_begin) == 0)
488                 {
489                         off_t begin = m_offset_begin;
490                         pts_t pts = m_pts_begin;
491                         if (m_streaminfo.fixupPTS(begin, pts) == 0)
492                         {
493                                 eDebug("[eDVBTSTools] calcBegin [@ML] m_streaminfo.getLastFrame returned %llu, %llu (%us), fixup to: %llu, %llu (%us)",
494                                        m_offset_begin, m_pts_begin, (unsigned int)(m_pts_begin/90000), begin, pts, (unsigned int)(pts/90000));
495                         }
496                         m_begin_valid = 1;
497                 }
498                 else
499                 {
500                         m_offset_begin = 0;
501                         if (!getPTS(m_offset_begin, m_pts_begin))
502                                 m_begin_valid = 1;
503                         else
504                                 m_futile = 1;
505                 }
506                 if (m_begin_valid)
507                 {
508                         /*
509                          * We've just calculated the begin position, which will have an effect on the
510                          * calculated length.
511                          * (when the end position had been determined before the begin position, the length
512                          * will be invalid)
513                          * So we force the end position to be (re-)calculated after the begin position has
514                          * been determined, in order to ensure m_pts_length will be corrected.
515                          */
516                          m_end_valid = 0;
517
518                 }
519         }
520 }
521
522 static pts_t pts_diff(pts_t low, pts_t high)
523 {
524         high -= low;
525         if (high < 0)
526                 high += 0x200000000LL;
527         return high;
528 }
529
530 void eDVBTSTools::calcEnd()
531 {
532         if (!m_source || !m_source->valid())
533                 return;
534
535         // If there's a structure file, the calculation is much smarter, so we can try more often
536         off_t threshold = m_streaminfo.hasStructure() ? 100*1024 : 1024*1024;
537
538         off_t end = m_source->length();
539         if (llabs(end - m_last_filelength) > threshold)
540         {
541                 m_last_filelength = end;
542                 m_end_valid = 0;
543                 m_futile = 0;
544 //              eDebug("[eDVBTSTools] calcEnd file size changed, recalc length");
545         }
546
547         int maxiter = 10;
548
549         if (!m_end_valid)
550         {
551                 off_t offset = m_offset_end = m_last_filelength;
552                 pts_t pts = m_pts_end;
553                 if (m_streaminfo.getLastFrame(offset, pts) == 0)
554                 {
555                         m_offset_end = offset;
556                         m_pts_length = m_pts_end = pts;
557                         end = m_offset_end;
558                         if (m_streaminfo.fixupPTS(end, m_pts_length) != 0)
559                         {
560                                 /* Not enough structure info, estimate */
561                                 m_pts_length = pts_diff(m_pts_begin, m_pts_end);
562                         }
563                         m_end_valid = 1;
564                 }
565                 else
566                 {
567                         eDebug("[eDVBTSTools] calcEnd [@ML] m_streaminfo.getLastFrame failed, fallback");
568                         while (!(m_end_valid || m_futile))
569                         {
570                                 if (!--maxiter)
571                                 {
572                                         m_futile = 1;
573                                         return;
574                                 }
575
576                                 m_offset_end -= m_maxrange;
577                                 if (m_offset_end < 0)
578                                         m_offset_end = 0;
579
580                                 offset = m_offset_end;
581                                 pts = m_pts_end;
582                                 if (!getPTS(offset, pts))
583                                 {
584                                         offset = m_offset_end;
585                                         m_pts_end = pts;
586                                         m_pts_length = pts_diff(m_pts_begin, m_pts_end);
587                                         m_end_valid = 1;
588                                 }
589
590                                 if (!m_offset_end)
591                                 {
592                                         m_futile = 1;
593                                         break;
594                                 }
595                         }
596                 }
597         }
598 }
599
600 void eDVBTSTools::calcBeginAndEnd()
601 {
602         calcBegin();
603         calcEnd();
604 }
605
606 int eDVBTSTools::calcLen(pts_t &len)
607 {
608         calcBeginAndEnd();
609         if (!(m_begin_valid && m_end_valid))
610                 return -1;
611         len = m_pts_length;
612         return 0;
613 }
614
615 int eDVBTSTools::calcBitrate()
616 {
617         pts_t len_in_pts;
618         if (calcLen(len_in_pts) != 0)
619                 return -1;
620         off_t len_in_bytes = m_offset_end - m_offset_begin;
621
622         if (!len_in_pts)
623                 return -1;
624
625         unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
626         if ((bitrate < 10000) || (bitrate > 100000000))
627                 return -1;
628
629         return bitrate;
630 }
631
632         /* pts, off */
633 void eDVBTSTools::takeSamples()
634 {
635         m_samples_taken = 1;
636         m_samples.clear();
637         int retries=2;
638
639         calcBeginAndEnd();
640         if (!(m_begin_valid && m_end_valid))
641                 return;
642
643         int nr_samples = 30;
644         off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
645         if (bytes_per_sample < 40*1024*1024)
646                 bytes_per_sample = 40*1024*1024;
647
648         bytes_per_sample -= bytes_per_sample % 188;
649
650         eDebug("[eDVBTSTools] takeSamples step %lld, pts begin %llu, pts end %llu, offs begin %lld, offs end %lld:",
651                 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
652
653         for (off_t offset = m_offset_begin; offset < m_offset_end;)
654         {
655                 pts_t p;
656                 if (takeSample(offset, p) && retries--)
657                         continue;
658                 retries = 2;
659                 offset += bytes_per_sample;
660         }
661         m_samples[0] = m_offset_begin;
662         m_samples[m_pts_end - m_pts_begin] = m_offset_end;
663 }
664
665         /* returns 0 when a sample was taken. */
666 int eDVBTSTools::takeSample(off_t off, pts_t &p)
667 {
668         off_t offset_org = off;
669
670         if (!eDVBTSTools::getPTS(off, p, 1))
671         {
672                         /* as we are happily mixing PTS and PCR values (no comment, please), we might
673                            end up with some "negative" segments.
674
675                            so check if this new sample is between the previous and the next field*/
676
677                 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
678                 std::map<pts_t, off_t>::const_iterator u = l;
679
680                 if (l != m_samples.begin())
681                 {
682                         --l;
683                         if (u != m_samples.end())
684                         {
685                                 if ((l->second > off) || (u->second < off))
686                                 {
687                                         eDebug("[eDVBTSTools] takeSample ignoring sample %lld %lld %lld (%llu %llu %llu)",
688                                                 l->second, off, u->second, l->first, p, u->first);
689                                         return 1;
690                                 }
691                         }
692                 }
693
694                 eDebug("[eDVBTSTools] takeSample adding sample %lld: pts %llu -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
695                 m_samples[p] = off;
696                 return 0;
697         }
698         return -1;
699 }
700
701 int eDVBTSTools::findPMT(eDVBPMTParser::program &program)
702 {
703         int pmtpid = -1;
704         ePtr<iDVBSectionReader> sectionreader;
705
706         eDVBPMTParser::clearProgramInfo(program);
707
708                 /* FIXME: this will be factored out soon! */
709         if (!m_source || !m_source->valid())
710         {
711                 eDebug("[eDVBTSTools] findPMT file not valid");
712                 return -1;
713         }
714
715         off_t position=0;
716         m_pmtready = false;
717
718         for (int attempts_left = (5*1024*1024)/188; attempts_left != 0; --attempts_left)
719         {
720                 unsigned char packet[188];
721                 int ret = m_source->read(position, packet, 188);
722                 if (ret != 188)
723                 {
724                         eDebug("[eDVBTSTools] findPMT read error");
725                         break;
726                 }
727                 position += 188;
728
729                 if (packet[0] != 0x47)
730                 {
731                         int i = 0;
732                         while (i < 188)
733                         {
734                                 if (packet[i] == 0x47)
735                                         break;
736                                 --position;
737                                 ++i;
738                         }
739                         continue;
740                 }
741
742                 if (pmtpid < 0 && !(packet[1] & 0x40)) /* pusi */
743                         continue;
744
745                         /* ok, now we have a PES header or section header*/
746                 unsigned char *sec;
747
748                         /* check for adaption field */
749                 if (packet[3] & 0x20)
750                 {
751                         if (packet[4] >= 183)
752                                 continue;
753                         sec = packet + packet[4] + 4 + 1;
754                 } else
755                         sec = packet + 4;
756
757                 if (pmtpid < 0)
758                 {
759                         if (sec[0]) /* table pointer, assumed to be 0 */
760                                 continue;
761                         if (sec[1] == 0x02) /* program map section */
762                         {
763                                 pmtpid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
764                                 int sid = (sec[4] << 8) | sec[5];
765                                 sectionreader = new eTSFileSectionReader(eApp);
766                                 m_PMT.begin(eApp, eDVBPMTSpec(pmtpid, sid), sectionreader);
767                                 ((eTSFileSectionReader*)(iDVBSectionReader*)sectionreader)->data(&sec[1], 188 - (sec + 1 - packet));
768                         }
769                 }
770                 else if (pmtpid == (((packet[1] << 8) | packet[2]) & 0x1FFF))
771                 {
772                         ((eTSFileSectionReader*)(iDVBSectionReader*)sectionreader)->data(sec, 188 - (sec - packet));
773                 }
774                 if (m_pmtready)
775                 {
776                         program = m_program;
777                         return 0;
778                 }
779         }
780         m_PMT.stop();
781         return -1;
782 }
783
784 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
785 {
786 //      eDebug("[eDVBTSTools] findFrame trying to find iFrame at %llu", offset);
787         if (!m_streaminfo.hasStructure())
788         {
789 //              eDebug("[eDVBTSTools] findFrame can't get next iframe without streaminfo");
790                 return -1;
791         }
792
793         off_t offset = _offset;
794         int nr_frames = 0;
795         bool is_mpeg2 = false;
796
797                 /* let's find the iframe before the given offset */
798         if (direction < 0)
799                 offset--;
800
801         unsigned long long longdata;
802         if (m_streaminfo.getStructureEntryFirst(offset, longdata) != 0)
803         {
804                 eDebug("[eDVBTSTools] findFramee getStructureEntryFirst failed");
805                 return -1;
806         }
807         if (direction == 0)
808         {
809                 // Special case, move an extra frame ahead
810                 if (m_streaminfo.getStructureEntryNext(offset, longdata, 1) != 0)
811                         return -1;
812                 direction = 1;
813         }
814         while (1)
815         {
816                 unsigned int data = (unsigned int)longdata; // only the lower bits are interesting
817                         /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
818                         /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
819                         /* TODO: check frame_types */
820                 // is_frame
821                 if (((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00)) /* H.264 UAD or MPEG2 start code */
822                 {
823                         ++nr_frames;
824                         if ((data & 0xE0FF) == 0x0009)          /* H.264 NAL unit access delimiter with I-frame*/
825                         {
826                                 break;
827                         }
828                         if ((data & 0x3800FF) == 0x080000)      /* MPEG2 picture start code with I-frame */
829                         {
830                                 is_mpeg2 = true;
831                                 break;
832                         }
833                 }
834                 if (m_streaminfo.getStructureEntryNext(offset, longdata, direction) != 0)
835                         return -1;
836         }
837         off_t start = offset;
838
839         /* let's find the next frame after the given offset */
840         unsigned int data;
841         do
842         {
843                 if (m_streaminfo.getStructureEntryNext(offset, longdata, 1))
844                 {
845                         eDebug("[eDVBTSTools] findFrame get next failed");
846                         return -1;
847                 }
848                 data = ((unsigned int)longdata) & 0xFF;
849         }
850         while ((data != 0x09) && (data != 0x00)); /* next frame */
851
852         if (is_mpeg2)
853         {
854                 // Seek back to sequence start (appears to be needed for e.g. a few TCM streams)
855                 while (nr_frames)
856                 {
857                         if (m_streaminfo.getStructureEntryNext(start, longdata, -1))
858                         {
859                                 eDebug("[eDVBTSTools] findFrame Failed to find MPEG2 start frame");
860                                 break;
861                         }
862                         if ((((unsigned int)longdata) & 0xFF) == 0xB3) /* sequence start or previous frame */
863                                 break;
864                         --nr_frames;
865                 }
866         }
867
868         /* make sure we've ended up in the right direction, ignore the result if we didn't */
869         if ((direction >= 0 && start < _offset) || (direction < 0 && start > _offset)) return -1;
870
871         len = offset - start;
872         _offset = start;
873         if (direction < 0)
874                 direction = -nr_frames;
875         else
876                 direction = nr_frames;
877 //      eDebug("[eDVBTSTools] findFrame result: offset=%llu, len: %ld", offset, (int)len);
878         return 0;
879 }
880
881 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
882 {
883         int nr_frames, direction;
884 //      eDebug("[eDVBTSTools] findNextPicture trying to move %d frames at %llu", distance, offset);
885
886         frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
887
888         off_t new_offset = offset;
889         size_t new_len = len;
890         int first = 1;
891
892         if (distance > 0) {
893                 direction = 0;
894                 nr_frames = 0;
895         } else {
896                 direction = -1;
897                 nr_frames = -1;
898                 distance = -distance+1;
899         }
900         while (distance > 0)
901         {
902                 int dir = direction;
903                 if (findFrame(new_offset, new_len, dir, frame_types))
904                 {
905 //                      eDebug("[eDVBTSTools] findNextPicture findFrame failed!\n");
906                         return -1;
907                 }
908
909                 distance -= abs(dir);
910
911 //              eDebug("[eDVBTSTools] findNextPicture we moved %d, %d to go frames (now at %llu)", dir, distance, new_offset);
912
913                 if (distance >= 0 || direction == 0)
914                 {
915                         first = 0;
916                         offset = new_offset;
917                         len = new_len;
918                         nr_frames += abs(dir);
919                 }
920                 else if (first)
921                 {
922                         first = 0;
923                         offset = new_offset;
924                         len = new_len;
925                         nr_frames += abs(dir) + distance; // never jump forward during rewind
926                 }
927         }
928
929         distance = (direction < 0) ? -nr_frames : nr_frames;
930 //      eDebug("[eDVBTSTools] findNextPicture in total, we moved %d frames", nr_frames);
931
932         return 0;
933 }
934
935 void eDVBTSTools::PMTready(int error)
936 {
937         if (!error)
938         {
939                 if (getProgramInfo(m_program) >= 0)
940                 {
941                         m_PMT.stop();
942                         m_pmtready = true;
943                 }
944         }
945 }