Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] [PATCH] section demux rewritten



HI all


After I read the specs, and I understood what was the functional
purpose of the old code (gosh, what a messy coding) I rewrote 
it cleanly.

The direct improvement compared to the old code is that the
new one properly handles all PUSI boundary conditions without 
intrudicing additionaly level of buffering and copying

Another news is that this code now can track the section payload
loss.

The new code's logic builds a sequential chunk of data 
between each PUSI=1 bit and uses section start 
"pointer" byte to determine the end the sequential chunk 

After the sequential chunk is complete, it may contain one or more 
sections. Section separation loop starts at the begin of the
chunk, calculates the section_length, calls the section_dump code
and adds to the pointer section_length bytes to jump to the next 
potential section, until the end of the sequential chunk is reached.

There are safety if() to cleanly handle the out-of-boundary data,
corrupted streams etc. (no crash during my tests).

I think this code can even be applied to the CVS,
but it would be good that others test it too.

Owners of non-7146 full TS cards, please test and post 
syslog of network when active receiving packets with compiled in 
#define TRACK_LOSS 
in dvb_demux.c after the attached patch
it will printk() how may bytes of TS payload are lost 
(and not gone into the section). 

short guide:

# dvbnet -p 451
# ifconfig dvb0_0 inet 1.2.3.4
# ifconfig dvb0_0 promisc
# szap -r hsi &
# tail -f /var/log/syslog
 

Best regards, Emard

diff -pur ../dvb-kernel/linux/drivers/media/dvb/dvb-core/demux.h dvb-kernel/linux/drivers/media/dvb/dvb-core/demux.h
--- ../dvb-kernel/linux/drivers/media/dvb/dvb-core/demux.h	2003-11-23 21:18:12.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/demux.h	2003-11-23 15:27:01.000000000 +0100
@@ -143,7 +143,8 @@ struct dmx_section_feed { 
         int check_crc;
 	u32 crc_val;
 
-        u8 secbuf[4096];
+        u8 *secbuf;
+        u8 secbuf_real[16384];
         int secbufp;
         int seclen;
 
diff -pur ../dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_demux.c dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_demux.c
--- ../dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_demux.c	2003-11-23 21:18:12.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_demux.c	2003-11-23 21:06:26.000000000 +0100
@@ -87,7 +87,7 @@ static inline u16 ts_pid(const u8 *buf)
 }
 
 
-static inline int payload(const u8 *tsp)
+static inline u8 payload(const u8 *tsp)
 {
 	if (!(tsp[3] & 0x10)) // no payload?
 		return 0;
@@ -221,6 +221,122 @@ static inline int dvb_dmx_swfilter_secti
 }
 
 
+
+#if 1
+static int dvb_dmx_swfilter_section_buffer_dump(struct dvb_demux_feed *feed)
+{
+	struct dmx_section_feed *sec = &feed->feed.sec;
+	u8 *buf;
+	u16 p = 0, count, seclen;
+	int n = 0;
+
+	buf = sec->secbuf;
+	count = sec->secbufp;
+	seclen = count;
+
+//  goto exit;
+
+	for(p = 0; p + 2 < count; n++)
+	{
+		seclen = section_length(buf + p);
+		if(seclen <= 0 || seclen > 4096 || seclen + p > count)
+			goto exit;
+		/* some would view next 2 lines as a slight hack,
+		** but it's a good one, saving a lot of code and CPU
+		*/
+		sec->secbuf = buf + p;
+		sec->seclen = sec->secbufp = seclen;
+		sec->crc_val = ~0;
+		dvb_dmx_swfilter_section_feed(feed); /* dump single secbuf */
+		p += seclen;
+	}
+
+ exit:; /* restore buffer memory pointer and reset pointer values before exit */
+#ifdef TRACK_LOSS
+	if(p < count)
+		printk("dvb_demux.c section syntax loss: %d/%d (n=%d)\n",
+		       count - p, count, n);
+#endif
+	sec->secbuf = buf;
+	sec->seclen = sec->secbufp = 0;
+	
+	return 0;
+}
+
+#define MAX_SECBUFP 4096
+
+static int dvb_dmx_swfilter_section_truncate_copy(struct dvb_demux_feed *feed, const u8 *buf, u8 len)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct dmx_section_feed *sec = &feed->feed.sec;
+
+	if(sec->secbufp >= MAX_SECBUFP)
+		return 0;
+
+	if(sec->secbufp + len > MAX_SECBUFP)
+	{
+#ifdef TRACK_LOSS
+		printk("dvb_demux.c section buffer full loss: %d/%d\n", 
+		       sec->secbufp + len - MAX_SECBUFP, MAX_SECBUFP);
+#endif
+		len = MAX_SECBUFP - sec->secbufp;
+	}
+	if(len > 0)
+	{
+		demux->memcopy(feed, sec->secbuf + sec->secbufp, buf, len);
+		sec->secbufp += len;
+	}
+	return 0;
+}
+
+
+static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
+{
+	u8 p, count;
+	int ccok;
+	u8 cc;
+
+	count = payload(buf);
+
+	if (count == 0)  /* count == 0 if no payload or out of range */
+		return -1;
+
+	p = 188-count; /* payload start */
+	
+	cc = buf[3] & 0x0f;
+	ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
+	feed->cc = cc;
+
+	if(buf[1] & 0x40)
+	{
+		// PUSI is set, section boundary is here
+		if(count > 1 && buf[p] < count)
+		{
+			const u8 *before = buf+p+1;
+			u8 before_len = buf[p];
+			const u8 *after = before+before_len;
+			u8 after_len = count-1-before_len;
+
+			dvb_dmx_swfilter_section_truncate_copy(feed, before, before_len);
+			dvb_dmx_swfilter_section_buffer_dump(feed);
+			dvb_dmx_swfilter_section_truncate_copy(feed, after, after_len);
+		}
+#ifdef TRACK_LOSS
+		else
+			printk("dvb_demux.c PUSI set and %d bytes lost\n", count);
+#endif
+	}
+	else
+	{
+		// PUSI is not set, no section boundary
+		const u8 *entire = buf+p;
+		u8 entire_len = count;
+		
+		dvb_dmx_swfilter_section_truncate_copy(feed, entire, entire_len);
+	}
+	return 0;
+}
+#else
 static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
 {
 	struct dvb_demux *demux = feed->demux;
@@ -346,6 +462,7 @@ static int dvb_dmx_swfilter_section_pack
 	return 0;
 }
 
+#endif
 
 static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, const u8 *buf)
 {
@@ -1009,6 +1126,7 @@ static int dvbdmx_allocate_section_feed(
 	dvbdmxfeed->cb.sec = callback;
 	dvbdmxfeed->demux = dvbdmx;
 	dvbdmxfeed->pid = 0xffff;
+	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_real;
 	dvbdmxfeed->feed.sec.secbufp = 0;
 	dvbdmxfeed->filter = 0;
 	dvbdmxfeed->buffer = 0;
Only in dvb-kernel/linux/drivers/media/dvb/dvb-core: dvb_demux.c~

Home | Main Index | Thread Index