From c848ab793a302dc067663ec4a06395745e443c9d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 6 Sep 2008 18:00:00 +0200 Subject: =?UTF-8?q?Version=201.7.1=20-=20Adapted=20the=20tuning=20code=20t?= =?UTF-8?q?o=20the=20new=20DVBFE=5FSET=5FDELSYS=20API=20(thanks=20to=20Rei?= =?UTF-8?q?nhard=20Nissl).=20=20=20VDR=20now=20uses=20the=20driver=20from?= =?UTF-8?q?=20http://jusst.de/hg/multiproto=5Fplus.=20-=20Updated=20the=20?= =?UTF-8?q?Italian=20OSD=20texts=20(thanks=20to=20Diego=20Pierotto).=20-?= =?UTF-8?q?=20Removed=20obsolete=20$(NCURSESLIB)=20from=20the=20Makefile.?= =?UTF-8?q?=20-=20Implemented=20handling=20the=20standard=20component=20de?= =?UTF-8?q?scriptor=20for=20AC3=20(stream=3D4),=20as=20it=20=20=20will=20s?= =?UTF-8?q?oon=20be=20used=20by=20the=20German=20ARD=20channels=20(thanks?= =?UTF-8?q?=20to=20Michael=20Pennewi=C3=9F=20for=20=20=20advance=20informa?= =?UTF-8?q?tion=20about=20this=20change).=20The=20previously=20used=20"Pre?= =?UTF-8?q?miere=20pseudo=20=20=20standard"=20(stream=3D2,=20type=3D5)=20s?= =?UTF-8?q?till=20works,=20but=20has=20apparently=20been=20wrongfully=20us?= =?UTF-8?q?ed=20=20=20by=20broadcasters=20from=20the=20beginning.=20-=20Ad?= =?UTF-8?q?ded=20missing=20description=20of=20the=20'S'=20channel=20parame?= =?UTF-8?q?ter=20to=20vdr.5=20(reported=20by=20=20=20Reinhard=20Nissl).=20?= =?UTF-8?q?-=20The=20SVDRP=20signon=20message=20now=20indicates=20the=20ch?= =?UTF-8?q?aracter=20encoding=20in=20use,=20as=20in=20=20=20"220=20video?= =?UTF-8?q?=20SVDRP=20VideoDiskRecorder=201.7.1;=20Fri=20May=20=202=2016:1?= =?UTF-8?q?7:10=202008;=20ISO-8859-1".=20=20=20This=20may=20be=20useful=20?= =?UTF-8?q?for=20instance=20for=20external=20tools=20that=20provide=20EPG?= =?UTF-8?q?=20data,=20so=20that=20=20=20they=20can=20correctly=20encode=20?= =?UTF-8?q?the=20strings.=20-=20No=20longer=20calling=20FcFini()=20to=20av?= =?UTF-8?q?oid=20problems=20with=20older=20(broken)=20versions=20of=20=20?= =?UTF-8?q?=20fontconfig=20(suggested=20by=20Edgar=20Toernig).=20-=20Remov?= =?UTF-8?q?ed=20the=20compile=20time=20option=20VFAT=20to=20allow=20users?= =?UTF-8?q?=20of=20precompiled=20binary=20=20=20distributions=20to=20have?= =?UTF-8?q?=20full=20control=20over=20whether=20or=20not=20to=20use=20the?= =?UTF-8?q?=20--vfat=20option=20=20=20at=20runtime=20(suggested=20by=20Mic?= =?UTF-8?q?hael=20Nork).=20-=20First=20step=20towards=20switching=20to=20T?= =?UTF-8?q?S=20(Transport=20Stream)=20as=20recording=20format:=20=20=20+?= =?UTF-8?q?=20The=20new=20function=20cDevice::PlayTs()=20is=20used=20to=20?= =?UTF-8?q?play=20TS=20packets.=20=20=20+=20The=20new=20functions=20cDevic?= =?UTF-8?q?e::PlayTsVideo()=20and=20cDevice::PlayTsAudio()=20=20=20=20=20a?= =?UTF-8?q?re=20used=20to=20play=20video=20and=20audio=20TS=20packets,=20r?= =?UTF-8?q?espectively.=20=20=20+=20The=20new=20function=20cAudio::PlayTs(?= =?UTF-8?q?)=20is=20used=20to=20play=20audio=20TS=20packets.=20=20=20+=20T?= =?UTF-8?q?he=20new=20class=20cPatPmtGenerator=20is=20used=20to=20generate?= =?UTF-8?q?=20a=20PAT/PMT=20pair=20that=20precedes=20=20=20=20=20the=20TS?= =?UTF-8?q?=20data=20in=20Transfer=20Mode.=20=20=20+=20The=20new=20class?= =?UTF-8?q?=20cPatPmtParser=20is=20used=20by=20cDevice=20to=20parse=20the?= =?UTF-8?q?=20PAT/PMT=20data=20in=20a=20=20=20=20=20TS=20in=20order=20to?= =?UTF-8?q?=20find=20out=20which=20streams=20it=20contains.=20=20=20+=20Th?= =?UTF-8?q?e=20new=20class=20cTsToPes=20is=20used=20to=20convert=20TS=20pa?= =?UTF-8?q?ckets=20to=20a=20PES=20packet.=20=20=20+=20cTransfer=20no=20lon?= =?UTF-8?q?ger=20uses=20cRemux,=20and=20doesn't=20run=20a=20separate=20thr?= =?UTF-8?q?ead=20any=20more.=20=20=20=20=20It=20just=20generates=20a=20PAT?= =?UTF-8?q?/PMT=20and=20sends=20all=20received=20TS=20packets=20to=20the?= =?UTF-8?q?=20primary=20=20=20=20=20device's=20PlayTs().=20=20=20+=20Live?= =?UTF-8?q?=20subtitle=20display=20no=20longer=20uses=20a=20ring=20buffer?= =?UTF-8?q?=20and=20separate=20thread.=20=20=20+=20cPesAssembler=20has=20b?= =?UTF-8?q?een=20removed.=20Old=20VDR=20recordings=20only=20contain=20comp?= =?UTF-8?q?lete=20PES=20=20=20=20=20packets.=20=20=20+=20Since=20a=20TS=20?= =?UTF-8?q?needs=20to=20have=20a=20PAT/PMT,=20which=20requires=20the=20vid?= =?UTF-8?q?eo=20stream=20type=20to=20=20=20=20=20be=20explicitly=20given,?= =?UTF-8?q?=20the=20format=20of=20the=20VPID=20field=20in=20the=20channels?= =?UTF-8?q?.conf=20file=20=20=20=20=20and=20the=20SVDRP=20commands=20NEWC/?= =?UTF-8?q?MODC/LSTC=20has=20been=20extended.=20The=20video=20stream=20typ?= =?UTF-8?q?e=20=20=20=20=20now=20follows=20the=20VPID=20and=20optional=20P?= =?UTF-8?q?PID,=20separated=20by=20an=20'=3D'=20sign.=20-=20Updated=20the?= =?UTF-8?q?=20sources.conf=20file=20(thanks=20to=20Oleg=20Roitburd).=20-?= =?UTF-8?q?=20Fixed=20a=20possible=20integer=20overflow=20in=20GetAbsTime(?= =?UTF-8?q?)=20(thanks=20to=20Alexander=20Rieger).=20-=20Fixed=20a=20probl?= =?UTF-8?q?em=20with=20calling=20isyslog()=20from=20within=20the=20SignalH?= =?UTF-8?q?andler()=20(thanks=20=20=20to=20Udo=20Richter).=20-=20Replaced?= =?UTF-8?q?=20the=20Finnish=20language=20code=20"smi"=20with=20"suo"=20(th?= =?UTF-8?q?anks=20to=20Rolf=20Ahrenberg).=20-=20Fixed=20wrong=20value=20fo?= =?UTF-8?q?r=20TableIdBAT=20in=20libsi/si.h=20(thanks=20to=20Winfried=20K?= =?UTF-8?q?=C3=B6hler).=20-=20Errors=20in=20config=20files=20no=20longer?= =?UTF-8?q?=20keep=20VDR=20from=20starting.=20-=20Removed=20unneeded=20inc?= =?UTF-8?q?lude=20files=20=20und=20=20from=20remu?= =?UTF-8?q?x.h=20=20=20(reported=20by=20Tobias=20Grimm).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remux.c | 477 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 473 insertions(+), 4 deletions(-) (limited to 'remux.c') diff --git a/remux.c b/remux.c index 6b42209..8312a74 100644 --- a/remux.c +++ b/remux.c @@ -11,15 +11,24 @@ * 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 2.0 2007/11/25 13:56:03 kls Exp $ + * $Id: remux.c 2.1 2008/08/15 14:49:34 kls Exp $ */ #include "remux.h" #include #include "channels.h" +#include "device.h" +#include "libsi/si.h" +#include "libsi/section.h" +#include "libsi/descriptor.h" #include "shutdown.h" #include "tools.h" +// Set this to 'true' for debug output: +static bool DebugPatPmt = false; + +#define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a) + ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader) { if (Count < 7) @@ -1413,7 +1422,6 @@ int cDolbyRepacker::BreakAt(const uchar *Data, int Count) //pts_dts flags #define PTS_ONLY 0x80 -#define TS_SIZE 188 #define PID_MASK_HI 0x1F #define CONT_CNT_MASK 0x0F @@ -2007,8 +2015,6 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic return -1; } -#define TS_SYNC_BYTE 0x47 - int cRemux::Put(const uchar *Data, int Count) { int used = 0; @@ -2182,3 +2188,466 @@ void cRemux::SetBrokenLink(uchar *Data, int Length) else dsyslog("SetBrokenLink: no video packet in frame"); } + +// --- cPatPmtGenerator ------------------------------------------------------ + +cPatPmtGenerator::cPatPmtGenerator(void) +{ + numPmtPackets = 0; + patCounter = pmtCounter = 0; + patVersion = pmtVersion = 0; + esInfoLength = NULL; + GeneratePat(); +} + +void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket) +{ + TsPacket[3] = (TsPacket[3] & 0xF0) | Counter; + if (++Counter > 0x0F) + Counter = 0x00; +} + +void cPatPmtGenerator::IncVersion(int &Version) +{ + if (++Version > 0x1F) + Version = 0x00; +} + +void cPatPmtGenerator::IncEsInfoLength(int Length) +{ + if (esInfoLength) { + Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1); + *esInfoLength = 0xF0 | (Length >> 8); + *(esInfoLength + 1) = Length; + } +} + +int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid) +{ + int i = 0; + Target[i++] = Type; // stream type + Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5) + Target[i++] = Pid; // pid lo + esInfoLength = &Target[i]; + Target[i++] = 0xF0; // dummy (4), ES info length hi + Target[i++] = 0x00; // ES info length lo + return i; +} + +int cPatPmtGenerator::MakeAC3Descriptor(uchar *Target) +{ + int i = 0; + Target[i++] = SI::AC3DescriptorTag; + Target[i++] = 0x01; // length + Target[i++] = 0x00; + IncEsInfoLength(i); + return i; +} + +int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language) +{ + int i = 0; + Target[i++] = SI::SubtitlingDescriptorTag; + Target[i++] = 0x08; // length + Target[i++] = *Language++; + Target[i++] = *Language++; + Target[i++] = *Language++; + Target[i++] = 0x00; // subtitling type + Target[i++] = 0x00; // composition page id hi + Target[i++] = 0x01; // composition page id lo + Target[i++] = 0x00; // ancillary page id hi + Target[i++] = 0x01; // ancillary page id lo + IncEsInfoLength(i); + return i; +} + +int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language) +{ + int i = 0; + Target[i++] = SI::ISO639LanguageDescriptorTag; + Target[i++] = 0x04; // length + Target[i++] = *Language++; + Target[i++] = *Language++; + Target[i++] = *Language++; + Target[i++] = 0x01; // audio type + IncEsInfoLength(i); + return i; +} + +int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length) +{ + int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF); + int i = 0; + Target[i++] = crc >> 24; + Target[i++] = crc >> 16; + Target[i++] = crc >> 8; + Target[i++] = crc; + return i; +} + +#define P_TSID 0x8008 // pseudo TS ID +#define P_PNR 0x0084 // pseudo Program Number +#define P_PMT_PID 0x0084 // pseudo PMT pid + +void cPatPmtGenerator::GeneratePat(void) +{ + memset(pat, 0xFF, sizeof(pat)); + uchar *p = pat; + int i = 0; + p[i++] = 0x47; // TS indicator + p[i++] = 0x40; // flags (3), pid hi (5) + p[i++] = 0x00; // pid lo + p[i++] = 0x10; // flags (4), continuity counter (4) + int PayloadStart = i; + p[i++] = 0x00; // table id + p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4) + int SectionLength = i; + p[i++] = 0x00; // section length lo (filled in later) + p[i++] = P_TSID >> 8; // TS id hi + p[i++] = P_TSID & 0xFF; // TS id lo + p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1) + p[i++] = 0x00; // section number + p[i++] = 0x00; // last section number + p[i++] = P_PNR >> 8; // program number hi + p[i++] = P_PNR & 0xFF; // program number lo + p[i++] = 0xE0 | (P_PMT_PID >> 8); // dummy (3), PMT pid hi (5) + p[i++] = P_PMT_PID & 0xFF; // PMT pid lo + pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC + MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart); + IncVersion(patVersion); +} + +void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) +{ + // generate the complete PMT section: + uchar buf[MAX_SECTION_SIZE]; + memset(buf, 0xFF, sizeof(buf)); + numPmtPackets = 0; + cChannel *Channel = Channels.GetByChannelID(ChannelID); + if (Channel) { + int Vpid = Channel->Vpid(); + uchar *p = buf; + int i = 0; + p[i++] = 0x02; // table id + int SectionLength = i; + p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4) + p[i++] = 0x00; // section length lo (filled in later) + p[i++] = P_PNR >> 8; // program number hi + p[i++] = P_PNR & 0xFF; // program number lo + p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1) + p[i++] = 0x00; // section number + p[i++] = 0x00; // last section number + p[i++] = 0xE0 | (Vpid >> 8); // dummy (3), PCR pid hi (5) + p[i++] = Vpid; // PCR pid lo + p[i++] = 0xF0; // dummy (4), program info length hi (4) + p[i++] = 0x00; // program info length lo + + if (Vpid) + i += MakeStream(buf + i, Channel->Vtype(), Vpid); + for (int n = 0; Channel->Apid(n); n++) { + i += MakeStream(buf + i, 0x04, Channel->Apid(n)); + const char *Alang = Channel->Alang(n); + i += MakeLanguageDescriptor(buf + i, Alang); + if (Alang[3] == '+') + i += MakeLanguageDescriptor(buf + i, Alang + 3); + } + for (int n = 0; Channel->Dpid(n); n++) { + i += MakeStream(buf + i, 0x06, Channel->Dpid(n)); + i += MakeAC3Descriptor(buf + i); + i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n)); + } + for (int n = 0; Channel->Spid(n); n++) { + i += MakeStream(buf + i, 0x06, Channel->Spid(n)); + i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n)); + } + + int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC + buf[SectionLength] |= (sl >> 8) & 0x0F; + buf[SectionLength + 1] = sl; + MakeCRC(buf + i, buf, i); + // split the PMT section into several TS packets: + uchar *q = buf; + while (i > 0) { + uchar *p = pmt[numPmtPackets++]; + int j = 0; + p[j++] = 0x47; // TS indicator + p[j++] = 0x40 | (P_PNR >> 8); // flags (3), pid hi (5) + p[j++] = P_PNR & 0xFF; // pid lo + p[j++] = 0x10; // flags (4), continuity counter (4) + int l = TS_SIZE - j; + memcpy(p + j, q, l); + q += l; + i -= l; + } + IncVersion(pmtVersion); + } + else + esyslog("ERROR: can't find channel %s", *ChannelID.ToString()); +} + +uchar *cPatPmtGenerator::GetPat(void) +{ + IncCounter(patCounter, pat); + return pat; +} + +uchar *cPatPmtGenerator::GetPmt(int &Index) +{ + if (Index < numPmtPackets) { + IncCounter(patCounter, pmt[Index]); + return pmt[Index++]; + } + return NULL; +} + +// --- cPatPmtParser --------------------------------------------------------- + +cPatPmtParser::cPatPmtParser(void) +{ + pmtSize = 0; + pmtPid = -1; + vpid = vtype = 0; +} + +void cPatPmtParser::ParsePat(const uchar *Data, int Length) +{ + // The PAT is always assumed to fit into a single TS packet + SI::PAT Pat(Data, false); + if (Pat.CheckCRCAndParse()) { + dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber()); + SI::PAT::Association assoc; + for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) { + dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid()); + if (!assoc.isNITPid()) { + pmtPid = assoc.getPid(); + dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid()); + } + } + } + else + esyslog("ERROR: can't parse PAT"); +} + +void cPatPmtParser::ParsePmt(const uchar *Data, int Length) +{ + // The PMT may extend over several TS packets, so we need to assemble them + if (pmtSize == 0) { + // this is the first packet + if (SectionLength(Data, Length) > Length) { + if (Length <= int(sizeof(pmt))) { + memcpy(pmt, Data, Length); + pmtSize = Length; + } + else + esyslog("ERROR: PMT packet length too big (%d byte)!", Length); + return; + } + // the packet contains the entire PMT section, so we run into the actual parsing + } + else { + // this is a following packet, so we add it to the pmt storage + if (Length <= int(sizeof(pmt)) - pmtSize) { + memcpy(pmt + pmtSize, Data, Length); + pmtSize += Length; + } + else { + esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length); + pmtSize = 0; + } + if (SectionLength(pmt, pmtSize) > pmtSize) + return; // more packets to come + // the PMT section is now complete, so we run into the actual parsing + Data = pmt; + } + SI::PMT Pmt(Data, false); + if (Pmt.CheckCRCAndParse()) { + dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber()); + dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid()); + cDevice::PrimaryDevice()->ClrAvailableTracks(false, true); + int NumApids = 0; + int NumDpids = 0; + int NumSpids = 0; + SI::PMT::Stream stream; + for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) { + dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid()); + switch (stream.getStreamType()) { + case 0x02: // STREAMTYPE_13818_VIDEO + case 0x1B: // MPEG4 + vpid = stream.getPid(); + vtype = stream.getStreamType(); + break; + case 0x04: // STREAMTYPE_13818_AUDIO + { + if (NumApids < MAXAPIDS) { + char ALangs[MAXLANGCODE2] = ""; + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + SI::ISO639LanguageDescriptor::Language l; + char *s = ALangs; + int n = 0; + for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) { + if (*ld->languageCode != '-') { // some use "---" to indicate "none" + dbgpatpmt(" '%s'", l.languageCode); + if (n > 0) + *s++ = '+'; + strn0cpy(s, I18nNormalizeLanguageCode(l.languageCode), MAXLANGCODE1); + s += strlen(s); + if (n++ > 1) + break; + } + } + } + break; + default: ; + } + delete d; + } + cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, stream.getPid(), ALangs); + NumApids++; + } + } + break; + case 0x06: // STREAMTYPE_13818_PES_PRIVATE + { + int dpid = 0; + char lang[MAXLANGCODE1] = ""; + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::AC3DescriptorTag: + dbgpatpmt(" AC3"); + dpid = stream.getPid(); + break; + case SI::SubtitlingDescriptorTag: + dbgpatpmt(" subtitling"); + if (NumSpids < MAXSPIDS) { + SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d; + SI::SubtitlingDescriptor::Subtitling sub; + char SLangs[MAXLANGCODE2] = ""; + char *s = SLangs; + int n = 0; + for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) { + if (sub.languageCode[0]) { + dbgpatpmt(" '%s'", sub.languageCode); + if (n > 0) + *s++ = '+'; + strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1); + s += strlen(s); + if (n++ > 1) + break; + } + } + cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), SLangs); + NumSpids++; + } + break; + case SI::ISO639LanguageDescriptorTag: { + SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d; + dbgpatpmt(" '%s'", ld->languageCode); + strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1); + } + break; + default: ; + } + delete d; + } + if (dpid) { + if (NumDpids < MAXDPIDS) { + cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang); + NumDpids++; + } + } + } + break; + } + dbgpatpmt("\n"); + cDevice::PrimaryDevice()->EnsureAudioTrack(true); + cDevice::PrimaryDevice()->EnsureSubtitleTrack(); + } + } + else + esyslog("ERROR: can't parse PMT"); + pmtSize = 0; +} + +// --- cTsToPes -------------------------------------------------------------- + +cTsToPes::cTsToPes(void) +{ + data = NULL; + size = length = 0; + synced = false; +} + +cTsToPes::~cTsToPes() +{ + free(data); +} + +void cTsToPes::PutTs(const uchar *Data, int Length) +{ + if (TsPayloadStart(Data)) + Reset(); + else if (!size) + return; // skip everything before the first payload start + Length = TsGetPayload(&Data); + if (length + Length > size) { + size = max(KILOBYTE(2), length + Length); + data = (uchar *)realloc(data, size); + } + memcpy(data + length, Data, Length); + length += Length; +} + +const uchar *cTsToPes::GetPes(int &Length) +{ + if (PesLongEnough(length)) { + Length = PesLength(data); + if (Length <= length) { + Length = length; // in case the PES packet has no explicit length, as is the case for video PES + return data; + } + } + return NULL; +} + +void cTsToPes::Reset(void) +{ + length = 0; +} + +// --- Some helper functions for debugging ----------------------------------- + +void BlockDump(const char *Name, const u_char *Data, int Length) +{ + printf("--- %s\n", Name); + for (int i = 0; i < Length; i++) { + if (i && (i % 16) == 0) + printf("\n"); + printf(" %02X", Data[i]); + } + printf("\n"); +} + +void TsDump(const char *Name, const u_char *Data, int Length) +{ + printf("%s: %04X", Name, Length); + int n = min(Length, 20); + for (int i = 0; i < n; i++) + printf(" %02X", Data[i]); + if (n < Length) { + printf(" ..."); + n = max(n, Length - 10); + for (n = max(n, Length - 10); n < Length; n++) + printf(" %02X", Data[n]); + } + printf("\n"); +} + +void PesDump(const char *Name, const u_char *Data, int Length) +{ + TsDump(Name, Data, Length); +} -- cgit v1.2.3