diff options
Diffstat (limited to 'command/ts2pkt.cpp')
-rw-r--r-- | command/ts2pkt.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/command/ts2pkt.cpp b/command/ts2pkt.cpp new file mode 100644 index 0000000..0d13df7 --- /dev/null +++ b/command/ts2pkt.cpp @@ -0,0 +1,194 @@ +/* + * ts2pkt.cpp: A program for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "ts2pkt.h" + +cMarkAdTS2Pkt::cMarkAdTS2Pkt(const char *QueueName, int QueueSize) +{ + queue=new cMarkAdPaketQueue(QueueName,QueueSize); + Reset(); +} + +cMarkAdTS2Pkt::~cMarkAdTS2Pkt() +{ + if (queue) delete queue; +} + +void cMarkAdTS2Pkt::Reset(int ErrIndex) +{ + sync=false; + switch (ErrIndex) + { + case MA_ERR_TSSIZE: + dsyslog("inbuf not 188 bytes"); + break; + case MA_ERR_NOSYNC: + dsyslog("found no sync"); + break; + case MA_ERR_SEQ: + dsyslog("sequence error"); + break; + case MA_ERR_AFC: + dsyslog("wrong AFC value"); + break; + case MA_ERR_TOBIG: + dsyslog("buflen > 188 bytes"); + break; + case MA_ERR_NEG: + dsyslog("buflen negative"); + break; + } + counter=-1; + if (queue) queue->Clear(); +} + +bool cMarkAdTS2Pkt::InjectVideoPES(uchar *PESData, int PESSize) +{ + if ((!PESData) || (!PESSize)) return false; + + struct PESHDR *peshdr=(struct PESHDR *) PESData; + + // first check some simple things + if ((peshdr->Sync1!=0) && (peshdr->Sync2!=0) && (peshdr->Sync3!=1)) return false; + if ((peshdr->StreamID & 0xF0)!=0xE0) return false; + + int Length=(peshdr->LenH<<8)+peshdr->LenL; + if (Length) Length+=sizeof(PESHDR); + if (Length!=PESSize) return false; + + struct PESHDROPT *peshdropt=(struct PESHDROPT *) &PESData[sizeof(struct PESHDR)]; + + uchar *buf; + int buflen; + + if (peshdropt->MarkerBits==0x2) + { + // we have an optional PES header + int bpos=sizeof(struct PESHDR)+sizeof(struct PESHDROPT)+ + peshdropt->Length; + buf=&PESData[bpos]; + buflen=PESSize-bpos; + } + else + { + int bpos=sizeof(struct PESHDR); + buf=&PESData[bpos]; + buflen=PESSize-bpos; + } + queue->Inject(buf,buflen); + return true; +} + +void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **PktData, int *PktSize) +{ + if ((!PktData) || (!PktSize) || (!queue)) return; + *PktData=NULL; + *PktSize=0; + + if (TSData) + { + if (TSSize!=TS_SIZE) + { + Reset(MA_ERR_TSSIZE); + return; // we need a full packet + } + + // check TS packet sync + if (TSData[0]!=0x47) + { + Reset(MA_ERR_NOSYNC); + return; + } + + struct TSHDR *tshdr = (struct TSHDR *) TSData; + + int pid = (tshdr->PidH << 8) | tshdr->PidL; + if (Pid.Num!=pid) + { + return; // not for us + } + + if (tshdr->PayloadStart) sync=true; + if (!sync) + { + return; // not synced + } + + if ((counter!=-1) && (((counter+1) & 0xF)!=tshdr->Counter)) + { + if (counter==(int) tshdr->Counter) + { + // duplicate paket -> just ignore + return; + } + // sequence error + Reset(MA_ERR_SEQ); + return; + } + counter=tshdr->Counter; + + if ((tshdr->AFC<=0) || (tshdr->AFC>3)) + { + Reset(MA_ERR_AFC); + return; + } + + // we just ignore the infos in the adaption field (e.g. OPCR/PCR) + if ((tshdr->AFC!=1) && (tshdr->AFC!=3)) + { + return; + } + + int buflen=TS_SIZE+1; + uchar *buf=NULL; + + if (tshdr->AFC==1) + { + // payload only + buflen=TS_SIZE-sizeof(struct TSHDR); + buf=&TSData[sizeof(struct TSHDR)]; + } + + if (tshdr->AFC==3) + { + // adaption field + payload + struct TSADAPT *tsadapt = (struct TSADAPT *) &TSData[4]; + int alen=tsadapt->Len+1; + buflen=TS_SIZE-(sizeof(struct TSHDR)+alen); + buf=&TSData[sizeof(struct TSHDR)+alen]; + } + + if (buflen>TS_SIZE) + { + // size to large + Reset(MA_ERR_TOBIG); + return; + } + if (buflen<0) + { + // error in size + Reset(MA_ERR_NEG); + return; + } + if (buflen==0) + { + // no data? + return; + } + + queue->Put(buf,buflen); + } + if (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264) + { + *PktData=queue->GetPacket(PktSize,MA_PACKET_H264); + } + else + { + *PktData=queue->GetPacket(PktSize,MA_PACKET_PKT); + } + return; +} |