]> git.vomp.tv Git - vompclient-marten.git/blob - demuxerts.cc
Add input buffer for ffmpeg, fix broken decoding
[vompclient-marten.git] / demuxerts.cc
1 /*\r
2     Copyright 2006-2008 Mark Calderbank\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
18     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 #include "demuxerts.h"\r
22 #include "log.h"\r
23 #include "video.h"\r
24 #include "vdr.h"\r
25 \r
26 #define PTS_JUMP_MARGIN   10000\r
27 #define PTS_ALLOWANCE 90000\r
28 \r
29 // TODO: PTS class to handle wrapping arithmetic & comparisons?\r
30 static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)\r
31 {\r
32   // Assume pts1, pts2 < 2^33; calculate shortest distance between\r
33   ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;\r
34   if (ret > (1LL<<32)) ret = (1LL<<33) - ret;\r
35   return ret;\r
36 }\r
37 \r
38 static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)\r
39 {\r
40   // Assume pts1, pts2 < 2^33; calculate pts1 - pts2\r
41   if (pts1 > pts2)\r
42     return pts1 - pts2;\r
43   else\r
44     return (1LL<<33) + pts1 - pts2;\r
45 }\r
46 \r
47 DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)\r
48 {\r
49   vID = p_vID; vActive = false;\r
50   aID = p_aID; aActive = false;\r
51   subID = p_subID; subActive = false;\r
52   atype = 0;\r
53   subLength = 0;\r
54   tID = p_tID;\r
55   havechannelinfo=false;\r
56   //doubledframerate=false;\r
57   framereserve=0;\r
58 }\r
59 \r
60 void DemuxerTS::flush()\r
61 {\r
62   partPacket = 0;\r
63   parsed = false;\r
64   havechannelinfo=false;\r
65   Demuxer::flush();\r
66   vPacket.init(PESTYPE_VID0);\r
67   switch (atype)\r
68   {\r
69   case 1:\r
70     aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
71     break;\r
72   default:\r
73   case 0:\r
74     aPacket.init(PESTYPE_AUD0);\r
75     break;\r
76   }\r
77   subPacket.init(PESTYPE_PRIVATE_1);\r
78 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
79 \r
80   vActive = false;\r
81   aActive = false;\r
82   subActive = false;\r
83   subLength = 0;\r
84   tActive = false;\r
85  // doubledframerate=false;\r
86   framereserve=0;\r
87 }\r
88 \r
89 int DemuxerTS::scan(UCHAR *buf, int len)\r
90 {\r
91   switch (atype)\r
92   {\r
93   case 1:\r
94     return PESTYPE_PRIVATE_1;\r
95   default:\r
96   case 0:\r
97     return PESTYPE_AUD0;\r
98   }\r
99 }\r
100 \r
101 void DemuxerTS::setVID(int p_vID)\r
102 {\r
103   vID = p_vID;\r
104   vPacket.init(PESTYPE_VID0);\r
105   vActive = false;\r
106 }\r
107 \r
108 void DemuxerTS::setAID(int p_aID, int type)\r
109 {\r
110   aID = p_aID;\r
111   atype = type;\r
112   switch (atype)\r
113   {\r
114   case 1:\r
115     aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
116     setAudioStream(PESTYPE_SUBSTREAM_AC30);\r
117     break;\r
118   default:\r
119   case 0:\r
120     aPacket.init(PESTYPE_AUD0);\r
121     setAudioStream(PESTYPE_AUD0);\r
122     break;\r
123   }\r
124   aActive = false;\r
125 }\r
126 \r
127 void DemuxerTS::setSubID(int p_subID)\r
128 {\r
129   subID = p_subID;\r
130   subPacket.init(PESTYPE_PRIVATE_1);\r
131   subActive = false;\r
132   subLength = 0;\r
133 }\r
134 \r
135 void DemuxerTS::setTID(int p_tID)\r
136 {\r
137   tID = p_tID;\r
138   tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
139   tActive = false;\r
140 \r
141 }\r
142 \r
143 \r
144 \r
145 \r
146 int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)\r
147 {\r
148   int scanaid=0;\r
149 \r
150   while (len >= TS_SIZE)\r
151   {\r
152       if (*buf != TS_SIG) {buf++;len--; continue;} \r
153 \r
154     //Pattern scanning won't work for ts\r
155 \r
156       \r
157       int datalen = TS_SIZE - 4;\r
158       int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
159       UCHAR payload = buf[1] & 0x40;\r
160       \r
161       if (buf[3] & 0x20) // Adaptation field is present\r
162           datalen -= (buf[4] + 1);\r
163 \r
164       UCHAR* curbuf =buf+ (TS_SIZE - datalen);\r
165      \r
166 \r
167       if (payload) {\r
168           if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
169               int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);\r
170               if ((pmtpid >> 13) != 0x07) \r
171               {\r
172                   Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));\r
173               } \r
174               else \r
175               {\r
176                   pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
177                   PMTPID = pmtpid;\r
178               }\r
179           \r
180           } else if (pid == PMTPID) { //PMT\r
181               int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);\r
182               //sectionlength += 4; //include header but subtract crc in the end...\r
183               int p = 13; //skip fixed part of pmt\r
184               while ( p < sectionlength) {\r
185                   int streamtype = *(curbuf+p);\r
186                   p++;\r
187                   int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);\r
188                   p += 2; //skip ES Pid\r
189                   int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);\r
190                   p += 2; //skip ES length\r
191                   if ((foundpid >> 13) != 0x07)\r
192                   {\r
193                       Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
194                   }\r
195                   else \r
196                   {\r
197                       foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
198                       //int pos=0; UNUSED?\r
199                       if (streamtype==3 || streamtype ==4) {\r
200                           scanaid=foundpid;\r
201                       }\r
202                   }\r
203                   p += eslength; //skip es descriptor\r
204               }\r
205           } else if (pid == scanaid) {     \r
206            //   UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5];  UNUSED?\r
207               \r
208               if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present\r
209               {\r
210                   *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) |\r
211                   ( (ULLONG)(curbuf[10])        << 22 ) |\r
212                   ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) |\r
213                   ( (ULLONG)(curbuf[12])        <<  7 ) |\r
214                   ( (ULLONG)(curbuf[13] & 0xFE) >>  1 );\r
215                   return 1;\r
216               }\r
217           }\r
218       }\r
219       len-=TS_SIZE;\r
220       buf+=TS_SIZE;\r
221   }\r
222   // No PTS found.\r
223   return 0;\r
224 }\r
225 \r
226 void DemuxerTS::setFrameNum(ULONG frame)\r
227 {\r
228   frameCounting = true;\r
229   frameNumber = frame;\r
230   framereserve=0;\r
231   Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame);\r
232 }\r
233 \r
234 void DemuxerTS::setPacketNum(ULONG npacket)\r
235 {\r
236   packetCounting = true;\r
237   packetNumber = npacket;\r
238   Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket);\r
239 }\r
240 \r
241 int DemuxerTS::put(UCHAR* buf, int len)\r
242 {\r
243   int ret = 0;    // return number of bytes consumed\r
244 \r
245   bool misaligned_mess=false;\r
246   while (partPacket)\r
247   {\r
248     if (len >= TS_SIZE + 1 - partPacket)\r
249     { // Remainder of partial packet is available, plus one\r
250       memcpy(store+partPacket, buf, TS_SIZE - partPacket);\r
251       ret += TS_SIZE - partPacket;\r
252       buf += TS_SIZE - partPacket;\r
253       len -= TS_SIZE - partPacket;\r
254       partPacket = TS_SIZE;\r
255       if (*buf == TS_SIG)\r
256       { // Packet is properly terminated\r
257         int rc = processTS(store);\r
258         if (rc)\r
259           partPacket = 0; // Successfully processed\r
260         else\r
261           return ret;     // Try again later.\r
262       }\r
263       else\r
264       { // Packet not terminated. Find another candidate, and shift store\r
265         if (!misaligned_mess) {\r
266                 Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!A");\r
267                 misaligned_mess=true; // do not alarm more than once\r
268         }\r
269         int search = 1;\r
270         while (search < partPacket && store[search] != TS_SIG)\r
271           search++;\r
272         partPacket -= search;\r
273         if (partPacket) memcpy(store, store+search, partPacket);\r
274       }\r
275     }\r
276     else\r
277     { // Still don't have complete packet. Consume what we do have.\r
278       memcpy(store+partPacket, buf, len);\r
279       partPacket += len;\r
280       ret += len;\r
281       return ret;\r
282     }\r
283   }\r
284 \r
285   // Position ourselves at a candidate TS packet\r
286   while (len > 0 && *buf != TS_SIG)\r
287   {\r
288           if (!misaligned_mess) {\r
289                   Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!B");\r
290               misaligned_mess=true; // do not alarm more than once\r
291            }\r
292     buf++; ret++; len--;\r
293   }\r
294 \r
295   while (len)\r
296   {\r
297     if (len < TS_SIZE + 1)\r
298     { // Not enough data. Store what we have.\r
299       memcpy(store, buf, len);\r
300       partPacket = len;\r
301       ret += len;\r
302       return ret;\r
303     }\r
304 \r
305     if (buf[TS_SIZE] != TS_SIG)\r
306     { // Not terminated correctly.\r
307       buf++; ret++; len--;\r
308       while (len > 0 && *buf != TS_SIG)\r
309       {\r
310         buf++; ret++; len--;\r
311       }\r
312     }\r
313     else\r
314     {\r
315       int rc = processTS(buf);\r
316       if (rc)\r
317       { // Successfully processed\r
318         buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;\r
319       }\r
320       else\r
321       { // Processing failed.\r
322         return ret;\r
323       }\r
324     }\r
325   }\r
326   return ret;\r
327 }\r
328 \r
329 \r
330 int DemuxerTS::processTS(UCHAR* buf)\r
331 {\r
332   int datalen = TS_SIZE - 4;\r
333 \r
334   int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
335   UCHAR payload = buf[1] & 0x40;\r
336 \r
337 \r
338   if (buf[3] & 0x20) // Adaptation field is present\r
339     datalen -= (buf[4] + 1);\r
340   if (datalen < 0) // Error in stream TODO log this\r
341     return 1;\r
342   if (datalen == 0) // Null packet\r
343     return 1;\r
344  // if (!(buf[3] &0x10)) return 1; // no payload\r
345   buf += (TS_SIZE - datalen);\r
346 \r
347   if (payload)\r
348   {\r
349       int rc = 1;\r
350       if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
351           int pmtpid = (*(buf+11)<< 8) | *(buf+12);\r
352           if ((pmtpid >> 13) != 0x07) \r
353           {\r
354               Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13));\r
355           } \r
356           else \r
357           {\r
358               pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
359               PMTPID = pmtpid;\r
360           }\r
361             return 1;\r
362     }\r
363     if (pid == PMTPID) \r
364     { //PMT\r
365         int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3);\r
366         //sectionlength += 4; //include header but subtract crc in the end...\r
367         int p = 13; //skip fixed part of pmt\r
368         Channel new_channelinfo;\r
369         new_channelinfo.numAPids=0;\r
370         new_channelinfo.numDPids=0;\r
371         new_channelinfo.numSPids=0;\r
372         new_channelinfo.number=0;\r
373         new_channelinfo.type=VDR::RADIO;\r
374         new_channelinfo.name=NULL;\r
375         new_channelinfo.tpid=0xFFFFF; //unused, check this\r
376         new_channelinfo.vpid=0xFFFFF; //unused, check this\r
377         new_channelinfo.index=0;\r
378 \r
379         new_channelinfo.apids.clear();\r
380         new_channelinfo.dpids.clear();\r
381         new_channelinfo.spids.clear();\r
382         \r
383         while ( p < sectionlength) {\r
384             int streamtype = *(buf+p);\r
385             p++;\r
386             int foundpid = (*(buf+p)<< 8) | *(buf+p+1);\r
387             p += 2; //skip ES Pid\r
388             int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1);\r
389             p += 2; //skip ES length\r
390             if ((foundpid >> 13) != 0x07)\r
391             {\r
392               Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
393             }\r
394             else \r
395             {\r
396                 foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
397                 bool notfound=false;\r
398                 int pos=0;\r
399        //     Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid);\r
400                 switch (streamtype)\r
401                 {\r
402                 case 0x1B: //MPEG 4 for future use\r
403                 case 1:\r
404                 case 2: { //video\r
405                     if (foundpid != getVID())   \r
406                         setVID(foundpid);\r
407                     new_channelinfo.type=VDR::VIDEO;\r
408                                         new_channelinfo.vstreamtype=streamtype;\r
409                     new_channelinfo.vpid=foundpid;\r
410                                         if (streamtype==0x1b) h264=true;\r
411                                         else h264=false;\r
412 \r
413                 //  Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid);\r
414                         }break;\r
415                 case 3:\r
416                 case 4: { //audio\r
417                     apid newapid;\r
418                     newapid.pid = foundpid;\r
419                     newapid.name = NULL; //set it in player\r
420                     new_channelinfo.apids.push_back(newapid);\r
421                     new_channelinfo.numAPids++;\r
422                     if (getAID() == 0) { //set unset AID to first audio pid that reports itself\r
423                         setAID(foundpid,0);\r
424                         Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid);\r
425                     }\r
426                         } break;\r
427                 case 5:\r
428                 case 6: { //Private Data \r
429                     apid newapid;\r
430                     newapid.pid = foundpid;\r
431                     newapid.name = NULL; //set it in player\r
432                     pos=0;\r
433                     notfound=true;\r
434                   \r
435                     while (pos< eslength && notfound) {\r
436                         switch (buf[p+pos]) {\r
437                         case 0x6A: {//Ac3 descriptor \r
438                             new_channelinfo.dpids.push_back(newapid);\r
439                             new_channelinfo.numDPids++;\r
440                             notfound=false;\r
441                                    } break; \r
442                        case 0x59: {//SubtitlingDescriptor\r
443                             new_channelinfo.spids.push_back(newapid);\r
444                             new_channelinfo.numSPids++;\r
445                             notfound=false;\r
446                                    } break;\r
447                        case 0x56: {\r
448                            new_channelinfo.tpid=foundpid;\r
449                            notfound=false;\r
450                                   } break;\r
451                         };\r
452                         pos+=2+buf[p+pos+1];\r
453                     }\r
454 \r
455                         } break;\r
456                 default://TODO how about subtitles and second audio pids\r
457                     break;\r
458                 }\r
459                 }\r
460             \r
461                  p += eslength; //skip es descriptor\r
462         \r
463         \r
464             }\r
465         bool audioPIDpresent=false; //Check if pids chnages\r
466         ULONG i;\r
467         for (i=0;i<channelinfo.numAPids;i++) {\r
468             if (aID == (int)channelinfo.apids[i].pid) {\r
469                 audioPIDpresent=true;\r
470             }\r
471         }\r
472         for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {\r
473             if (aID == (int)channelinfo.dpids[i].pid) {\r
474                 audioPIDpresent=true;\r
475             }\r
476         }\r
477         if (! audioPIDpresent) {\r
478             if (channelinfo.numAPids>0) {\r
479                 setAID(channelinfo.apids[0].pid,0);\r
480             } else if (channelinfo.numDPids>0) {\r
481                 setAID(channelinfo.dpids[0].pid,1);\r
482             }\r
483         }\r
484 \r
485         channelinfo=new_channelinfo;\r
486         havechannelinfo=true;\r
487 \r
488          return 1;\r
489     }\r
490     \r
491 \r
492     \r
493 \r
494     if (pid == vID)\r
495     {\r
496       if (vActive)\r
497       {\r
498         if (!parsed)\r
499         {\r
500           parseTSPacketDetails(vPacket);\r
501           parsed = true;\r
502         }\r
503         rc = submitPacket(vPacket);\r
504       }\r
505       vActive = true;\r
506     }\r
507     if (pid == aID)\r
508     {\r
509       if (aActive)\r
510       {\r
511         if (!parsed)\r
512         {\r
513           parseTSPacketDetails(aPacket);\r
514           parsed = true;\r
515         }\r
516         rc = submitPacket(aPacket);\r
517       }\r
518       aActive = true;\r
519     }\r
520     if (pid == subID)\r
521     {\r
522       if (subActive)\r
523       {\r
524         if (!parsed)\r
525         {\r
526           parseTSPacketDetails(subPacket);\r
527           parsed = true;\r
528         }\r
529         rc = submitPacket(subPacket);\r
530       }\r
531       subActive = true;\r
532     }\r
533     if (isteletextdecoded && pid == tID)\r
534     {\r
535       if (tActive)\r
536       {\r
537         if (!parsed)\r
538         {\r
539           parseTSPacketDetails(tPacket);\r
540           parsed = true;\r
541         }\r
542       rc = submitPacket(tPacket);\r
543       }\r
544       tActive = true;\r
545     }\r
546     if (rc == 0) return 0;\r
547 \r
548     parsed = false;\r
549     if (pid == vID)\r
550     {\r
551       vPacket.init(PESTYPE_VID0);\r
552       buf += 6; datalen -= 6;\r
553     }\r
554     if (pid == aID)\r
555     {\r
556       switch (atype)\r
557       {\r
558       case 1:\r
559         aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);\r
560         break;\r
561       default:\r
562       case 0:\r
563         aPacket.init(PESTYPE_AUD0);\r
564         break;\r
565       }\r
566       buf += 6; datalen -= 6;\r
567     }\r
568     if (pid == subID)\r
569     {\r
570       subPacket.init(PESTYPE_PRIVATE_1);\r
571       subLength = (buf[4] << 8) + buf[5];\r
572       buf += 6; datalen -= 6;\r
573     }\r
574     if (isteletextdecoded && pid == tID)\r
575     {\r
576         tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);\r
577       buf += 6; datalen -= 6;\r
578     }\r
579   }\r
580 \r
581   if ( (pid == vID && vActive) ||\r
582        (pid == aID && aActive) ||\r
583        (pid == tID && tActive) ||\r
584        (pid == subID && subActive) )\r
585   {\r
586     PESPacket* packet = NULL;\r
587     if (pid == vID) packet = &vPacket;\r
588     if (pid == aID) packet = &aPacket;\r
589     if (pid == subID) {\r
590       packet = &subPacket;\r
591     }\r
592     if (pid == tID) packet = &tPacket;\r
593     if (packet != NULL)\r
594     {\r
595       if (packet->write(buf, datalen) == 0)\r
596       { // Writing to packet failed. It has overflowed.\r
597         if (!parsed)\r
598         {\r
599           parseTSPacketDetails(*packet);\r
600           parsed = true;\r
601         }\r
602         if (submitPacket(*packet) == 0) return 0;\r
603         parsed = false;\r
604         packet->truncate();\r
605         packet->write((UCHAR*)"\200\000\000", 3);\r
606         packet->write(buf, datalen);\r
607       }\r
608     }\r
609   }\r
610 \r
611   if (pid == subID && subActive && subPacket.getLength() == subLength)\r
612   {\r
613     parsePacketDetails(subPacket);\r
614 Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream());\r
615     submitPacket(subPacket);\r
616     subActive = false;\r
617   }\r
618 \r
619   return 1;\r
620 }\r
621 \r
622 ULONG DemuxerTS::getPacketNum()\r
623 {\r
624   return packetNumber;\r
625 }\r
626 \r
627 ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts)\r
628 {\r
629   ULLONG difference = (1LL<<33);\r
630   ULONG ref_frame = 0;\r
631   int total = 0, actual = 0;\r
632   if (pts==0) return 0; //we are in startup\r
633   pts_map_mutex.Lock();\r
634   PTSMap::iterator iter = pts_map.begin();\r
635   while (iter != pts_map.end())\r
636   {\r
637     ++total;\r
638      //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts);\r
639     if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)\r
640     {\r
641       difference = 0;\r
642       ref_frame = iter->frame;\r
643       actual = total;\r
644       break;\r
645     }\r
646     ULLONG newdiff = PTSDifference(pts, iter->pts);\r
647     if (newdiff < difference)\r
648     {\r
649       difference = newdiff;\r
650       ref_frame = iter->frame;\r
651       actual = total;\r
652     }\r
653     ++iter;\r
654   }\r
655   if (total > 1 && actual == 1) // We are using the most recent PTS ref.\r
656   {                             // Delete the rest.\r
657     iter = pts_map.begin(); iter++;\r
658     pts_map.erase(iter, pts_map.end());\r
659   }\r
660   pts_map_mutex.Unlock();\r
661   \r
662  Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference);\r
663 \r
664   if (difference == (1LL<<33))\r
665     return 0; // We cannot make sense of the pts\r
666   else\r
667     return ref_frame + difference * fps / 90000;\r
668 }\r
669 \r
670 \r
671 void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas\r
672 {\r
673     parsePacketDetails(packet);\r
674     if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&\r
675                         packet.getPacketType() <= PESTYPE_AUDMAX)\r
676     {\r
677         packetNumber++;\r
678     }\r
679     UINT pictsinpacket=packet.countPictureHeaders(h264);\r
680     \r
681     UINT numpicts=0;\r
682   /*  if (!doubledframerate)\r
683     {*/\r
684         numpicts=pictsinpacket;\r
685   /*  }\r
686     else\r
687     {\r
688         numpicts=(pictsinpacket+framereserve)>>1;\r
689         framereserve=(pictsinpacket+framereserve)%2;\r
690     }*/\r
691 \r
692 \r
693   if (frameCounting && numpicts &&\r
694       packet.getPacketType() >= PESTYPE_VID0 &&\r
695       packet.getPacketType() <= PESTYPE_VIDMAX)\r
696   {\r
697     frameNumber+=numpicts;\r
698     ULONG frame_num = frameNumber;\r
699     if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())\r
700     {\r
701       PTSMapEntry me;\r
702       pts_map_mutex.Lock();\r
703       if (pts_map.empty())\r
704       {\r
705         me.pts = packet.getPTS();\r
706         me.frame = frame_num;\r
707         pts_map_mutex.Unlock();\r
708         pts_map_mutex.Lock();\r
709         pts_map.push_front(me);\r
710       }\r
711       me = pts_map.front();\r
712       pts_map_mutex.Unlock();\r
713 \r
714       //UINT fps = Video::getInstance()->getFPS();\r
715       double tfps=fps;\r
716      // if (doubledframerate) tfps*=2.;\r
717       ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / tfps));\r
718       while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);\r
719 \r
720       // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file\r
721 \r
722       /*\r
723       if (!doubledframerate \r
724           &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1 \r
725           || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) {\r
726               doubledframerate=true; //Detected  p50 or p60\r
727       }*/\r
728 \r
729       if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!\r
730       {\r
731         me.pts = packet.getPTS();\r
732         me.frame = frame_num;\r
733         pts_map_mutex.Lock();\r
734         pts_map.push_front(me);\r
735         pts_map_mutex.Unlock();\r
736       }\r
737     }\r
738   }\r
739 }\r
740 \r
741 \r
742 bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
743 {\r
744     int pmtpidy=0;\r
745 \r
746   while (len >= TS_SIZE)\r
747   {\r
748       if (*buf != TS_SIG) {buf++;len--; continue;} \r
749 \r
750     //Pattern scanning won't work for ts\r
751 \r
752       \r
753       int datalen = TS_SIZE - 4;\r
754       int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];\r
755       UCHAR payload = buf[1] & 0x40;\r
756       \r
757       if (buf[3] & 0x20) // Adaptation field is present\r
758           datalen -= (buf[4] + 1);\r
759 \r
760       UCHAR* curbuf =buf+ (TS_SIZE - datalen);\r
761      \r
762       if (payload) {\r
763           if (pid == 0x00) {//PAT, only take first program number, ignore the rest\r
764               int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);\r
765               if ((pmtpid >> 13) != 0x07) \r
766               {\r
767                   Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));\r
768               } \r
769               else \r
770               {\r
771                   pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits\r
772                   pmtpidy = pmtpid;\r
773                                   Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid );\r
774               }\r
775           \r
776           } else if (pid == pmtpidy) { //PMT\r
777               int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);\r
778               //sectionlength += 4; //include header but subtract crc in the end...\r
779               int p = 13; //skip fixed part of pmt\r
780               while ( p < sectionlength) {\r
781                   int streamtype = *(curbuf+p);\r
782                   p++;\r
783                   int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);\r
784                   p += 2; //skip ES Pid\r
785                   int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);\r
786                   p += 2; //skip ES length\r
787                   if ((foundpid >> 13) != 0x07)\r
788                   {\r
789                       Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));\r
790                   }\r
791                   else \r
792                   {\r
793                       foundpid = foundpid & 0x1FFF; //clear upper 3 bits\r
794                    //   int pos=0; UNUSED?\r
795                                           Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype);\r
796                       if (streamtype==1 || streamtype ==2) {\r
797                                                   ish264=false;\r
798                                                   Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video");\r
799                           return true;\r
800                       }\r
801                                           if (streamtype==0x1b) {\r
802                                                   ish264=true;\r
803                                                   Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video");\r
804                                                   return true;\r
805                                           }\r
806                   }\r
807                   p += eslength; //skip es descriptor\r
808               }\r
809                           ish264=false;\r
810               return false;\r
811           } \r
812       }\r
813       len-=TS_SIZE;\r
814       buf+=TS_SIZE;\r
815   }\r
816   ish264=false;\r
817   return false;\r
818 }\r
819 \r
820 UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted\r
821\r
822     //This function strips all TS Headers and non video payload\r
823     UINT readpos=0;\r
824     UINT writepos=0;\r
825     PESPacket destpaket;\r
826     bool started=true;\r
827     while (readpos < len ) {\r
828         if (buf[readpos] != TS_SIG) {readpos++; continue;} \r
829         UINT oldreadpos=readpos;\r
830 \r
831         int datalen = TS_SIZE - 4;\r
832         int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2];\r
833         UCHAR payload = buf[readpos+1] & 0x40;\r
834         if (buf[readpos+3] & 0x20) { // Adaptation field is present\r
835            datalen -= (buf[readpos+4] + 1);\r
836         }\r
837         if (datalen < 0) {// Error in stream TODO log this\r
838             return 0;\r
839         }\r
840         if (datalen == 0) {// Null packet\r
841              readpos=oldreadpos+TS_SIZE;\r
842             continue;\r
843         }\r
844         readpos += (TS_SIZE - datalen);\r
845         UINT towrite=min(datalen,len-readpos);\r
846         if (pid == vID) {\r
847             if (payload) {\r
848                 if (started) {\r
849                     parsePacketDetails(destpaket);\r
850                     memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
851                     writepos+=destpaket.getSize();\r
852                  }\r
853                  destpaket.init(PESTYPE_VID0);\r
854                  readpos += 6; towrite -= 6;\r
855                  started=true;\r
856             }\r
857 \r
858             if (started) {\r
859                 if (!destpaket.write(buf+readpos,towrite)) {\r
860                     parsePacketDetails(destpaket);\r
861                     memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
862                     writepos+=destpaket.getSize();\r
863                     destpaket.truncate();\r
864                                         destpaket.write((UCHAR*)"\200\000\000", 3);\r
865                     destpaket.write(buf+readpos,towrite);\r
866 \r
867                 }\r
868             }\r
869             \r
870        \r
871 \r
872         }\r
873         readpos=oldreadpos+TS_SIZE;\r
874     }\r
875     parsePacketDetails(destpaket);\r
876     memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());\r
877     writepos+=destpaket.getSize();\r
878  \r
879     return writepos;\r
880 }    \r
881 \r
882 \r
883 \r