2 Copyright 2006-2008 Mark Calderbank
\r
4 This file is part of VOMP.
\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
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
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
21 #include "demuxerts.h"
\r
26 #define PTS_JUMP_MARGIN 10000
\r
27 #define PTS_ALLOWANCE 90000
\r
29 // TODO: PTS class to handle wrapping arithmetic & comparisons?
\r
30 static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
\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
38 static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
\r
40 // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
\r
44 return (1LL<<33) + pts1 - pts2;
\r
47 DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID)
\r
49 vID = p_vID; vActive = false;
\r
50 aID = p_aID; aActive = false;
\r
51 subID = p_subID; subActive = false;
\r
55 havechannelinfo=false;
\r
56 //doubledframerate=false;
\r
60 void DemuxerTS::flush()
\r
64 havechannelinfo=false;
\r
66 vPacket.init(PESTYPE_VID0);
\r
70 aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
\r
74 aPacket.init(PESTYPE_AUD0);
\r
77 subPacket.init(PESTYPE_PRIVATE_1);
\r
78 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
\r
85 // doubledframerate=false;
\r
89 int DemuxerTS::scan(UCHAR *buf, int len)
\r
94 return PESTYPE_PRIVATE_1;
\r
97 return PESTYPE_AUD0;
\r
101 void DemuxerTS::setVID(int p_vID)
\r
104 vPacket.init(PESTYPE_VID0);
\r
108 void DemuxerTS::setAID(int p_aID, int type)
\r
115 aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
\r
116 setAudioStream(PESTYPE_SUBSTREAM_AC30);
\r
120 aPacket.init(PESTYPE_AUD0);
\r
121 setAudioStream(PESTYPE_AUD0);
\r
127 void DemuxerTS::setSubID(int p_subID)
\r
130 subPacket.init(PESTYPE_PRIVATE_1);
\r
135 void DemuxerTS::setTID(int p_tID)
\r
138 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
\r
146 int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
\r
150 while (len >= TS_SIZE)
\r
152 if (*buf != TS_SIG) {buf++;len--; continue;}
\r
154 //Pattern scanning won't work for ts
\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
161 if (buf[3] & 0x20) // Adaptation field is present
\r
162 datalen -= (buf[4] + 1);
\r
164 UCHAR* curbuf =buf+ (TS_SIZE - datalen);
\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
172 Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
\r
176 pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
\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
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
193 Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
\r
197 foundpid = foundpid & 0x1FFF; //clear upper 3 bits
\r
198 //int pos=0; UNUSED?
\r
199 if (streamtype==3 || streamtype ==4) {
\r
203 p += eslength; //skip es descriptor
\r
205 } else if (pid == scanaid) {
\r
206 // UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5]; UNUSED?
\r
208 if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
\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
226 void DemuxerTS::setFrameNum(ULONG frame)
\r
228 frameCounting = true;
\r
229 frameNumber = frame;
\r
231 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame);
\r
234 void DemuxerTS::setPacketNum(ULONG npacket)
\r
236 packetCounting = true;
\r
237 packetNumber = npacket;
\r
238 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket);
\r
241 int DemuxerTS::put(UCHAR* buf, int len)
\r
243 int ret = 0; // return number of bytes consumed
\r
245 bool misaligned_mess=false;
\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
259 partPacket = 0; // Successfully processed
\r
261 return ret; // Try again later.
\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
270 while (search < partPacket && store[search] != TS_SIG)
\r
272 partPacket -= search;
\r
273 if (partPacket) memcpy(store, store+search, partPacket);
\r
277 { // Still don't have complete packet. Consume what we do have.
\r
278 memcpy(store+partPacket, buf, len);
\r
285 // Position ourselves at a candidate TS packet
\r
286 while (len > 0 && *buf != TS_SIG)
\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
292 buf++; ret++; len--;
\r
297 if (len < TS_SIZE + 1)
\r
298 { // Not enough data. Store what we have.
\r
299 memcpy(store, buf, len);
\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
310 buf++; ret++; len--;
\r
315 int rc = processTS(buf);
\r
317 { // Successfully processed
\r
318 buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
\r
321 { // Processing failed.
\r
330 int DemuxerTS::processTS(UCHAR* buf)
\r
332 int datalen = TS_SIZE - 4;
\r
334 int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
\r
335 UCHAR payload = buf[1] & 0x40;
\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
342 if (datalen == 0) // Null packet
\r
344 // if (!(buf[3] &0x10)) return 1; // no payload
\r
345 buf += (TS_SIZE - datalen);
\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
354 Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13));
\r
358 pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
\r
363 if (pid == PMTPID)
\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
379 new_channelinfo.apids.clear();
\r
380 new_channelinfo.dpids.clear();
\r
381 new_channelinfo.spids.clear();
\r
383 while ( p < sectionlength) {
\r
384 int streamtype = *(buf+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
392 Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
\r
396 foundpid = foundpid & 0x1FFF; //clear upper 3 bits
\r
397 bool notfound=false;
\r
399 // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid);
\r
400 switch (streamtype)
\r
402 case 0x1B: //MPEG 4 for future use
\r
405 if (foundpid != getVID())
\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
413 // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid);
\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
428 case 6: { //Private Data
\r
430 newapid.pid = foundpid;
\r
431 newapid.name = NULL; //set it in player
\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
442 case 0x59: {//SubtitlingDescriptor
\r
443 new_channelinfo.spids.push_back(newapid);
\r
444 new_channelinfo.numSPids++;
\r
448 new_channelinfo.tpid=foundpid;
\r
452 pos+=2+buf[p+pos+1];
\r
456 default://TODO how about subtitles and second audio pids
\r
461 p += eslength; //skip es descriptor
\r
465 bool audioPIDpresent=false; //Check if pids chnages
\r
467 for (i=0;i<channelinfo.numAPids;i++) {
\r
468 if (aID == (int)channelinfo.apids[i].pid) {
\r
469 audioPIDpresent=true;
\r
472 for (i=0;i<channelinfo.numDPids && (! audioPIDpresent);i++) {
\r
473 if (aID == (int)channelinfo.dpids[i].pid) {
\r
474 audioPIDpresent=true;
\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
485 channelinfo=new_channelinfo;
\r
486 havechannelinfo=true;
\r
500 parseTSPacketDetails(vPacket);
\r
503 rc = submitPacket(vPacket);
\r
513 parseTSPacketDetails(aPacket);
\r
516 rc = submitPacket(aPacket);
\r
526 parseTSPacketDetails(subPacket);
\r
529 rc = submitPacket(subPacket);
\r
533 if (isteletextdecoded && pid == tID)
\r
539 parseTSPacketDetails(tPacket);
\r
542 rc = submitPacket(tPacket);
\r
546 if (rc == 0) return 0;
\r
551 vPacket.init(PESTYPE_VID0);
\r
552 buf += 6; datalen -= 6;
\r
559 aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30);
\r
563 aPacket.init(PESTYPE_AUD0);
\r
566 buf += 6; datalen -= 6;
\r
570 subPacket.init(PESTYPE_PRIVATE_1);
\r
571 subLength = (buf[4] << 8) + buf[5];
\r
572 buf += 6; datalen -= 6;
\r
574 if (isteletextdecoded && pid == tID)
\r
576 tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX);
\r
577 buf += 6; datalen -= 6;
\r
581 if ( (pid == vID && vActive) ||
\r
582 (pid == aID && aActive) ||
\r
583 (pid == tID && tActive) ||
\r
584 (pid == subID && subActive) )
\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
592 if (pid == tID) packet = &tPacket;
\r
593 if (packet != NULL)
\r
595 if (packet->write(buf, datalen) == 0)
\r
596 { // Writing to packet failed. It has overflowed.
\r
599 parseTSPacketDetails(*packet);
\r
602 if (submitPacket(*packet) == 0) return 0;
\r
604 packet->truncate();
\r
605 packet->write((UCHAR*)"\200\000\000", 3);
\r
606 packet->write(buf, datalen);
\r
611 if (pid == subID && subActive && subPacket.getLength() == subLength)
\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
622 ULONG DemuxerTS::getPacketNum()
\r
624 return packetNumber;
\r
627 ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts)
\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
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
642 ref_frame = iter->frame;
\r
646 ULLONG newdiff = PTSDifference(pts, iter->pts);
\r
647 if (newdiff < difference)
\r
649 difference = newdiff;
\r
650 ref_frame = iter->frame;
\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
660 pts_map_mutex.Unlock();
\r
662 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference);
\r
664 if (difference == (1LL<<33))
\r
665 return 0; // We cannot make sense of the pts
\r
667 return ref_frame + difference * fps / 90000;
\r
671 void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas
\r
673 parsePacketDetails(packet);
\r
674 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
\r
675 packet.getPacketType() <= PESTYPE_AUDMAX)
\r
679 UINT pictsinpacket=packet.countPictureHeaders(h264);
\r
682 /* if (!doubledframerate)
\r
684 numpicts=pictsinpacket;
\r
688 numpicts=(pictsinpacket+framereserve)>>1;
\r
689 framereserve=(pictsinpacket+framereserve)%2;
\r
693 if (frameCounting && numpicts &&
\r
694 packet.getPacketType() >= PESTYPE_VID0 &&
\r
695 packet.getPacketType() <= PESTYPE_VIDMAX)
\r
697 frameNumber+=numpicts;
\r
698 ULONG frame_num = frameNumber;
\r
699 if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS())
\r
702 pts_map_mutex.Lock();
\r
703 if (pts_map.empty())
\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
711 me = pts_map.front();
\r
712 pts_map_mutex.Unlock();
\r
714 //UINT fps = Video::getInstance()->getFPS();
\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
720 // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file
\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
729 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
\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
742 bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
\r
746 while (len >= TS_SIZE)
\r
748 if (*buf != TS_SIG) {buf++;len--; continue;}
\r
750 //Pattern scanning won't work for ts
\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
757 if (buf[3] & 0x20) // Adaptation field is present
\r
758 datalen -= (buf[4] + 1);
\r
760 UCHAR* curbuf =buf+ (TS_SIZE - datalen);
\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
767 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13));
\r
771 pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits
\r
773 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid );
\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
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
789 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13));
\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
798 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video");
\r
801 if (streamtype==0x1b) {
\r
803 Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video");
\r
807 p += eslength; //skip es descriptor
\r
820 UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted
\r
822 //This function strips all TS Headers and non video payload
\r
825 PESPacket destpaket;
\r
827 while (readpos < len ) {
\r
828 if (buf[readpos] != TS_SIG) {readpos++; continue;}
\r
829 UINT oldreadpos=readpos;
\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
837 if (datalen < 0) {// Error in stream TODO log this
\r
840 if (datalen == 0) {// Null packet
\r
841 readpos=oldreadpos+TS_SIZE;
\r
844 readpos += (TS_SIZE - datalen);
\r
845 UINT towrite=min(datalen,len-readpos);
\r
849 parsePacketDetails(destpaket);
\r
850 memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
\r
851 writepos+=destpaket.getSize();
\r
853 destpaket.init(PESTYPE_VID0);
\r
854 readpos += 6; towrite -= 6;
\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
873 readpos=oldreadpos+TS_SIZE;
\r
875 parsePacketDetails(destpaket);
\r
876 memcpy(buf+writepos,destpaket.getData(),destpaket.getSize());
\r
877 writepos+=destpaket.getSize();
\r