2 Copyright 2006-2008 Mark Calderbank
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
20 #include "demuxerts.h"
26 #define PTS_JUMP_MARGIN 10000
27 #define PTS_ALLOWANCE 90000
29 // TODO: PTS class to handle wrapping arithmetic & comparisons?
30 static u8 PTSDistance(u8 pts1, u8 pts2)
32 // Assume pts1, pts2 < 2^33; calculate shortest distance between
33 u8 ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
34 if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
38 static u8 PTSDifference(u8 pts1, u8 pts2)
40 // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
44 return (1LL<<33) + pts1 - pts2;
47 DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)
49 vID = p_vID; vActive = false;
50 aID = p_aID; aActive = false;
51 subID = p_subID; subActive = false;
55 havechannelinfo=false;
56 //doubledframerate=false;
60 pinfo.hasaccessunit=false;
63 void DemuxerTS::flush()
67 havechannelinfo=false;
69 vPacket.init(PESTYPE_VID0);
73 aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
77 aPacket.init(PESTYPE_AUD0);
80 subPacket.init(PESTYPE_PRIVATE_1);
81 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
88 // doubledframerate=false;
91 pinfo.hasaccessunit=false;
94 int DemuxerTS::scan(u1* /*buf*/, int /*len*/)
99 return PESTYPE_PRIVATE_1;
106 void DemuxerTS::setVID(int p_vID)
109 vPacket.init(PESTYPE_VID0);
113 void DemuxerTS::setAID(int p_aID, int type, int streamtype, bool slivetv)
117 astreamtype = streamtype;
122 aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
123 setAudioStream(PESTYPE_SUBSTREAM_AC30);
127 aPacket.init(PESTYPE_AUD0);
128 setAudioStream(PESTYPE_AUD0);
134 void DemuxerTS::setSubID(int p_subID)
137 subPacket.init(PESTYPE_PRIVATE_1);
142 void DemuxerTS::setTID(int p_tID)
145 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
153 int DemuxerTS::findPTS(u1* buf, int len, u8* dest)
157 while (len >= TS_SIZE)
159 if (*buf != TS_SIG) {buf++;len--; continue;}
161 //Pattern scanning won't work for ts
164 int datalen = TS_SIZE - 4;
165 int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
166 u1 payload = buf[1] & 0x40;
168 if (buf[3] & 0x20) // Adaptation field is present
169 datalen -= (buf[4] + 1);
171 u1* curbuf =buf+ (TS_SIZE - datalen);
175 if (pid == 0x00) {//PAT, only take first program number, ignore the rest
176 int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);
177 if ((pmtpid >> 13) != 0x07)
179 LogNT::getInstance()->debug("findPTS", "PMTPID={:#x} {:#x} TRAILING 111 not set but {:#x}", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
183 pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
187 } else if (pid == PMTPID) { //PMT
188 int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);
189 //sectionlength += 4; //include header but subtract crc in the end...
190 int p = 13; //skip fixed part of pmt
191 while ( p < sectionlength) {
192 int streamtype = *(curbuf+p);
194 int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);
195 p += 2; //skip ES Pid
196 int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);
197 p += 2; //skip ES length
198 if ((foundpid >> 13) != 0x07)
200 LogNT::getInstance()->debug("findPTS", "FOUNDPID={:#x} {:#x} TRAILING 111 not set but {:#x}", *(buf+p),*(buf+p+1), (foundpid >> 13));
204 foundpid = foundpid & 0x1FFF; //clear upper 3 bits
206 if (streamtype==3 || streamtype ==4) {
210 p += eslength; //skip es descriptor
212 } else if (pid == scanaid) {
213 // u4 framelength = ((u4)curbuf[4] << 8) | curbuf[5]; UNUSED?
215 if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
217 *dest = ( (u8)(curbuf[9] & 0x0E) << 29 ) |
218 ( (u8)(curbuf[10]) << 22 ) |
219 ( (u8)(curbuf[11] & 0xFE) << 14 ) |
220 ( (u8)(curbuf[12]) << 7 ) |
221 ( (u8)(curbuf[13] & 0xFE) >> 1 );
233 void DemuxerTS::setFrameNum(u4 frame)
235 frameCounting = true;
238 LogNT::getInstance()->debug("DemuxerTS", "setFrameNum {}", frame);
241 void DemuxerTS::setPacketNum(u4 npacket)
243 packetCounting = true;
244 packetNumber = npacket;
245 LogNT::getInstance()->debug("DemuxerTS", "setPacketNum {}", npacket);
248 int DemuxerTS::put(u1* buf, int len)
250 int ret = 0; // return number of bytes consumed
252 bool misaligned_mess=false;
255 if (len >= TS_SIZE + 1 - partPacket)
256 { // Remainder of partial packet is available, plus one
257 memcpy(store+partPacket, buf, TS_SIZE - partPacket);
258 ret += TS_SIZE - partPacket;
259 buf += TS_SIZE - partPacket;
260 len -= TS_SIZE - partPacket;
261 partPacket = TS_SIZE;
263 { // Packet is properly terminated
264 int rc = processTS(store);
266 partPacket = 0; // Successfully processed
268 return ret; // Try again later.
271 { // Packet not terminated. Find another candidate, and shift store
272 if (!misaligned_mess) {
273 LogNT::getInstance()->error("TS Demuxer", "TS Misaligned!A");
274 misaligned_mess=true; // do not alarm more than once
277 while (search < partPacket && store[search] != TS_SIG)
279 partPacket -= search;
280 if (partPacket) memcpy(store, store+search, partPacket);
284 { // Still don't have complete packet. Consume what we do have.
285 memcpy(store+partPacket, buf, len);
292 // Position ourselves at a candidate TS packet
293 while (len > 0 && *buf != TS_SIG)
295 if (!misaligned_mess) {
296 LogNT::getInstance()->error("TS Demuxer", "TS Misaligned!B");
297 misaligned_mess=true; // do not alarm more than once
304 if (len < TS_SIZE + 1)
305 { // Not enough data. Store what we have.
306 memcpy(store, buf, len);
312 if (buf[TS_SIZE] != TS_SIG)
313 { // Not terminated correctly.
315 while (len > 0 && *buf != TS_SIG)
322 int rc = processTS(buf);
324 { // Successfully processed
325 buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
328 { // Processing failed.
337 int DemuxerTS::processTS(u1* buf)
339 int datalen = TS_SIZE - 4;
341 int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
342 u1 payload = buf[1] & 0x40;
345 if (buf[3] & 0x20) // Adaptation field is present
346 datalen -= (buf[4] + 1);
347 if (datalen < 0) // Error in stream TODO log this
349 if (datalen == 0) // Null packet
351 // if (!(buf[3] &0x10)) return 1; // no payload
352 buf += (TS_SIZE - datalen);
357 if (pid == 0x00) {//PAT, only take first program number, ignore the rest
358 int pmtpid = (*(buf+11)<< 8) | *(buf+12);
359 if ((pmtpid >> 13) != 0x07)
361 LogNT::getInstance()->debug("ProcessTS", "PMTPID={:#x} {:#x} TRAILING 111 not set but {:#x}", *(buf+11),*(buf+12), (pmtpid >> 13));
365 pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
372 int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3);
373 //sectionlength += 4; //include header but subtract crc in the end...
374 int p = 13; //skip fixed part of pmt
375 Channel new_channelinfo;
376 new_channelinfo.numAPids=0;
377 new_channelinfo.numDPids=0;
378 new_channelinfo.numSPids=0;
379 new_channelinfo.number=0;
380 new_channelinfo.type=VDR::RADIO;
381 new_channelinfo.tpid=0xFFFFF; //unused, check this
382 new_channelinfo.vpid=0xFFFFF; //unused, check this
383 new_channelinfo.index=0;
385 new_channelinfo.apids.clear();
386 new_channelinfo.dpids.clear();
387 new_channelinfo.spids.clear();
389 while ( p < sectionlength) {
390 int streamtype = *(buf+p);
392 int foundpid = (*(buf+p)<< 8) | *(buf+p+1);
393 p += 2; //skip ES Pid
394 int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1);
395 p += 2; //skip ES length
396 if ((foundpid >> 13) != 0x07)
398 LogNT::getInstance()->debug("ProcessTS", "FOUNDPID={:#x} {:#x} TRAILING 111 not set but {:#x}", *(buf+p),*(buf+p+1), (foundpid >> 13));
402 foundpid = foundpid & 0x1FFF; //clear upper 3 bits
406 // LogNT::getInstance()->debug("ProcessTS", "FOUNDPID is {:#x} {:#x}", foundpid,streamtype);
409 case 0x1B: //MPEG 4 for future use
412 if (foundpid != getVID())
414 new_channelinfo.type=VDR::VIDEO;
415 new_channelinfo.vstreamtype=streamtype;
416 new_channelinfo.vpid=foundpid;
417 if (streamtype==0x1b) h264=true;
420 // LogNT::getInstance()->debug("ProcessTS", "Set video PID to {:#x}", foundpid);
422 case 0x0F: //AAC ADTS packaging
423 case 0x11: // LATM packaging
427 newapid.pid = foundpid;
429 newapid.type=streamtype;
432 while (pos< eslength && nolang) {
433 switch (buf[p+pos]) {
435 newapid.desc[0]=buf[p+pos+2];
436 newapid.desc[1]=buf[p+pos+3];
437 newapid.desc[2]=buf[p+pos+4];
440 // LogNT::getInstance()->debug("ProcessTS", "FOUNDLANG is {}", newapid.desc);
447 new_channelinfo.apids.push_back(newapid);
448 new_channelinfo.numAPids++;
452 case 6: { //Private Data
454 newapid.pid = foundpid;
455 newapid.desc[0]=0; //set it in player
461 while (pos< eslength && (notfound || nolang)) {
462 switch (buf[p+pos]) {
463 case 0x7A: // Enhanced Ac3 Desriptor
464 case 0x6A: {//Ac3 descriptor
465 newapid.type=buf[p+pos];
470 case 0x59: {//SubtitlingDescriptor
472 newapid.type=buf[p+pos];
473 newapid.desc[0]=buf[p+pos+2];
474 newapid.desc[1]=buf[p+pos+3];
475 newapid.desc[2]=buf[p+pos+4];
477 newapid.data1=(buf[p+pos+5]<<8) |(buf[p+pos+6]);
478 newapid.data2=(buf[p+pos+7]<<8) |(buf[p+pos+8]);
479 // LogNT::getInstance()->debug("ProcessTS", "FOUNDSUB is {}", newapid.desc);
484 newapid.desc[0]=buf[p+pos+2];
485 newapid.desc[1]=buf[p+pos+3];
486 newapid.desc[2]=buf[p+pos+4];
489 // LogNT::getInstance()->debug("ProcessTS", "FOUNDLANG is {}", newapid.desc);
493 new_channelinfo.tpid=foundpid;
500 new_channelinfo.dpids.push_back(newapid);
501 new_channelinfo.numDPids++;
502 } else if (type==2) {
503 new_channelinfo.spids.push_back(newapid);
504 new_channelinfo.numSPids++;
508 default://TODO how about subtitles and second audio pids
513 p += eslength; //skip es descriptor
518 bool audioPIDpresent=false; //Check if pids chnages
520 for (i=0;i<channelinfo.numAPids;i++) {
521 if (aID == (int)channelinfo.apids[i].pid) {
522 audioPIDpresent=true;
525 for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {
526 if (aID == (int)channelinfo.dpids[i].pid) {
527 audioPIDpresent=true;
530 if (! audioPIDpresent || getAID() == 0) {
535 Control* control = Control::getInstance();
537 if (channelinfo.numDPids > 0 && Audio::getInstance()->maysupportAc3())
540 while (j < channelinfo.numDPids)
542 int newpref = control->getLangPref(false, channelinfo.dpids[j].desc);
543 if (Audio::getInstance()->streamTypeSupported(channelinfo.dpids[j].type)
544 && (prefered < 0 || newpref < prefered))
554 if (channelinfo.numAPids > 0)
557 while (j < channelinfo.numAPids)
559 int newpref = control->getLangPref(false, channelinfo.apids[j].desc);
560 if (Audio::getInstance()->streamTypeSupported(channelinfo.apids[j].type)
561 && (prefered < 0 || newpref < prefered))
572 setAID(channelinfo.dpids[selected].pid,1,channelinfo.dpids[selected].type,false);
573 Audio::getInstance()->setStreamType(Audio::MPEG2_PES);
575 setAID(channelinfo.apids[selected].pid,0,channelinfo.apids[selected].type,false);
576 Audio::getInstance()->setStreamType(Audio::MPEG2_PES);
583 if (channelinfo.numSPids) {
585 while (j < channelinfo.numSPids)
587 int newpref = control->getLangPref(true, channelinfo.spids[j].desc);
588 if ( (prefered < 0 || newpref < prefered))
598 setSubID(channelinfo.spids[selected].pid);
603 channelinfo=new_channelinfo;
606 havechannelinfo=true;
620 parseTSPacketDetails(vPacket);
623 rc = submitPacket(vPacket);
633 parseTSPacketDetails(aPacket);
636 rc = submitPacket(aPacket);
646 parseTSPacketDetails(subPacket);
649 rc = submitPacket(subPacket);
653 if (isteletextdecoded && pid == tID)
659 parseTSPacketDetails(tPacket);
662 rc = submitPacket(tPacket);
666 if (rc == 0) return 0;
671 vPacket.init(PESTYPE_VID0);
672 buf += 6; datalen -= 6;
679 aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
683 aPacket.init(PESTYPE_AUD0);
686 buf += 6; datalen -= 6;
690 subPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_DVBSUBTITLE0);
691 subLength = (buf[4] << 8) + buf[5];
692 buf += 6; datalen -= 6;
694 if (isteletextdecoded && pid == tID)
696 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
697 buf += 6; datalen -= 6;
701 if ( (pid == vID && vActive) ||
702 (pid == aID && aActive) ||
703 (pid == tID && tActive) ||
704 (pid == subID && subActive) )
706 PESPacket* packet = NULL;
707 if (pid == vID) packet = &vPacket;
708 if (pid == aID) packet = &aPacket;
712 if (pid == tID) packet = &tPacket;
715 if (packet->write(buf, datalen) == 0)
716 { // Writing to packet failed. It has overflowed.
719 parseTSPacketDetails(*packet);
722 if (submitPacket(*packet) == 0) return 0;
725 packet->write((u1*)"\200\000\000", 3);
726 packet->write(buf, datalen);
731 if (pid == subID && subActive && subPacket.getLength() == subLength)
733 parsePacketDetails(subPacket);
734 //LogNT::getInstance()->debug("DEMUXERTS", "SUBMITTING A SUBTITLE PACKET {} {:#x}", subLength, subPacket.getSubstream());
735 submitPacket(subPacket);
742 u4 DemuxerTS::getPacketNum()
747 u4 DemuxerTS::getFrameNumFromPTS(u8 pts)
749 u8 difference = (1LL<<33);
751 int total = 0, actual = 0;
752 if (pts==0) return 0; //we are in startup
753 pts_map_mutex.lock();
754 PTSMap::iterator iter = pts_map.begin();
755 while (iter != pts_map.end())
758 //LogNT::getInstance()->debug("DemuxerTS", "getFrameNumfromPTS pts1 {} pts2 {}", pts, iter->pts);
759 if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
762 ref_frame = iter->frame;
766 u8 newdiff = PTSDifference(pts, iter->pts);
767 if (newdiff < difference)
769 difference = newdiff;
770 ref_frame = iter->frame;
775 if (total > 1 && actual == 1) // We are using the most recent PTS ref.
776 { // Delete the rest.
777 iter = pts_map.begin(); iter++;
778 pts_map.erase(iter, pts_map.end());
780 pts_map_mutex.unlock();
782 //LogNT::getInstance()->debug("DemuxerTS", "getFrameNumfromPTS pts {} deleted {} difference {}", pts, total,difference);
784 if (difference == (1LL<<33))
785 return 0; // We cannot make sense of the pts
787 return ref_frame + difference * fps / 90000;
791 void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas
793 parsePacketDetails(packet);
794 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
795 packet.getPacketType() <= PESTYPE_AUDMAX)
799 u4 pictsinpacket=packet.countPictureHeaders(h264,pinfo);
802 /* if (!doubledframerate)
804 numpicts=pictsinpacket;
808 numpicts=(pictsinpacket+framereserve)>>1;
809 framereserve=(pictsinpacket+framereserve)%2;
813 if (frameCounting && numpicts &&
814 packet.getPacketType() >= PESTYPE_VID0 &&
815 packet.getPacketType() <= PESTYPE_VIDMAX)
817 frameNumber+=numpicts;
818 u4 frame_num = frameNumber;
819 if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())
822 pts_map_mutex.lock();
825 me.pts = packet.getPTS();
826 me.frame = frame_num;
827 pts_map_mutex.unlock();
828 pts_map_mutex.lock();
829 pts_map.push_front(me);
831 me = pts_map.front();
832 pts_map_mutex.unlock();
834 //u4 fps = Video::getInstance()->getFPS();
836 // if (doubledframerate) tfps*=2.;
837 long long pts_expected = me.pts + 90000LL*((long long)(((double)(frame_num - me.frame)) / tfps));
839 while (pts_expected < 0) pts_expected += (1LL<<33);
840 while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
842 // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file
845 if (!doubledframerate
846 &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1
847 || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) {
848 doubledframerate=true; //Detected p50 or p60
851 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
853 me.pts = packet.getPTS();
854 me.frame = frame_num;
855 pts_map_mutex.lock();
856 pts_map.push_front(me);
857 pts_map_mutex.unlock();
864 bool DemuxerTS::scanForVideo(u1* buf, u4 len, bool &ish264)
868 while (len >= TS_SIZE)
870 if (*buf != TS_SIG) {buf++;len--; continue;}
872 //Pattern scanning won't work for ts
875 int datalen = TS_SIZE - 4;
876 int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
877 u1 payload = buf[1] & 0x40;
879 if (buf[3] & 0x20) // Adaptation field is present
880 datalen -= (buf[4] + 1);
882 u1* curbuf =buf+ (TS_SIZE - datalen);
885 if (pid == 0x00) {//PAT, only take first program number, ignore the rest
886 int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12);
887 if ((pmtpid >> 13) != 0x07)
889 LogNT::getInstance()->debug("DemuxerTS", "PMTPID={:#x} {:#x} TRAILING 111 not set but {:#x}", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
893 pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
895 LogNT::getInstance()->debug("DemuxerTS", "PMT pid {:#x}", pmtpid);
898 } else if (pid == pmtpidy) { //PMT
899 int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3);
900 //sectionlength += 4; //include header but subtract crc in the end...
901 int p = 13; //skip fixed part of pmt
902 while ( p < sectionlength) {
903 int streamtype = *(curbuf+p);
905 int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1);
906 p += 2; //skip ES Pid
907 int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1);
908 p += 2; //skip ES length
909 if ((foundpid >> 13) != 0x07)
911 LogNT::getInstance()->debug("DemuxerTS", "FOUNDPID={:#x} {:#x} TRAILING 111 not set but {:#x}", *(buf+p),*(buf+p+1), (foundpid >> 13));
915 foundpid = foundpid & 0x1FFF; //clear upper 3 bits
916 // int pos=0; UNUSED?
917 LogNT::getInstance()->debug("DemuxerTS", "Pid found {:#x} type {:#x}",foundpid ,streamtype);
918 if (streamtype==1 || streamtype ==2) {
920 LogNT::getInstance()->debug("DemuxerTS", "Found Mpeg2 Video");
923 if (streamtype==0x1b) {
925 LogNT::getInstance()->debug("DemuxerTS", "Found h264 Video");
929 p += eslength; //skip es descriptor
942 u4 DemuxerTS::stripAudio(u1* buf, u4 len) //it has to be adapted
944 //This function strips all TS Headers and non video payload
949 while (readpos < len ) {
950 if (buf[readpos] != TS_SIG) {readpos++; continue;}
951 u4 oldreadpos=readpos;
953 int datalen = TS_SIZE - 4;
954 int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2];
955 u1 payload = buf[readpos+1] & 0x40;
956 if (buf[readpos+3] & 0x20) { // Adaptation field is present
957 datalen -= (buf[readpos+4] + 1);
959 if (datalen < 0) {// Error in stream TODO log this
962 if (datalen == 0) {// Null packet
963 readpos=oldreadpos+TS_SIZE;
966 readpos += (TS_SIZE - datalen);
967 u4 towrite=min(datalen,len-readpos);
971 parsePacketDetails(destpaket);
972 memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
973 writepos+=destpaket.getSize();
975 destpaket.init(PESTYPE_VID0);
976 readpos += 6; towrite -= 6;
981 if (!destpaket.write(buf+readpos,towrite)) {
982 parsePacketDetails(destpaket);
983 memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
984 writepos+=destpaket.getSize();
985 destpaket.truncate();
986 destpaket.write((u1*)"\200\000\000", 3);
987 destpaket.write(buf+readpos,towrite);
995 readpos=oldreadpos+TS_SIZE;
997 parsePacketDetails(destpaket);
998 memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
999 writepos+=destpaket.getSize();