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