diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2009-01-25 13:13:00 +0100 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2009-01-25 13:13:00 +0100 |
commit | 084e16c057ab195a76c2117c631a2fe10a904238 (patch) | |
tree | 5506d63dbe1fca2f785017aefd6c9ee03e79c291 /remux.c | |
parent | c2966475942fcb9d4b8d41dbf026ff57630a1ad6 (diff) | |
download | vdr-patch-lnbsharing-084e16c057ab195a76c2117c631a2fe10a904238.tar.gz vdr-patch-lnbsharing-084e16c057ab195a76c2117c631a2fe10a904238.tar.bz2 |
Version 1.7.4vdr-1.7.4
- Removed the '#define FE_CAN_2ND_GEN_MODULATION', since it was wrong and the
flag is now in the driver, anyway.
- The full-featured DVB cards are now given the TS data directly for replay
(thanks to Oliver Endriss for enhancing the av7110 driver to make it replay
TS data). The patch from ftp://ftp.cadsoft.de/vdr/Developer/av7110_ts_replay__1.diff
implements this change in the driver.
The patch av7110_v4ldvb_api5_audiobuf_test_1.diff mentioned in version 1.7.2
is still necessary to avoid audio and video glitches on some channels.
- Added a typecast in cUnbufferedFile::Write() to avoid an error message when
compiling on 64 bit systems.
- Added some missing 'const' statements to cBitmap (thanks to Andreas Regel).
- Fixed returning complete PES packets in cTsToPes::GetPes() (thanks to Reinhard
Nissl).
- Added a missing Detach() in cTransfer::Activate() (thanks to Marco Schlüßler).
- Added clearing the TS buffers in cDevice::Detach() (thanks to Marco Schlüßler).
- Fixed incrementing the continuity counter in cPatPmtGenerator::GetPmt() (thanks
to Johann Friedrichs).
- Fixed removing deleted recordings in case there is a problem. Once a recording
caused a problem with removing, no others were removed any more and an ongoing
recording could fill up the disk and cause other recordings to be deleted
automatically (reported by Reinhard Nissl).
- Added "DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
to Make.config.template (thanks to Johann Friedrichs for pointing this out).
Plugin authors should add this line to their Makefile or Make.config if they use
file access functions that need special versions for 64 bit offsets.
- The new command line option -i can be used to set an "instance id", which will
be used to distinguish recordings of the same broadcast made by different instances
of VDR (suggested by Frank Schmirler). This replaces the use of the "resume id"
that was introduced in version 1.7.3.
- Added checking mutexCurrentAudioTrack to cDevice::PlayTs() (thanks to Reinhard
Nissl for pointing this out).
- Fixed handling the pointer field in cPatPmtParser::ParsePmt() (thanks to Frank
Schmirler - sorry I swapped two lines when adopting the original patch).
- Checking the remaining packet length after processing the pointer field in
cPatPmtParser::ParsePat() and cPatPmtParser::ParsePmt() (suggested by Frank
Schmirler).
- Checking the pointer field in cPatPmtParser::ParsePmt() only in 'payload start'
packets (suggested by Frank Schmirler).
- Changed cPatPmtGenerator to make sure the PMT pid doesn't collide with any of
the actual pids of the channel.
- Fixed cDevice::PlayTsAudio() and made cDevice::PlayTsVideo() return 0 if
PlayVideo() didn't play anything.
- Added an 'int' typecast to calculations involving FramesPerSecond() to avoid
compiler warnings (reported by Winfried Koehler).
- Fixed detecting frames for pure audio recordings.
- Fixed editing PES recordings. The frame type in the index.vdr file generated for
the edited PES recording is set to 1 for I-frames and 2 for all others (P- and
B-frames). The exact frame type doesn't matter for VDR, it only needs to know if
it's an I-frame or not.
- The PAT/PMT is now only processed if its version changes (reported by Reinhard
Nissl).
- Fixed handling the maximum video file size (reported by Udo Richter).
- Improved fast-forward/-rewind for audio recordings. The actual data is now sent
to the output device, so that it can be replayed and thus cause the proper delay.
For pure audio recordings the audio is no longer muted in fast-forward/-rewind
mode, so that some orientation regarding the position within the recording is
possible. There may still be some offset in the replay position displayed by the
progress indicator when switching from fast-forward/-rewind to play mode, as well
as in the current position during normal play mode. This is due to the various
buffers between the player and the output device and will be addressed later.
Note the new function cDevice::IsPlayingVideo(), which is used to inform the
player whether there is video data in the currently replayed stream. If a derived
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
new function works as expected.
Diffstat (limited to 'remux.c')
-rw-r--r-- | remux.c | 102 |
1 files changed, 77 insertions, 25 deletions
@@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.c 2.5 2009/01/06 14:46:21 kls Exp $ + * $Id: remux.c 2.13 2009/01/24 13:44:45 kls Exp $ */ #include "remux.h" @@ -111,13 +111,14 @@ void cRemux::SetBrokenLink(uchar *Data, int Length) // --- cPatPmtGenerator ------------------------------------------------------ -cPatPmtGenerator::cPatPmtGenerator(void) +cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel) { numPmtPackets = 0; patCounter = pmtCounter = 0; patVersion = pmtVersion = 0; + pmtPid = 0; esInfoLength = NULL; - GeneratePat(); + SetChannel(Channel); } void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket) @@ -206,16 +207,31 @@ int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length) } #define P_TSID 0x8008 // pseudo TS ID -#define P_PNR 0x0084 // pseudo Program Number #define P_PMT_PID 0x0084 // pseudo PMT pid +#define MAXPID 0x2000 // the maximum possible number of pids + +void cPatPmtGenerator::GeneratePmtPid(cChannel *Channel) +{ + bool Used[MAXPID] = { false }; +#define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; } +#define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } } + SETPID(Channel->Vpid()); + SETPID(Channel->Ppid()); + SETPID(Channel->Tpid()); + SETPIDS(Channel->Apids()); + SETPIDS(Channel->Dpids()); + SETPIDS(Channel->Spids()); + for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++) + ; +} 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++] = TS_SYNC_BYTE; // TS indicator + p[i++] = TS_PAYLOAD_START; // flags (3), pid hi (5) p[i++] = 0x00; // pid lo p[i++] = 0x10; // flags (4), continuity counter (4) p[i++] = 0x00; // pointer field (payload unit start indicator is set) @@ -229,22 +245,21 @@ void cPatPmtGenerator::GeneratePat(void) 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 + p[i++] = pmtPid >> 8; // program number hi + p[i++] = pmtPid & 0xFF; // program number lo + p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5) + p[i++] = pmtPid & 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) +void cPatPmtGenerator::GeneratePmt(cChannel *Channel) { // 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; @@ -253,8 +268,8 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) 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++] = pmtPid >> 8; // program number hi + p[i++] = pmtPid & 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 @@ -292,9 +307,9 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) while (i > 0) { uchar *p = pmt[numPmtPackets++]; int j = 0; - p[j++] = 0x47; // TS indicator - p[j++] = (pusi ? 0x40 : 0x00) | (P_PNR >> 8); // flags (3), pid hi (5) - p[j++] = P_PNR & 0xFF; // pid lo + p[j++] = TS_SYNC_BYTE; // TS indicator + p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5) + p[j++] = pmtPid & 0xFF; // pid lo p[j++] = 0x10; // flags (4), continuity counter (4) if (pusi) { p[j++] = 0x00; // pointer field (payload unit start indicator is set) @@ -307,8 +322,15 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) } IncVersion(pmtVersion); } - else - esyslog("ERROR: can't find channel %s", *ChannelID.ToString()); +} + +void cPatPmtGenerator::SetChannel(cChannel *Channel) +{ + if (Channel) { + GeneratePmtPid(Channel); + GeneratePat(); + GeneratePmt(Channel); + } } uchar *cPatPmtGenerator::GetPat(void) @@ -320,7 +342,7 @@ uchar *cPatPmtGenerator::GetPat(void) uchar *cPatPmtGenerator::GetPmt(int &Index) { if (Index < numPmtPackets) { - IncCounter(patCounter, pmt[Index]); + IncCounter(pmtCounter, pmt[Index]); return pmt[Index++]; } return NULL; @@ -330,18 +352,32 @@ uchar *cPatPmtGenerator::GetPmt(int &Index) cPatPmtParser::cPatPmtParser(void) { + Reset(); +} + +void cPatPmtParser::Reset(void) +{ pmtSize = 0; + patVersion = pmtVersion = -1; pmtPid = -1; vpid = vtype = 0; } void cPatPmtParser::ParsePat(const uchar *Data, int Length) { + // Unpack the TS packet: + int PayloadOffset = TsPayloadOffset(Data); + Data += PayloadOffset; + Length -= PayloadOffset; // The PAT is always assumed to fit into a single TS packet + if ((Length -= Data[0] + 1) <= 0) + return; Data += Data[0] + 1; // process pointer_field 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()); + if (patVersion == Pat.getVersionNumber()) + return; SI::PAT::Association assoc; for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) { dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid()); @@ -350,6 +386,7 @@ void cPatPmtParser::ParsePat(const uchar *Data, int Length) dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid()); } } + patVersion = Pat.getVersionNumber(); } else esyslog("ERROR: can't parse PAT"); @@ -357,10 +394,17 @@ void cPatPmtParser::ParsePat(const uchar *Data, int Length) void cPatPmtParser::ParsePmt(const uchar *Data, int Length) { + // Unpack the TS packet: + bool PayloadStart = TsPayloadStart(Data); + int PayloadOffset = TsPayloadOffset(Data); + Data += PayloadOffset; + Length -= PayloadOffset; // The PMT may extend over several TS packets, so we need to assemble them - if (pmtSize == 0) { + if (PayloadStart) { + pmtSize = 0; + if ((Length -= Data[0] + 1) <= 0) + return; Data += Data[0] + 1; // this is the first packet - Length -= Data[0] + 1; if (SectionLength(Data, Length) > Length) { if (Length <= int(sizeof(pmt))) { memcpy(pmt, Data, Length); @@ -372,7 +416,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) } // the packet contains the entire PMT section, so we run into the actual parsing } - else { + else if (pmtSize > 0) { // this is a following packet, so we add it to the pmt storage if (Length <= int(sizeof(pmt)) - pmtSize) { memcpy(pmt + pmtSize, Data, Length); @@ -387,10 +431,14 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) // the PMT section is now complete, so we run into the actual parsing Data = pmt; } + else + return; // fragment of broken packet - ignore 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()); + if (pmtVersion == Pmt.getVersionNumber()) + return; cDevice::PrimaryDevice()->ClrAvailableTracks(false, true); int NumApids = 0; int NumDpids = 0; @@ -496,6 +544,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) cDevice::PrimaryDevice()->EnsureAudioTrack(true); cDevice::PrimaryDevice()->EnsureSubtitleTrack(); } + pmtVersion = Pmt.getVersionNumber(); } else esyslog("ERROR: can't parse PMT"); @@ -559,8 +608,10 @@ const uchar *cTsToPes::GetPes(int &Length) } else { Length = PesLength(data); - offset = Length; // to make sure we break out in case of garbage data - return data; + if (Length <= length) { + offset = Length; // to make sure we break out in case of garbage data + return data; + } } } return NULL; @@ -703,6 +754,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length) if (frameDuration) { newFrame = true; independentFrame = true; + scanning = false; } else framesPerPayloadUnit = 1; |