Index: server/livestreamer.h
===================================================================
RCS file: /var/cvsroot/streamdev/server/livestreamer.h,v
retrieving revision 1.10
diff -u -r1.10 livestreamer.h
--- server/livestreamer.h	15 Jan 2007 12:00:19 -0000	1.10
+++ server/livestreamer.h	9 Apr 2007 21:53:13 -0000
@@ -5,34 +5,14 @@
 #include <vdr/receiver.h>
 
 #include "server/streamer.h"
-#include "server/livefilter.h"
 #include "common.h"
 
 class cTS2PSRemux;
 class cTS2ESRemux;
 class cExternRemux;
 class cRemux;
-
-// --- cStreamdevLiveReceiver -------------------------------------------------
-
-class cStreamdevLiveReceiver: public cReceiver {
-	friend class cStreamdevLiveStreamer;
-
-private:
-	cStreamdevLiveStreamer *m_Streamer;
-
-protected:
-	virtual void Activate(bool On);
-	virtual void Receive(uchar *Data, int Length);
-
-public:
-#if VDRVERSNUM < 10500
-	cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, int Ca, int Priority, const int *Pids);
-#else
-	cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
-#endif
-	virtual ~cStreamdevLiveReceiver();
-};
+class cStreamdevPatFilter;
+class cStreamdevLiveReceiver;
 
 // --- cStreamdevLiveStreamer -------------------------------------------------
 
@@ -45,17 +25,22 @@
 	const cChannel         *m_Channel;
 	cDevice                *m_Device;
 	cStreamdevLiveReceiver *m_Receiver;
+	cStreamdevPatFilter    *m_PatFilter;
 	cRemux                 *m_PESRemux;
 	cTS2ESRemux            *m_ESRemux;
 	cTS2PSRemux            *m_PSRemux;
 	cExternRemux           *m_ExtRemux;
 
+	void StartReceiver(void);
+	bool HasPid(int Pid);
+
 public:
 	cStreamdevLiveStreamer(int Priority);
 	virtual ~cStreamdevLiveStreamer();
 
 	void SetDevice(cDevice *Device) { m_Device = Device; }
 	bool SetPid(int Pid, bool On);
+	bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
 	bool SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid = 0);
 	bool SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On);
 	
@@ -70,12 +55,4 @@
 	virtual std::string Report(void);
 };
 
-// --- cStreamdevLiveReceiver reverse inlines ---------------------------------
-
-inline void cStreamdevLiveReceiver::Activate(bool On) 
-{ 
-	Dprintf("LiveReceiver->Activate(%d)\n", On);
-	m_Streamer->Activate(On); 
-}
-
 #endif // VDR_STREAMDEV_LIVESTREAMER_H
Index: server/livestreamer.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/livestreamer.c,v
retrieving revision 1.11
diff -u -r1.11 livestreamer.c
--- server/livestreamer.c	15 Jan 2007 12:00:19 -0000	1.11
+++ server/livestreamer.c	9 Apr 2007 22:18:07 -0000
@@ -1,6 +1,12 @@
+#include <assert.h>
+
 #include <vdr/ringbuffer.h>
 
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+
 #include "server/livestreamer.h"
+#include "server/livefilter.h"
 #include "remux/ts2ps.h"
 #include "remux/ts2es.h"
 #include "remux/extern.h"
@@ -8,12 +14,31 @@
 
 // --- cStreamdevLiveReceiver -------------------------------------------------
 
+class cStreamdevLiveReceiver: public cReceiver {
+        friend class cStreamdevStreamer;
+
+private:
+	cStreamdevStreamer *m_Streamer;
+
+protected:
+	virtual void Activate(bool On);
+	virtual void Receive(uchar *Data, int Length);
+
+public:
 #if VDRVERSNUM < 10500
-cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, int Ca, 
+	cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, int Priority, const int *Pids);
+#else
+	cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
+#endif
+	virtual ~cStreamdevLiveReceiver();
+};
+
+#if VDRVERSNUM < 10500
+cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, 
                                                int Priority, const int *Pids):
 		cReceiver(Ca, Priority, 0, Pids),
 #else
-cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, tChannelID ChannelID, 
+cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, 
                                                int Priority, const int *Pids):
 		cReceiver(ChannelID, Priority, 0, Pids),
 #endif
@@ -33,6 +58,228 @@
 		m_Streamer->ReportOverflow(Length - p);
 }
 
+inline void cStreamdevLiveReceiver::Activate(bool On) 
+{ 
+	Dprintf("LiveReceiver->Activate(%d)\n", On);
+	m_Streamer->Activate(On); 
+}
+
+// --- cStreamdevPatFilter ----------------------------------------------------
+
+class cStreamdevPatFilter : public cFilter {
+private:
+	int    pmtPid;
+	int    pmtSid;
+	int    pmtVersion;
+
+	const cChannel *m_Channel;
+	cStreamdevLiveStreamer *m_Streamer;
+
+	virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
+
+	int GetPid(SI::PMT::Stream& stream);
+public:
+	cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel);
+};
+
+cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel)
+{
+	Dprintf("cStreamdevPatFilter(\"%s\")", Channel->Name());
+	assert(Streamer);
+	m_Channel = Channel;
+	m_Streamer = Streamer;
+	pmtPid = 0;
+	pmtSid = 0;
+	pmtVersion = -1;
+	Set(0x00, 0x00);  // PAT
+}
+
+static const char * const psStreamTypes[] = {
+	"UNKNOWN", 
+	"ISO/IEC 11172 Video", 
+	"ISO/IEC 13818-2 Video", 
+	"ISO/IEC 11172 Audio", 
+	"ISO/IEC 13818-3 Audio",
+	"ISO/IEC 13818-1 Privete sections", 
+	"ISO/IEC 13818-1 Private PES data",
+	"ISO/IEC 13512 MHEG", 
+	"ISO/IEC 13818-1 Annex A DSM CC",
+	"0x09",
+	"ISO/IEC 13818-6 Multiprotocol encapsulation",
+	"ISO/IEC 13818-6 DSM-CC U-N Messages",
+	"ISO/IEC 13818-6 Stream Descriptors",
+	"ISO/IEC 13818-6 Sections (any type, including private data)",
+	"ISO/IEC 13818-1 auxiliary",
+	"ISO/IEC 13818-7 Audio with ADTS transport sytax",
+	"ISO/IEC 14496-2 Visual (MPEG-4)",
+	"ISO/IEC 14496-3 Audio with LATM transport syntax",
+	"0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a",
+	"ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)",
+	"",
+};
+
+int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
+{
+	SI::Descriptor *d;
+
+	if (!stream.getPid()) 
+		return 0;
+
+	switch (stream.getStreamType()) {
+	case 0x01: // ISO/IEC 11172 Video
+	case 0x02: // ISO/IEC 13818-2 Video
+	case 0x03: // ISO/IEC 11172 Audio
+	case 0x04: // ISO/IEC 13818-3 Audio
+#if 0
+	case 0x07: // ISO/IEC 13512 MHEG 
+	case 0x08: // ISO/IEC 13818-1 Annex A  DSM CC
+	case 0x0a: // ISO/IEC 13818-6 Multiprotocol encapsulation
+	case 0x0b: // ISO/IEC 13818-6 DSM-CC U-N Messages
+	case 0x0c: // ISO/IEC 13818-6 Stream Descriptors
+	case 0x0d: // ISO/IEC 13818-6 Sections (any type, including private data)
+	case 0x0e: // ISO/IEC 13818-1 auxiliary
+#endif
+	case 0x0f: // ISO/IEC 13818-7 Audio with ADTS transport syntax
+	case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4)
+	case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
+	case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)
+		Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)",
+			stream.getPid(), psStreamTypes[stream.getStreamType()]);
+		return stream.getPid();
+	case 0x05: // ISO/IEC 13818-1 private sections
+	case 0x06: // ISO/IEC 13818-1 PES packets containing private data
+		for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+			switch (d->getDescriptorTag()) {
+			case SI::AC3DescriptorTag:
+				Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
+				return stream.getPid();
+			case SI::TeletextDescriptorTag:
+				Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
+				return stream.getPid();
+			case SI::SubtitlingDescriptorTag:
+				Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
+				return stream.getPid();
+			default:
+				Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
+				break;
+			}
+			delete d;
+		}
+		break;
+	default:
+		/* This following section handles all the cases where the audio track 
+		 * info is stored in PMT user info with stream id >= 0x80
+		 * we check the registration format identifier to see if it 
+		 * holds "AC-3"
+		 */
+		if (stream.getStreamType() >= 0x80) {
+			bool found = false;
+			for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+				switch (d->getDescriptorTag()) {
+				case SI::RegistrationDescriptorTag:
+					/* unfortunately libsi does not implement RegistrationDescriptor */
+					if (d->getLength() >= 4) {
+						found = true;
+						SI::CharArray rawdata = d->getData();
+						if (/*rawdata[0] == 5 && rawdata[1] >= 4 && */
+						    rawdata[2] == 'A' && rawdata[3] == 'C' &&
+						    rawdata[4] == '-' && rawdata[5] == '3') {
+							isyslog("cStreamdevPatFilter PMT scanner:"
+								"Adding pid %d (type 0x%x) RegDesc len %d (%c%c%c%c)", 
+								stream.getPid(), stream.getStreamType(), 
+								d->getLength(), rawdata[2], rawdata[3], 
+								rawdata[4], rawdata[5]);
+							return stream.getPid();
+						}
+					}
+					break;
+				default: 
+					break;
+				}
+				delete d;
+			}
+			if(!found) {
+				isyslog("Adding pid %d (type 0x%x) RegDesc not found -> assume AC-3", 
+					stream.getPid(), stream.getStreamType());
+				return stream.getPid();
+			}
+		}
+		Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s)",
+			stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0]);
+		break;
+	}
+	return 0;
+}
+
+void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
+{
+	if (Pid == 0x00) {
+		if (Tid == 0x00 && !pmtPid) {
+			SI::PAT pat(Data, false);
+			if (!pat.CheckCRCAndParse())
+				return;
+			SI::PAT::Association assoc;
+			for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
+				if (!assoc.isNITPid()) {
+					const cChannel *Channel =  Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
+					if (Channel && (Channel == m_Channel)) {
+						if (0 != (pmtPid = assoc.getPid())) {
+							Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d", Channel->Name(), pmtPid);
+							pmtSid = assoc.getServiceId();
+							if (Length < TS_SIZE-5) {
+								// repack PAT to TS frame and send to client
+								uint8_t pat_ts[TS_SIZE] = {TS_SYNC_BYTE, 0x40 /* pusi=1 */, 0 /* pid=0 */, 0x10 /* adaption=1 */, 0 /* pointer */};
+								memcpy(pat_ts + 5, Data, Length);
+								m_Streamer->Put(pat_ts, TS_SIZE);
+							} else 
+								isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length);
+							m_Streamer->SetPids(pmtPid);
+							Add(pmtPid, 0x02);
+							pmtVersion = -1;
+							return;
+						}
+					}
+				}
+			}
+		}
+	} else if (Pid == pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) {
+		SI::PMT pmt(Data, false);
+		if (!pmt.CheckCRCAndParse())
+			return;
+		if (pmt.getServiceId() != pmtSid)
+			return; // skip broken PMT records
+		if (pmtVersion != -1) {
+			if (pmtVersion != pmt.getVersionNumber()) {
+				Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids");
+				Del(pmtPid, 0x02);
+				pmtPid = 0; // this triggers PAT scan
+			}
+			return;
+		}
+		pmtVersion = pmt.getVersionNumber();
+
+		SI::PMT::Stream stream;
+		int pids[MAXRECEIVEPIDS + 1], npids = 0;
+		pids[npids++] = pmtPid;
+#if 0
+		pids[npids++] = 0x10;  // pid 0x10, tid 0x40: NIT 
+		pids[npids++] = 0x11;  // pid 0x11, tid 0x42: SDT 
+		pids[npids++] = 0x12;  // pid 0x12, tid 0x4E...0x6F: EIT 
+		pids[npids++] = 0x14;  // pid 0x14, tid 0x70: TDT 
+#endif
+		for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
+			if (0 != (pids[npids] = GetPid(stream)) && npids < MAXRECEIVEPIDS)
+				npids++;
+
+		pids[npids] = 0;
+		m_Streamer->SetPids(pmt.getPCRPid(), pids);
+	}
+}
+
 // --- cStreamdevLiveStreamer -------------------------------------------------
 
 cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority):
@@ -43,6 +290,7 @@
 		m_Channel(NULL),
 		m_Device(NULL),
 		m_Receiver(NULL),
+		m_PatFilter(NULL),
 		m_PESRemux(NULL),
 		m_ESRemux(NULL),
 		m_PSRemux(NULL),
@@ -54,14 +302,24 @@
 {
 	Dprintf("Desctructing Live streamer\n");
 	Stop();
-	delete m_Receiver;
+	if(m_PatFilter) {
+		Detach();
+		DELETENULL(m_PatFilter);
+	}
+	DELETENULL(m_Receiver);
 	delete m_PESRemux;
 	delete m_ESRemux;
 	delete m_PSRemux;
 	delete m_ExtRemux;
-#if VDRVERSNUM >= 10300
-	//delete m_Filter; TODO
-#endif
+}
+
+bool cStreamdevLiveStreamer::HasPid(int Pid) 
+{
+	int idx;
+	for (idx = 0; idx < m_NumPids; ++idx)
+		if (m_Pids[idx] == Pid)
+			return true;
+	return false;
 }
 
 bool cStreamdevLiveStreamer::SetPid(int Pid, bool On) 
@@ -93,6 +351,44 @@
 		}
 	}
 
+	StartReceiver();
+	return true;
+}
+
+bool cStreamdevLiveStreamer::SetPids(int Pid, const int *Pids1, const int *Pids2, const int *Pids3)
+{
+	m_NumPids = 0;
+
+	if (Pid)
+		m_Pids[m_NumPids++] = Pid;
+
+	if (Pids1)
+		for ( ; *Pids1 && m_NumPids < MAXRECEIVEPIDS; Pids1++)
+			if (!HasPid(*Pids1))
+				m_Pids[m_NumPids++] = *Pids1;
+
+	if (Pids2)
+		for ( ; *Pids2 && m_NumPids < MAXRECEIVEPIDS; Pids2++)
+			if (!HasPid(*Pids2))
+				m_Pids[m_NumPids++] = *Pids2;
+
+	if (Pids3)
+		for ( ; *Pids3 && m_NumPids < MAXRECEIVEPIDS; Pids3++)
+			if (!HasPid(*Pids3))
+				m_Pids[m_NumPids++] = *Pids3;
+
+	if (m_NumPids >= MAXRECEIVEPIDS) {
+		esyslog("ERROR: Streamdev: No free slot to receive pid %d\n", Pid);
+		return false;
+	}
+
+	m_Pids[m_NumPids] = 0;
+	StartReceiver();
+	return true;
+}
+
+void cStreamdevLiveStreamer::StartReceiver(void)
+{
 	DELETENULL(m_Receiver);
 	if (m_NumPids > 0) {
 		Dprintf("Creating Receiver to respect changed pids\n");
@@ -106,15 +402,19 @@
 			Attach();
 		}
 	}
-	return true;
 }
 
 bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid) 
 {
 	Dprintf("Initializing Remuxer for full channel transfer\n");
-	printf("ca pid: %d\n", Channel->Ca());
+	//printf("ca pid: %d\n", Channel->Ca());
 	m_Channel = Channel;
 	m_StreamType = StreamType;
+
+	int apid[2] = { Apid, 0 };
+	const int *Apids = Apid ? apid : m_Channel->Apids();
+	const int *Dpids = Apid ? NULL : m_Channel->Dpids();
+
 	switch (m_StreamType) {
 	case stES: 
 		{
@@ -122,51 +422,33 @@
 			if (Apid != 0)
 				pid = Apid;
 			m_ESRemux = new cTS2ESRemux(pid);
-			return SetPid(pid, true);
+			return SetPids(pid);
 		}
 
 	case stPES: 
-		Dprintf("PES\n");
 		m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), 
 								m_Channel->Spids(), false);
-		if (Apid != 0)
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(Apid, true);
-		else
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(m_Channel->Apid(0), true)
-			    && SetPid(m_Channel->Dpid(0), true);
+		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
 	case stPS:  
 		m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
 		                            m_Channel->Spids());
-		if (Apid != 0)
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(Apid, true);
-		else
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(m_Channel->Apid(0), true)
-			    && SetPid(m_Channel->Dpid(0), true);
+		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
 	case stTS:
-		if (Apid != 0)
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(Apid, true);
-		else
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(m_Channel->Apid(0), true)
-			    && SetPid(m_Channel->Dpid(0), true);
+		// This should never happen, but ...
+		if (m_PatFilter) {
+			Detach();
+			DELETENULL(m_PatFilter);
+		}
+		// Set pids from PMT
+		m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
+		return true;
 
 	case stExtern:
 		m_ExtRemux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
 		                              m_Channel->Spids());
-		if (Apid != 0)
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(Apid, true);
-		else
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(m_Channel->Apid(0), true)
-			    && SetPid(m_Channel->Dpid(0), true);
+		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
 	case stTSPIDS:
 		Dprintf("pid streaming mode\n");
@@ -270,14 +552,28 @@
 	
 void cStreamdevLiveStreamer::Attach(void) 
 { 
-	printf("RIGHT ATTACH\n");
-	m_Device->AttachReceiver(m_Receiver); 
+	Dprintf("cStreamdevLiveStreamer::Attach()\n");
+	if (m_Device) {
+		if (m_Receiver) {
+			m_Device->Detach(m_Receiver); 
+	        	m_Device->AttachReceiver(m_Receiver); 
+		}
+		if (m_PatFilter) {
+			m_Device->Detach(m_PatFilter); 
+			m_Device->AttachFilter(m_PatFilter); 
+		}
+	}
 }
 
 void cStreamdevLiveStreamer::Detach(void) 
 { 
-	printf("RIGHT DETACH\n");
-	m_Device->Detach(m_Receiver); 
+	Dprintf("cStreamdevLiveStreamer::Detach()\n");
+	if (m_Device) {
+		if (m_Receiver)
+			m_Device->Detach(m_Receiver); 
+		if (m_PatFilter)
+			m_Device->Detach(m_PatFilter); 
+	}
 }
 
 std::string cStreamdevLiveStreamer::Report(void) 
