From af483c11aebd8146a978dba3d604bda0951e24ac Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 17 Oct 2004 18:00:00 +0200 Subject: =?UTF-8?q?Version=201.3.13=20-=20Fixed=20checking=20for=20the=20p?= =?UTF-8?q?resence=20of=20NPTL=20(thanks=20to=20Jouni=20Karvo).=20-=20Maki?= =?UTF-8?q?ng=20sure=20section=20filters=20are=20only=20set=20if=20the=20d?= =?UTF-8?q?evice=20actually=20has=20a=20lock=20=20=20(thanks=20to=20Andrea?= =?UTF-8?q?s=20Share=20for=20pointing=20this=20out).=20-=20Fixed=20a=20pos?= =?UTF-8?q?sible=20NULL=20pointer=20assignment=20in=20cMenuText::SetText()?= =?UTF-8?q?=20(thanks=20to=20=20=20Marco=20Schl=C3=BCssler).=20-=20Fixed?= =?UTF-8?q?=20a=20crash=20in=20case=20the=20last=20line=20in=20channels.co?= =?UTF-8?q?nf=20is=20a=20group=20separator=20and=20=20=20that=20group=20is?= =?UTF-8?q?=20selected=20in=20the=20channel=20display=20(thanks=20to=20Dic?= =?UTF-8?q?k=20Streefland).=20-=20Added=20cRingBufferLinear::Read()=20to?= =?UTF-8?q?=20read=20directly=20from=20a=20file=20handle=20into=20the=20?= =?UTF-8?q?=20=20ring=20buffer.=20-=20Using=20timeouts=20in=20ring=20buffe?= =?UTF-8?q?rs=20to=20avoid=20'usleep()'.=20-=20Clearing=20the=20'Transfer?= =?UTF-8?q?=20Mode'=20ring=20buffer=20after=20clearing=20the=20device=20to?= =?UTF-8?q?=20avoid=20=20=20an=20"almost=20full"=20ring=20buffer.=20-=20Re?= =?UTF-8?q?moved=20locking=20from=20cRingBufferLinear=20for=20better=20per?= =?UTF-8?q?formance=20under=20high=20load.=20-=20Using=20a=20cRingBufferLi?= =?UTF-8?q?near=20in=20cRemux=20to=20avoid=20unnecessary=20copying=20of=20?= =?UTF-8?q?data.=20-=20Using=20a=20cRingBufferLinear=20in=20cTSBuffer=20an?= =?UTF-8?q?d=20filling=20it=20in=20a=20separate=20thread=20=20=20to=20avoi?= =?UTF-8?q?d=20buffer=20overflows.=20Plugins=20using=20cTSBuffer=20will=20?= =?UTF-8?q?need=20to=20remove=20the=20=20=20call=20to=20the=20now=20obsole?= =?UTF-8?q?te=20Read()=20function=20(see=20cDvbDevice::GetTSPacket()=20for?= =?UTF-8?q?=20=20=20the=20new=20usage=20of=20cTSBuffer).=20-=20cRemux::Pro?= =?UTF-8?q?cess()=20has=20been=20split=20into=20Put(),=20Get()=20and=20Del?= =?UTF-8?q?()=20to=20allow=20for=20a=20=20=20better=20decoupling=20of=20th?= =?UTF-8?q?e=20remuxing=20and=20disk=20writing=20process.=20Plugins=20usin?= =?UTF-8?q?g=20=20=20cRemux=20will=20need=20to=20be=20modified=20according?= =?UTF-8?q?ly.=20-=20The=20actual=20disk=20writing=20in=20recordings=20is?= =?UTF-8?q?=20now=20done=20in=20a=20separate=20thread=20to=20=20=20improve?= =?UTF-8?q?=20the=20overall=20throughput.=20-=20Changed=20cRemux=20so=20th?= =?UTF-8?q?at=20it=20returns=20the=20maximum=20available=20amount=20of=20d?= =?UTF-8?q?ata=20with=20=20=20each=20call,=20not=20just=202048=20byte.=20-?= =?UTF-8?q?=20Added=20a=20visual=20display=20of=20all=20cRingBufferLinear?= =?UTF-8?q?=20buffers=20for=20debugging.=20To=20=20=20activate=20it,=20def?= =?UTF-8?q?ine=20DEBUGRINGBUFFERS=20in=20ringbuffer.h.=20-=20Instead=20of?= =?UTF-8?q?=20cCondVar=20now=20using=20the=20new=20cCondWait=20(which=20al?= =?UTF-8?q?so=20avoids=20a=20possible=20=20=20"near=20miss"=20condition;?= =?UTF-8?q?=20thanks=20to=20Sascha=20Volkenandt=20for=20pointing=20out=20t?= =?UTF-8?q?his=20one).=20=20=20cCondVar=20is=20still=20present=20for=20plu?= =?UTF-8?q?gins=20that=20use=20it=20(and=20VDR=20itself=20also=20still=20?= =?UTF-8?q?=20=20uses=20it=20in=20cRemote).=20-=20The=20cRingBuffer=20now?= =?UTF-8?q?=20does=20EnableGet()/EnablePut()=20only=20if=20the=20buffer=20?= =?UTF-8?q?is=20more=20than=20=20=20one=20third=20full=20or=20empty,=20res?= =?UTF-8?q?pectively.=20This=20dramatically=20improves=20recording=20=20?= =?UTF-8?q?=20performance=20and=20reduces=20system=20load=20(thanks=20to?= =?UTF-8?q?=20Marco=20Schl=C3=BC=C3=9Fler=20for=20doing=20some=20=20=20tes?= =?UTF-8?q?ting=20regarding=20buffer=20performance=20and=20giving=20me=20s?= =?UTF-8?q?ome=20hints=20that=20finally=20led=20=20=20to=20finding=20out?= =?UTF-8?q?=20that=20this=20was=20the=20basic=20problem=20causing=20buffer?= =?UTF-8?q?=20overflows).=20-=20Improved=20Transfer=20Mode=20(thanks=20to?= =?UTF-8?q?=20Marco=20Schl=C3=BC=C3=9Fler=20for=20suggestions=20and=20test?= =?UTF-8?q?ing).=20-=20Fixed=20a=20possible=20crash=20with=20inconsistent?= =?UTF-8?q?=20SI=20data=20(thanks=20to=20Marcel=20Wiesweg).=20-=20Fixed=20?= =?UTF-8?q?showing=20the=20replay=20mode=20if=20the=20OSD=20is=20currently?= =?UTF-8?q?=20in=20use=20(thanks=20to=20Kimmo=20=20=20Tykkala=20for=20poin?= =?UTF-8?q?ting=20out=20this=20problem).=20-=20cOsdProvider::NewOsd()=20no?= =?UTF-8?q?w=20always=20returns=20a=20valid=20pointer,=20even=20if=20the?= =?UTF-8?q?=20OSD=20is=20=20=20currently=20in=20use=20(it=20will=20then=20?= =?UTF-8?q?return=20a=20dummy=20cOsd=20object=20and=20write=20a=20message?= =?UTF-8?q?=20to=20=20=20the=20log=20file).=20-=20Added=20Estonian=20langu?= =?UTF-8?q?age=20texts=20(thanks=20to=20Arthur=20Konovalov).=20-=20Fixed?= =?UTF-8?q?=20'newplugin'=20and=20libsi/Makefile=20to=20use=20the=20compil?= =?UTF-8?q?er=20defined=20in=20$(CXX)=20for=20=20=20generating=20file=20de?= =?UTF-8?q?pendencies=20(thanks=20to=20Andreas=20Brachold).=20-=20Moved=20?= =?UTF-8?q?the=20initialization=20of=20aPid1=20and=20aPid2=20to=20the=20be?= =?UTF-8?q?ginning=20of=20cDvbDevice::cDvbDevice()=20=20=20to=20have=20the?= =?UTF-8?q?m=20set=20in=20case=20a=20patch=20references=20them=20(thanks?= =?UTF-8?q?=20to=20Wayne=20Keer=20for=20pointing=20=20=20this=20out).=20-?= =?UTF-8?q?=20Completed=20the=20Russian=20OSD=20texts=20(thanks=20to=20Vya?= =?UTF-8?q?cheslav=20Dikonov).=20-=20Avoiding=20unnecessary=20section=20fi?= =?UTF-8?q?lter=20start/stops=20(thanks=20to=20Marco=20Schl=C3=BC=C3=9Fler?= =?UTF-8?q?).=20-=20Made=20the=20"Channel=20not=20available!"=20message=20?= =?UTF-8?q?and=20mtInfo=20instead=20of=20mtError=20(suggested=20=20=20by?= =?UTF-8?q?=20Wayne=20Keer).=20-=20Made=20volume=20control=20more=20linear?= =?UTF-8?q?=20(thanks=20to=20Emil=20Naepflein=20and=20Udo=20Richter).=20-?= =?UTF-8?q?=20Now=20skipping=20code=20table=20info=20in=20SI=20data=20(sug?= =?UTF-8?q?gested=20by=20Milos=20Kapoun).=20-=20Added=20missing=20Czech=20?= =?UTF-8?q?characters=20to=20fontosd-iso8859-2.c=20(thanks=20to=20Milos=20?= =?UTF-8?q?Kapoun).=20-=20Fixed=20a=20crash=20in=20the=20time=20search=20m?= =?UTF-8?q?echanism=20(reported=20by=20Reinhard=20Nissl).=20-=20If=20one?= =?UTF-8?q?=20PID=20can't=20be=20added,=20the=20whole=20cDevice::AttachRec?= =?UTF-8?q?eiver()=20will=20now=20fail=20=20=20and=20all=20PIDs=20added=20?= =?UTF-8?q?so=20far=20will=20be=20deleted=20(thanks=20to=20Marco=20Schl?= =?UTF-8?q?=C3=BC=C3=9Fler=20for=20=20=20pointing=20out=20this=20one).=20-?= =?UTF-8?q?=20Now=20only=20saving=20channels.conf=20after=20a=20modificati?= =?UTF-8?q?on=20made=20by=20the=20user=20(avoids=20=20=20lots=20of=20disk?= =?UTF-8?q?=20access=20due=20to=20automatic=20channel=20updates).=20Automa?= =?UTF-8?q?tic=20channel=20=20=20modifications=20will=20be=20saved=20every?= =?UTF-8?q?=2010=20minutes=20if=20no=20recording=20is=20currently=20=20=20?= =?UTF-8?q?active.=20-=20Removed=20the=20'Log'=20parameter=20from=20the=20?= =?UTF-8?q?cChannel::Set...=20functions.=20Instead=20=20=20checking=20if?= =?UTF-8?q?=20the=20channel=20has=20a=20non-zero=20number.=20-=20Updated?= =?UTF-8?q?=20'channels.conf.terr'=20for=20Hannover=20(thanks=20to=20Sven?= =?UTF-8?q?=20Kreiensen).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remux.c | 328 +++++++++++++++++++++++++++------------------------------------- 1 file changed, 137 insertions(+), 191 deletions(-) (limited to 'remux.c') diff --git a/remux.c b/remux.c index 65544b5..9b3b286 100644 --- a/remux.c +++ b/remux.c @@ -8,63 +8,9 @@ * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit * VDR's needs. * - * $Id: remux.c 1.18 2004/02/14 10:40:37 kls Exp $ + * $Id: remux.c 1.19 2004/10/16 09:11:52 kls Exp $ */ -/* The calling interface of the 'cRemux::Process()' function is defined - as follows: - - 'Data' points to a chunk of data that consists of 'Count' bytes. - The 'Process' function shall try to remultiplex as much of the - data as possible and return a pointer to the resulting buffer. - That buffer typically is different from the incoming 'Data', - but in the simplest case (when 'Process' does nothing) might - as well point to the original 'Data'. When returning, 'Count' - shall be set to the number of bytes that have been processed - (i.e. have been taken from 'Data'), while 'Result' indicates - how many bytes the returned buffer contains. 'PictureType' shall - be set to NO_PICTURE if the returned data does not start a new - picture, or one of I_FRAME, P_FRAME or B_FRAME if a new picture - starting point has been found. This also means that the returned - data buffer may contain at most one entire video frame, because - the next frame must be returned with its own value for 'PictureType'. - - 'Process' shall do it's best to keep the latency time as short - as possible in order to allow a quick start of VDR's "Transfer - mode" (displaying the signal of one DVB card on another card). - In order to do that, this function may decide to first pass - through the incoming data (almost) unprocessed, and make - actual processing kick in after a few seconds (if that is at - all possible for the algorithm). This may result in a non- - optimal stream at the beginning, which won't matter for normal - recordings but may make switching through encrypted channels - in "Transfer mode" faster. - - In the resulting data stream, a new packet shall always be started - when a frame border is encountered. VDR needs this in order to - be able to detect and store the frame indexes, and to easily - display single frames in fast forward/back mode. The very first - data block returned shall be the starting point of an I_FRAME. - Everything before that shall be silently dropped. - - If the incoming data is not enough to do remultiplexing, a value - of NULL shall be returned ('Result' has no meaning then). This - will tell the caller to wait for more data to be presented in - the next call. If NULL is returned and 'Count' is not 0, the - caller shall remove 'Count' bytes from the beginning of 'Data' - before the next call. This is the way 'Process' indicates that - it must skip that data. - - Any data that is not used during this call will appear at the - beginning of the incoming 'Data' buffer at the next call, plus - any new data that has become available. - - It is guaranteed that the caller will completely process any - returned data before the next call to 'Process'. That way, 'Process' - can dynamically allocate its return buffer and be sure the caller - doesn't keep any pointers into that buffer. -*/ - #include "remux.h" #include #include "thread.h" @@ -133,8 +79,7 @@ private: uint8_t check; int which; bool done; - uint8_t *resultBuffer; - int *resultCount; + cRingBufferLinear *resultBuffer; int tsErrors; int ccErrors; int ccCounter; @@ -145,7 +90,7 @@ private: void write_ipack(const uint8_t *Data, int Count); void instant_repack(const uint8_t *Buf, int Count); public: - cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid = 0x00); + cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid = 0x00); ~cTS2PES(); void ts_to_pes(const uint8_t *Buf); // don't need count (=188) void Clear(void); @@ -153,10 +98,9 @@ public: uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 }; -cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid) +cTS2PES::cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid) { resultBuffer = ResultBuffer; - resultCount = ResultCount; size = Size; audioCid = AudioCid; @@ -184,12 +128,9 @@ void cTS2PES::Clear(void) void cTS2PES::store(uint8_t *Data, int Count) { - if (*resultCount + Count > RESULTBUFFERSIZE) { - esyslog("ERROR: result buffer overflow (%d + %d > %d)", *resultCount, Count, RESULTBUFFERSIZE); - Count = RESULTBUFFERSIZE - *resultCount; - } - memcpy(resultBuffer + *resultCount, Data, Count); - *resultCount += Count; + int n = resultBuffer->Put(Data, Count); + if (n != Count) + esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Count - n, Count); } void cTS2PES::reset_ipack(void) @@ -452,6 +393,8 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188) // --- cRemux ---------------------------------------------------------------- +#define RESULTBUFFERSIZE KILOBYTE(256) + cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure) { vPid = VPid; @@ -463,13 +406,15 @@ cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOn numUPTerrors = 0; synced = false; skipped = 0; - resultCount = resultDelivered = 0; - vTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS); - aTS2PES1 = new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0); - aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL; - dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : NULL; + resultSkipped = 0; + resultBuffer = new cRingBufferLinear(RESULTBUFFERSIZE, IPACKS, false, "Result"); + resultBuffer->SetTimeouts(0, 100); + vTS2PES = new cTS2PES(resultBuffer, IPACKS); + aTS2PES1 = new cTS2PES(resultBuffer, IPACKS, 0xC0); + aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, IPACKS, 0xC1) : NULL; + dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, IPACKS) : NULL; //XXX don't yet know how to tell apart primary and secondary DD data... - dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : XXX*/ NULL; + dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, IPACKS) : XXX*/ NULL; } cRemux::~cRemux() @@ -479,6 +424,7 @@ cRemux::~cRemux() delete aTS2PES2; delete dTS2PES1; delete dTS2PES2; + delete resultBuffer; } int cRemux::GetPid(const uchar *Data) @@ -488,27 +434,32 @@ int cRemux::GetPid(const uchar *Data) int cRemux::GetPacketLength(const uchar *Data, int Count, int Offset) { - // Returns the entire length of the packet starting at offset, or -1 in case of error. - return (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1; + // Returns the length of the packet starting at Offset, or -1 if Count is + // too small to contain the entire packet. + int Length = (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1; + if (Length > 0 && Offset + Length <= Count) + return Length; + return -1; } int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType) { // Scans the video packet starting at Offset and returns its length. // If the return value is -1 the packet was not completely in the buffer. - int Length = GetPacketLength(Data, Count, Offset); - if (Length > 0 && Offset + Length <= Count) { - int i = Offset + 8; // the minimum length of the video packet header - i += Data[i] + 1; // possible additional header bytes - for (; i < Offset + Length; i++) { - if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { - switch (Data[i + 3]) { - case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07; - return Length; - } + if (Length > 0) { + if (Length >= 8) { + int i = Offset + 8; // the minimum length of the video packet header + i += Data[i] + 1; // possible additional header bytes + for (; i < Offset + Length; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07; + return Length; + } + } } - } + } PictureType = NO_PICTURE; return Length; } @@ -517,28 +468,8 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic #define TS_SYNC_BYTE 0x47 -uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar *PictureType) +int cRemux::Put(const uchar *Data, int Count) { - uchar dummyPictureType; - if (!PictureType) - PictureType = &dummyPictureType; - -/*XXX - // test recording the raw TS: - Result = Count; - *PictureType = I_FRAME; - return Data; -XXX*/ - - // Remove any previously delivered data from the result buffer: - - if (resultDelivered) { - if (resultDelivered < resultCount) - memmove(resultBuffer, resultBuffer + resultDelivered, resultCount - resultDelivered); - resultCount -= resultDelivered; - resultDelivered = 0; - } - int used = 0; // Make sure we are looking at a TS packet: @@ -560,6 +491,8 @@ XXX*/ break; if (Data[i] != TS_SYNC_BYTE) break; + if (resultBuffer->Free() < IPACKS) + break; int pid = GetPid(Data + i + 1); if (Data[i + 3] & 0x10) { // got payload if (pid == vPid) vTS2PES->ts_to_pes(Data + i); @@ -569,31 +502,9 @@ XXX*/ else if (pid == dPid2 && dTS2PES2) dTS2PES2->ts_to_pes(Data + i); } used += TS_SIZE; - if (resultCount > (int)sizeof(resultBuffer) / 2) - break; } - Count = used; - -/*XXX - // test recording without determining the real frame borders: - *PictureType = I_FRAME; - Result = resultDelivered = resultCount; - return Result ? resultBuffer : NULL; -XXX*/ - - // Special VPID case to enable recording radio channels: - - if (vPid == 0 || vPid == 1 || vPid == 0x1FFF) { - // XXX actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?) - // XXX also allowing 0x1FFF to not break Michael Paar's original patch, - // XXX but it would probably be best to only use '0' - *PictureType = I_FRAME; - Result = resultDelivered = resultCount; - return Result ? resultBuffer : NULL; - } // Check if we're getting anywhere here: - if (!synced && skipped >= 0) { if (skipped > MAXNONUSEFULDATA) { esyslog("ERROR: no useful data seen within %d byte of video stream", skipped); @@ -602,77 +513,112 @@ XXX*/ cThread::EmergencyExit(true); } else - skipped += Count; + skipped += used; + } + + return used; +} + +uchar *cRemux::Get(int &Count, uchar *PictureType) +{ + // Remove any previously skipped data from the result buffer: + + if (resultSkipped > 0) { + resultBuffer->Del(resultSkipped); + resultSkipped = 0; + } + +#if 0 + // Test recording without determining the real frame borders: + if (PictureType) + *PictureType = I_FRAME; + return resultBuffer->Get(Count); +#endif + + // Special VPID case to enable recording radio channels: + + if (vPid == 0 || vPid == 1 || vPid == 0x1FFF) { + // XXX actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?) + // XXX also allowing 0x1FFF to not break Michael Paar's original patch, + // XXX but it would probably be best to only use '0' + if (PictureType) + *PictureType = I_FRAME; + return resultBuffer->Get(Count); } // Check for frame borders: - *PictureType = NO_PICTURE; - - if (resultCount >= MINVIDEODATA) { - for (int i = 0; i < resultCount; i++) { - if (resultBuffer[i] == 0 && resultBuffer[i + 1] == 0 && resultBuffer[i + 2] == 1) { - switch (resultBuffer[i + 3]) { - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - { - uchar pt = NO_PICTURE; - int l = ScanVideoPacket(resultBuffer, resultCount, i, pt); - if (l < 0) - return NULL; // no useful data found, wait for more - if (pt != NO_PICTURE) { - if (pt < I_FRAME || B_FRAME < pt) { - esyslog("ERROR: unknown picture type '%d'", pt); - if (++numUPTerrors > MAXNUMUPTERRORS && exitOnFailure) - cThread::EmergencyExit(true); - } - else if (!synced) { - if (pt == I_FRAME) { - resultDelivered = i; // will drop everything before this position - SetBrokenLink(resultBuffer + i, l); - synced = true; - } - else { - resultDelivered = i + l; // will drop everything before and including this packet - return NULL; - } - } - } - if (synced) { - *PictureType = pt; - Result = l; - uchar *p = resultBuffer + resultDelivered; - resultDelivered += l; - return p; - } - else { - resultDelivered = i + l; // will drop everything before and including this packet - return NULL; - } - } - break; - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - { - int l = GetPacketLength(resultBuffer, resultCount, i); - if (l < 0) - return NULL; // no useful data found, wait for more - if (synced) { - Result = l; - uchar *p = resultBuffer + resultDelivered; - resultDelivered += l; - return p; - } - else { - resultDelivered = i + l; // will drop everything before and including this packet - return NULL; + if (PictureType) + *PictureType = NO_PICTURE; + + Count = 0; + uchar *resultData = NULL; + int resultCount = 0; + uchar *data = resultBuffer->Get(resultCount); + if (data) { + for (int i = 0; i < resultCount - 3; i++) { + if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) { + int l = 0; + uchar StreamType = data[i + 3]; + if (VIDEO_STREAM_S <= StreamType && StreamType <= VIDEO_STREAM_E) { + uchar pt = NO_PICTURE; + l = ScanVideoPacket(data, resultCount, i, pt); + if (l < 0) + return resultData; + if (pt != NO_PICTURE) { + if (pt < I_FRAME || B_FRAME < pt) { + esyslog("ERROR: unknown picture type '%d'", pt); + if (++numUPTerrors > MAXNUMUPTERRORS && exitOnFailure) + cThread::EmergencyExit(true); + } + else if (!synced) { + if (pt == I_FRAME) { + if (PictureType) + *PictureType = pt; + resultSkipped = i; // will drop everything before this position + SetBrokenLink(data + i, l); + synced = true; } - } - break; - } + } + else if (Count) + return resultData; + else if (PictureType) + *PictureType = pt; + } + } + else { //if (AUDIO_STREAM_S <= StreamType && StreamType <= AUDIO_STREAM_E || StreamType == PRIVATE_STREAM1) { + l = GetPacketLength(data, resultCount, i); + if (l < 0) + return resultData; + } + if (synced) { + if (!Count) + resultData = data + i; + Count += l; + } + else + resultSkipped = i; + if (l > 0) + i += l - 1; // the loop increments, too } } } - return NULL; // no useful data found, wait for more + return resultData; +} + +void cRemux::Del(int Count) +{ + resultBuffer->Del(Count); +} + +void cRemux::Clear(void) +{ + if (vTS2PES) vTS2PES->Clear(); + if (aTS2PES1) aTS2PES1->Clear(); + if (aTS2PES2) aTS2PES2->Clear(); + if (dTS2PES1) dTS2PES1->Clear(); + if (dTS2PES2) dTS2PES2->Clear(); + resultBuffer->Clear(); } void cRemux::SetBrokenLink(uchar *Data, int Length) -- cgit v1.2.3