summaryrefslogtreecommitdiff
path: root/remux.c
diff options
context:
space:
mode:
Diffstat (limited to 'remux.c')
-rw-r--r--remux.c102
1 files changed, 77 insertions, 25 deletions
diff --git a/remux.c b/remux.c
index 840f5df..b008621 100644
--- a/remux.c
+++ b/remux.c
@@ -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;