From c23992b807aca1cea08193b773f80eee0cb8f829 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 5 Feb 2006 18:00:00 +0100 Subject: =?UTF-8?q?Version=201.3.42=20-=20Removed=20leftover=20'needsBuffe?= =?UTF-8?q?rReserve'=20variable=20from=20cTransfer=20(thanks=20to=20Marco?= =?UTF-8?q?=20=20=20Schl=C3=BC=C3=9Fler).=20-=20Fixed=20setting=20"No=20ti?= =?UTF-8?q?tle"=20for=20broken=20event=20data=20(reported=20by=20Ronny=20K?= =?UTF-8?q?ornexl).=20-=20Fixed=20channel=20up/down=20switching=20on=20sin?= =?UTF-8?q?gle=20card=20systems=20(reported=20by=20Stefan=20=20=20Huelswit?= =?UTF-8?q?t).=20-=20Fixed=20handling=20"pending"=20timers=20that=20blocke?= =?UTF-8?q?d=20others=20that=20actually=20could=20record=20=20=20(reported?= =?UTF-8?q?=20by=20Thomas=20Koch).=20-=20Speeded=20up=20cVideoRepacker=20(?= =?UTF-8?q?thanks=20to=20Reinhard=20Nissl).=20-=20Added=20an=20'Id'=20para?= =?UTF-8?q?meter=20to=20cDevice::PlayAudio()=20to=20allow=20plugins=20to?= =?UTF-8?q?=20easier=20=20=20process=20the=20audio=20data=20(thanks=20to?= =?UTF-8?q?=20Marco=20Schl=C3=BC=C3=9Fler).=20-=20Added=20Czech=20language?= =?UTF-8?q?=20texts=20(thanks=20to=20Vladim=C3=ADr=20B=C3=A1rta).=20=20=20?= =?UTF-8?q?Plugin=20authors=20may=20want=20to=20add=20the=20new=20entries?= =?UTF-8?q?=20to=20their=20I18N=20texts=20and=20contact=20=20=20the=20tran?= =?UTF-8?q?slators=20to=20have=20their=20texts=20translated.=20Note=20that?= =?UTF-8?q?=20there=20are=20now=2021=20=20=20different=20OSD=20languages,?= =?UTF-8?q?=20so=20please=20make=20sure=20you=20have=2021=20versions=20for?= =?UTF-8?q?=20each=20of=20=20=20your=20texts.=20-=20Updated=20the=20Polish?= =?UTF-8?q?=20OSD=20texts=20(thanks=20to=20Jaroslaw=20Swierczynski).=20-?= =?UTF-8?q?=20Fixed=20auto=20advance=20in=20string=20entry=20fields=20when?= =?UTF-8?q?=20pressing=20Up/Down=20in=20insert=20mode=20=20=20(reported=20?= =?UTF-8?q?by=20Udo=20Richter).=20-=20Fixed=20handling=20the=20"Setup/OSD/?= =?UTF-8?q?Menu=20button=20closes"=20option=20when=20set=20to=20'yes'=20in?= =?UTF-8?q?=20=20=20case=20a=20replay=20is=20active=20(thanks=20to=20Udo?= =?UTF-8?q?=20Richter).=20-=20Improved=20cUnbufferedFile;=20USE=5FFADVISE?= =?UTF-8?q?=20is=20now=20defined=20in=20tools.c=20by=20default,=20so=20=20?= =?UTF-8?q?=20if=20you=20don't=20want=20to=20use=20"fadvise"=20you=20need?= =?UTF-8?q?=20to=20comment=20out=20that=20line=20(thanks=20to=20=20=20Artu?= =?UTF-8?q?r=20Skawina).=20-=20Fixed=20a=20missing=20','=20in=20the=20Swed?= =?UTF-8?q?ish=20OSD=20texts=20(thanks=20to=20Arthur=20Konovalov).=20-=20c?= =?UTF-8?q?Device::Transferring()=20can=20now=20be=20used=20to=20determine?= =?UTF-8?q?=20whether=20the=20(primary)=20=20=20device=20is=20currently=20?= =?UTF-8?q?playing=20in=20Transfer=20Mode=20(based=20on=20a=20suggestion?= =?UTF-8?q?=20by=20=20=20Reinhard=20Nissl).=20-=20The=20'runvdr'=20script?= =?UTF-8?q?=20no=20longer=20uses=20the=20$VDRUSR=20environment=20variable?= =?UTF-8?q?=20to=20set=20=20=20the=20user=20id=20under=20which=20'vdr'=20s?= =?UTF-8?q?hall=20run.=20Just=20add=20the=20'-u=20username'=20option=20=20?= =?UTF-8?q?=20when=20you=20call=20'runvdr'.=20-=20Fixed=20multiple=20entri?= =?UTF-8?q?es=20of=20the=20same=20subdirectory=20in=20the=20"Recordings"?= =?UTF-8?q?=20menu=20=20=20(reported=20by=20Christian=20Jacobsen).=20-=20E?= =?UTF-8?q?nabled=20generating=20a=20core=20dump=20if=20VDR=20is=20run=20w?= =?UTF-8?q?ith=20a=20different=20user=20id=20(thanks=20=20=20to=20Ville=20?= =?UTF-8?q?Skytt=C3=A4).=20-=20Fixed=20handling=20the=20"Blue"=20key=20in?= =?UTF-8?q?=20the=20"Schedule"=20menu=20for=20the=20current=20channel=20?= =?UTF-8?q?=20=20(thanks=20to=20Rolf=20Ahrenberg).=20-=20Renamed=20the=20M?= =?UTF-8?q?akefile=20target=20'plugins-clean'=20to=20'clean-plugins'=20(su?= =?UTF-8?q?ggested=20by=20=20=20Sebastian=20Frei).=20-=20Made=20all=20font?= =?UTF-8?q?=20and=20image=20data=20'const'=20(thanks=20to=20Darren=20Salt)?= =?UTF-8?q?.=20-=20Fixed=20scrolling=20with=20Up/Down=20in=20case=20there?= =?UTF-8?q?=20are=20non-selectable=20items=20at=20the=20=20=20beginning=20?= =?UTF-8?q?or=20end=20of=20the=20menu=20(reported=20by=20Helmut=20Auer).?= =?UTF-8?q?=20-=20Added=20cSkin::GetTextAreaWidth()=20and=20cSkin::GetText?= =?UTF-8?q?AreaFont(),=20so=20that=20a=20plugin=20=20=20that=20wants=20to?= =?UTF-8?q?=20do=20special=20text=20formatting=20can=20do=20so=20(thanks?= =?UTF-8?q?=20to=20Alexander=20Rieger).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remux.c | 349 ++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 243 insertions(+), 106 deletions(-) (limited to 'remux.c') diff --git a/remux.c b/remux.c index c48e5f9..31ad719 100644 --- a/remux.c +++ b/remux.c @@ -11,7 +11,7 @@ * The cRepacker family's code was originally written by Reinhard Nissl , * and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de. * - * $Id: remux.c 1.53 2006/01/08 11:40:16 kls Exp $ + * $Id: remux.c 1.54 2006/02/03 16:19:02 kls Exp $ */ #include "remux.h" @@ -248,6 +248,14 @@ private: scanPicture }; int state; + void HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel); + inline bool ScanDataForStartCodeSlow(const uchar *const Data); + inline bool ScanDataForStartCodeFast(const uchar *&Data, const uchar *Limit); + inline bool ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo); + inline void AdjustCounters(const int Delta, int &Done, int &Todo); + inline bool ScanForEndOfPictureSlow(const uchar *&Data); + inline bool ScanForEndOfPictureFast(const uchar *&Data, const uchar *Limit); + inline bool ScanForEndOfPicture(const uchar *&Data, const uchar *Limit); public: cVideoRepacker(void); virtual void Reset(void); @@ -267,6 +275,162 @@ void cVideoRepacker::Reset(void) state = syncing; } +void cVideoRepacker::HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel) +{ + // synchronisation is detected some bytes after frame start. + const int SkippedBytesLimit = 4; + + // which kind of start code have we got? + switch (*Data) { + case 0xB9 ... 0xFF: // system start codes + LOG("cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed"); + break; + case 0xB0 ... 0xB1: // reserved start codes + case 0xB6: + LOG("cVideoRepacker: found reserved start code: stream seems to be scrambled"); + break; + case 0xB4: // sequence error code + LOG("cVideoRepacker: found sequence error code: stream seems to be damaged"); + case 0xB2: // user data start code + case 0xB5: // extension start code + break; + case 0xB7: // sequence end code + case 0xB3: // sequence header code + case 0xB8: // group start code + case 0x00: // picture start code + if (state == scanPicture) { + // the above start codes indicate that the current picture is done. So + // push out the packet to start a new packet for the next picuture. If + // the byte count get's negative then the current buffer ends in a + // partitial start code that must be stripped off, as it shall be put + // in the next packet. + PushOutPacket(ResultBuffer, Payload, Data - 3 - Payload); + // go on with syncing to the next picture + state = syncing; + } + if (state == syncing) { + if (initiallySyncing) // omit report for the typical initial case + initiallySyncing = false; + else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes + LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit); + skippedBytes = 0; + // if there is a PES header available, then use it ... + if (pesHeaderBackupLen > 0) { + // ISO 13818-1 says: + // In the case of video, if a PTS is present in a PES packet header + // it shall refer to the access unit containing the first picture start + // code that commences in this PES packet. A picture start code commences + // in PES packet if the first byte of the picture start code is present + // in the PES packet. + memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen); + pesHeaderLen = pesHeaderBackupLen; + pesHeaderBackupLen = 0; + } + else { + // ... otherwise create a continuation PES header + pesHeaderLen = 0; + pesHeader[pesHeaderLen++] = 0x00; + pesHeader[pesHeaderLen++] = 0x00; + pesHeader[pesHeaderLen++] = 0x01; + pesHeader[pesHeaderLen++] = StreamID; // video stream ID + pesHeader[pesHeaderLen++] = 0x00; // length still unknown + pesHeader[pesHeaderLen++] = 0x00; // length still unknown + + if (MpegLevel == phMPEG2) { + pesHeader[pesHeaderLen++] = 0x80; + pesHeader[pesHeaderLen++] = 0x00; + pesHeader[pesHeaderLen++] = 0x00; + } + else + pesHeader[pesHeaderLen++] = 0x0F; + } + // append the first three bytes of the start code + pesHeader[pesHeaderLen++] = 0x00; + pesHeader[pesHeaderLen++] = 0x00; + pesHeader[pesHeaderLen++] = 0x01; + // the next packet's payload will begin with the fourth byte of + // the start code (= the actual code) + Payload = Data; + // as there is no length information available, assume the + // maximum we can hold in one PES packet + packetTodo = maxPacketSize - pesHeaderLen; + // go on with finding the picture data + state++; + } + break; + case 0x01 ... 0xAF: // slice start codes + if (state == findPicture) { + // go on with scanning the picture data + state++; + } + break; + } +} + +bool cVideoRepacker::ScanDataForStartCodeSlow(const uchar *const Data) +{ + scanner <<= 8; + bool FoundStartCode = (scanner == 0x00000100); + scanner |= *Data; + return FoundStartCode; +} + +bool cVideoRepacker::ScanDataForStartCodeFast(const uchar *&Data, const uchar *Limit) +{ + Limit--; + + while (Data < Limit && (Data = (const uchar *)memchr(Data, 0x01, Limit - Data))) { + if (Data[-2] || Data[-1]) + Data += 3; + else { + scanner = 0x00000100 | *++Data; + return true; + } + } + + Data = Limit; + unsigned long *Scanner = (unsigned long *)(Data - 3); + scanner = ntohl(*Scanner); + return false; +} + +bool cVideoRepacker::ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo) +{ + const uchar *const DataOrig = Data; + const int MinDataSize = 4; + + if (Todo < MinDataSize || (state != syncing && packetTodo < MinDataSize)) + return ScanDataForStartCodeSlow(Data); + + int Limit = Todo; + if (state != syncing && Limit > packetTodo) + Limit = packetTodo; + + if (ScanDataForStartCodeSlow(Data)) + return true; + + if (ScanDataForStartCodeSlow(++Data)) { + AdjustCounters(1, Done, Todo); + return true; + } + ++Data; + + bool FoundStartCode = ScanDataForStartCodeFast(Data, DataOrig + Limit); + AdjustCounters(Data - DataOrig, Done, Todo); + return FoundStartCode; +} + +void cVideoRepacker::AdjustCounters(const int Delta, int &Done, int &Todo) +{ + Done += Delta; + Todo -= Delta; + + if (state <= syncing) + skippedBytes += Delta; + else + packetTodo -= Delta; +} + void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) { // synchronisation is detected some bytes after frame start. @@ -300,98 +464,9 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, if (state <= syncing) skippedBytes++; // did we reach a start code? - scanner <<= 8; - if (scanner != 0x00000100) - scanner |= *data; - else { - scanner |= *data; - - // which kind of start code have we got? - switch (*data) { - case 0xB9 ... 0xFF: // system start codes - LOG("cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed"); - break; - case 0xB0 ... 0xB1: // reserved start codes - case 0xB6: - LOG("cVideoRepacker: found reserved start code: stream seems to be scrambled"); - break; - case 0xB4: // sequence error code - LOG("cVideoRepacker: found sequence error code: stream seems to be damaged"); - case 0xB2: // user data start code - case 0xB5: // extension start code - break; - case 0xB7: // sequence end code - case 0xB3: // sequence header code - case 0xB8: // group start code - case 0x00: // picture start code - if (state == scanPicture) { - // the above start codes indicate that the current picture is done. So - // push out the packet to start a new packet for the next picuture. If - // the byte count get's negative then the current buffer ends in a - // partitial start code that must be stripped off, as it shall be put - // in the next packet. - PushOutPacket(ResultBuffer, payload, data - 3 - payload); - // go on with syncing to the next picture - state = syncing; - } - if (state == syncing) { - if (initiallySyncing) // omit report for the typical initial case - initiallySyncing = false; - else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes - LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit); - skippedBytes = 0; - // if there is a PES header available, then use it ... - if (pesHeaderBackupLen > 0) { - // ISO 13818-1 says: - // In the case of video, if a PTS is present in a PES packet header - // it shall refer to the access unit containing the first picture start - // code that commences in this PES packet. A picture start code commences - // in PES packet if the first byte of the picture start code is present - // in the PES packet. - memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen); - pesHeaderLen = pesHeaderBackupLen; - pesHeaderBackupLen = 0; - } - else { - // ... otherwise create a continuation PES header - pesHeaderLen = 0; - pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x01; - pesHeader[pesHeaderLen++] = Data[3]; // video stream ID - pesHeader[pesHeaderLen++] = 0x00; // length still unknown - pesHeader[pesHeaderLen++] = 0x00; // length still unknown - - if (mpegLevel == phMPEG2) { - pesHeader[pesHeaderLen++] = 0x80; - pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x00; - } - else - pesHeader[pesHeaderLen++] = 0x0F; - } - // append the first three bytes of the start code - pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x00; - pesHeader[pesHeaderLen++] = 0x01; - // the next packet's payload will begin with the fourth byte of - // the start code (= the actual code) - payload = data; - // as there is no length information available, assume the - // maximum we can hold in one PES packet - packetTodo = maxPacketSize - pesHeaderLen; - // go on with finding the picture data - state++; - } - break; - case 0x01 ... 0xAF: // slice start codes - if (state == findPicture) { - // go on with scanning the picture data - state++; - } - break; - } - } + if (ScanDataForStartCode(data, done, todo)) + HandleStartCode(data, ResultBuffer, payload, Data[3], mpegLevel); + // move on data++; done++; todo--; @@ -501,6 +576,79 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, } } +bool cVideoRepacker::ScanForEndOfPictureSlow(const uchar *&Data) +{ + localScanner <<= 8; + localScanner |= *Data++; + // check start codes which follow picture data + switch (localScanner) { + case 0x00000100: // picture start code + case 0x000001B8: // group start code + case 0x000001B3: // sequence header code + case 0x000001B7: // sequence end code + return true; + } + return false; +} + +bool cVideoRepacker::ScanForEndOfPictureFast(const uchar *&Data, const uchar *Limit) +{ + Limit--; + + while (Data < Limit && (Data = (const uchar *)memchr(Data, 0x01, Limit - Data))) { + if (Data[-2] || Data[-1]) + Data += 3; + else { + localScanner = 0x00000100 | *++Data; + // check start codes which follow picture data + switch (localScanner) { + case 0x00000100: // picture start code + case 0x000001B8: // group start code + case 0x000001B3: // sequence header code + case 0x000001B7: // sequence end code + Data++; + return true; + default: + Data += 3; + } + } + } + + Data = Limit + 1; + unsigned long *LocalScanner = (unsigned long *)(Data - 4); + localScanner = ntohl(*LocalScanner); + return false; +} + +bool cVideoRepacker::ScanForEndOfPicture(const uchar *&Data, const uchar *Limit) +{ + const uchar *const DataOrig = Data; + const int MinDataSize = 4; + bool FoundEndOfPicture; + + if (Limit - Data <= MinDataSize) { + FoundEndOfPicture = false; + while (Data < Limit) { + if (ScanForEndOfPictureSlow(Data)) { + FoundEndOfPicture = true; + break; + } + } + } + else { + FoundEndOfPicture = true; + if (!ScanForEndOfPictureSlow(Data)) { + if (!ScanForEndOfPictureSlow(Data)) { + if (!ScanForEndOfPictureFast(Data, Limit)) + FoundEndOfPicture = false; + } + } + } + + localStart += (Data - DataOrig); + return FoundEndOfPicture; +} + int cVideoRepacker::BreakAt(const uchar *Data, int Count) { if (initiallySyncing) @@ -522,19 +670,8 @@ int cVideoRepacker::BreakAt(const uchar *Data, int Count) const uchar *data = Data + PesPayloadOffset + localStart; const uchar *limit = Data + Count; // scan data - while (data < limit) { - localStart++; - localScanner <<= 8; - localScanner |= *data++; - // check start codes which follow picture data - switch (localScanner) { - case 0x00000100: // picture start code - case 0x000001B8: // group start code - case 0x000001B3: // sequence header code - case 0x000001B7: // sequence end code - return data - Data; - } - } + if (ScanForEndOfPicture(data, limit)) + return data - Data; } // just fill up packet and append next start code return PesPayloadOffset + packetTodo + 4; -- cgit v1.2.3