X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Fdvb-core%2Fdvb_demux.c;h=7901398d6e3f25ea7f492096eb860efdb0961374;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=657d5579b16b6e9c4679c90a11cdfcf88ad426c8;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 657d5579b..7901398d6 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -31,7 +31,6 @@ #include #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); +