vserver 1.9.5.x5
[linux-2.6.git] / drivers / media / dvb / dvb-core / dvb_demux.c
index 657d557..7901398 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/uaccess.h>
 
 #include "dvb_demux.h"
-#include "dvb_functions.h"
 
 #define NOBUFS  
 /* 
@@ -248,7 +247,22 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
                }
 
 /* 
-** Losless Section Demux 1.4 by Emard
+** Losless Section Demux 1.4.1 by Emard
+** Valsecchi Patrick:
+**  - middle of section A  (no PUSI)
+**  - end of section A and start of section B 
+**    (with PUSI pointing to the start of the second section)
+**  
+**  In this case, without feed->pusi_seen you'll receive a garbage section
+**  consisting of the end of section A. Basically because tsfeedp
+**  is incemented and the use=0 condition is not raised
+**  when the second packet arrives.
+**
+** Fix:
+** when demux is started, let feed->pusi_seen = 0 to
+** prevent initial feeding of garbage from the end of
+** previous section. When you for the first time see PUSI=1
+** then set feed->pusi_seen = 1
 */
 static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len)
 {
@@ -294,7 +308,12 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const
                sec->seclen = seclen;
                sec->crc_val = ~0;
                /* dump [secbuf .. secbuf+seclen) */
+               if(feed->pusi_seen)
                dvb_dmx_swfilter_section_feed(feed);
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               else
+                       printk("dvb_demux.c pusi not seen, discarding section data\n");
+#endif
                sec->secbufp += seclen; /* secbufp and secbuf moving together is */
                sec->secbuf += seclen; /* redundand but saves pointer arithmetic */
                }
@@ -306,7 +325,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const
 static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
 {
        u8 p, count;
-       int ccok;
+       int ccok, dc_i = 0;
        u8 cc;
 
        count = payload(buf);
@@ -317,31 +336,41 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8
        p = 188-count; /* payload start */
 
        cc = buf[3] & 0x0f;
-       ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
+       ccok = ((feed->cc + 1) & 0x0f) == cc;
        feed->cc = cc;
-       if(ccok == 0)
-       {
+
+       if (buf[3] & 0x20) {
+               /* adaption field present, check for discontinuity_indicator */
+               if ((buf[4] > 0) && (buf[5] & 0x80))
+                       dc_i = 1;
+       }
+
+       if (!ccok || dc_i) {
 #ifdef DVB_DEMUX_SECTION_LOSS_LOG
                printk("dvb_demux.c discontinuity detected %d bytes lost\n", count);
                /* those bytes under sume circumstances will again be reported
                ** in the following dvb_dmx_swfilter_section_new
                */
 #endif
+               /* Discontinuity detected. Reset pusi_seen = 0 to
+               ** stop feeding of suspicious data until next PUSI=1 arrives
+               */
+               feed->pusi_seen = 0;
                dvb_dmx_swfilter_section_new(feed);
                return 0;
        }
 
-       if(buf[1] & 0x40)
-       {
+       if (buf[1] & 0x40) {
                // PUSI=1 (is set), section boundary is here
-               if(count > 1 && buf[p] < count)
-               {
+               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_copy_dump(feed, before, before_len);
+                       /* before start of new section, set pusi_seen = 1 */
+                       feed->pusi_seen = 1;
                        dvb_dmx_swfilter_section_new(feed);
                        dvb_dmx_swfilter_section_copy_dump(feed, after, after_len);
                }
@@ -350,9 +379,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8
                        if(count > 0)
                                printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
 #endif
-       }
-       else
-       {
+       } else {
                // PUSI=0 (is not set), no section boundary
                const u8 *entire = buf+p;
                u8 entire_len = count;
@@ -425,7 +452,7 @@ void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
                        feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
        }
 }
-
+EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
 
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
@@ -440,6 +467,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t cou
 
        spin_unlock(&demux->lock);
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@@ -479,6 +507,7 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 bailout:
        spin_unlock(&demux->lock);
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter);
 
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
@@ -523,6 +552,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 bailout:
        spin_unlock(&demux->lock);
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
 
 static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux)
@@ -570,24 +600,30 @@ static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
 
 static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
 {
+       spin_lock_irq(&feed->demux->lock);
        if (dvb_demux_feed_find(feed)) {
                printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
                                __FUNCTION__, feed->type, feed->state, feed->pid);
-               return;
+               goto out;
        }
 
        list_add(&feed->list_head, &feed->demux->feed_list);
+out:
+       spin_unlock_irq(&feed->demux->lock);
 }
 
 static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
 {
+       spin_lock_irq(&feed->demux->lock);
        if (!(dvb_demux_feed_find(feed))) {
                printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
                                __FUNCTION__, feed->type, feed->state, feed->pid);
-               return;
+               goto out;
 }
 
        list_del(&feed->list_head);
+out:
+       spin_unlock_irq(&feed->demux->lock);
 }
 
 static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, 
@@ -776,10 +812,8 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_
        }
 
 #ifndef NOBUFS
-       if (feed->buffer) { 
                vfree(feed->buffer);
                feed->buffer=0;
-       }
 #endif
 
        feed->state = DMX_STATE_FREE;
@@ -789,7 +823,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_
 
                feed->pid = 0xffff;
        
-       if (feed->ts_type & TS_DECODER)
+       if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
                demux->pesfilter[feed->pes_type] = NULL;
 
        up(&demux->mutex);
@@ -1047,10 +1081,8 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
                return -EINVAL;
        }
 #ifndef NOBUFS
-       if (dvbdmxfeed->buffer) {
                vfree(dvbdmxfeed->buffer);
                dvbdmxfeed->buffer=0;
-       }
 #endif
        dvbdmxfeed->state=DMX_STATE_FREE;
 
@@ -1158,6 +1190,7 @@ int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *fronte
        up(&dvbdemux->mutex);
        return 0;
 }
+EXPORT_SYMBOL(dvbdmx_connect_frontend);
 
 
 int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
@@ -1171,6 +1204,7 @@ int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
        up(&dvbdemux->mutex);
        return 0;
 }
+EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
 
 
 static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids)
@@ -1251,6 +1285,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
 
        return 0;
 }
+EXPORT_SYMBOL(dvb_dmx_init);
 
 
 int dvb_dmx_release(struct dvb_demux *dvbdemux)
@@ -1258,9 +1293,9 @@ int dvb_dmx_release(struct dvb_demux *dvbdemux)
        struct dmx_demux *dmx = &dvbdemux->dmx;
 
        dmx_unregister_demux(dmx);
-       if (dvbdemux->filter)
                vfree(dvbdemux->filter);
-       if (dvbdemux->feed)
                vfree(dvbdemux->feed);
        return 0;
 }
+EXPORT_SYMBOL(dvb_dmx_release);
+