From: Michael Hunold add a parameter to dvb_filter_pes2ts function to specify whether the packet is a payload unit start or not. new section demux code by emard change license GPL -> LGPL for dvb_ringbuffer, like all other DVB core files fix rare crash on invalid packets, patch by Asier Aguirre i2c: copy the data variable as well on register client so that detach sees it. 25-akpm/drivers/media/dvb/dvb-core/demux.h | 15 - 25-akpm/drivers/media/dvb/dvb-core/dvb_demux.c | 277 ++++++++++++-------- 25-akpm/drivers/media/dvb/dvb-core/dvb_demux.h | 3 25-akpm/drivers/media/dvb/dvb-core/dvb_filter.c | 6 25-akpm/drivers/media/dvb/dvb-core/dvb_filter.h | 3 25-akpm/drivers/media/dvb/dvb-core/dvb_i2c.c | 1 25-akpm/drivers/media/dvb/dvb-core/dvb_ksyms.c | 1 25-akpm/drivers/media/dvb/dvb-core/dvb_ringbuffer.c | 30 -- 25-akpm/drivers/media/dvb/dvb-core/dvb_ringbuffer.h | 2 9 files changed, 212 insertions(+), 126 deletions(-) diff -puN drivers/media/dvb/dvb-core/demux.h~dvb-05-core-update drivers/media/dvb/dvb-core/demux.h --- 25/drivers/media/dvb/dvb-core/demux.h~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/demux.h Fri Dec 19 14:54:10 2003 @@ -44,6 +44,15 @@ #endif /* + * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter. + */ + +#ifndef DMX_MAX_SECFEED_SIZE +#define DMX_MAX_SECFEED_SIZE 4096 +#endif + + +/* * enum dmx_success: Success codes for the Demux Callback API. */ @@ -143,9 +152,9 @@ struct dmx_section_feed { int check_crc; u32 crc_val; - u8 secbuf[4096]; - int secbufp; - int seclen; + u8 *secbuf; + u8 secbuf_base[DMX_MAX_SECFEED_SIZE]; + u16 secbufp, seclen, tsfeedp; int (*set) (struct dmx_section_feed* feed, u16 pid, diff -puN drivers/media/dvb/dvb-core/dvb_demux.c~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_demux.c --- 25/drivers/media/dvb/dvb-core/dvb_demux.c~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_demux.c Fri Dec 19 14:54:10 2003 @@ -34,6 +34,11 @@ #include "dvb_functions.h" #define NOBUFS +/* +** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog +*/ +// #define DVB_DEMUX_SECTION_LOSS_LOG + LIST_HEAD(dmx_muxs); @@ -87,7 +92,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; @@ -188,9 +193,7 @@ static inline int dvb_dmx_swfilter_secti struct dvb_demux_filter *f = feed->filter; struct dmx_section_feed *sec = &feed->feed.sec; u8 *buf = sec->secbuf; - - if (sec->secbufp != sec->seclen) - return -1; + int section_syntax_indicator; if (!sec->is_filtering) return 0; @@ -198,15 +201,19 @@ static inline int dvb_dmx_swfilter_secti if (!f) return 0; - if (sec->check_crc && demux->check_crc32(feed, sec->secbuf, sec->seclen)) + if (sec->check_crc) { + section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); + if (section_syntax_indicator && + demux->check_crc32(feed, sec->secbuf, sec->seclen)) return -1; + } do { if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0) return -1; } while ((f = f->next) && sec->is_filtering); - sec->secbufp = sec->seclen = 0; + sec->seclen = 0; memset(buf, 0, DVB_DEMUX_MASK_MAX); @@ -214,128 +221,147 @@ static inline int dvb_dmx_swfilter_secti } -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) +static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { - struct dvb_demux *demux = feed->demux; struct dmx_section_feed *sec = &feed->feed.sec; - int p, count; - int ccok, rest; - u8 cc; - - if (!(count = payload(buf))) - return -1; - - p = 188-count; - - cc = buf[3] & 0x0f; - ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0; - feed->cc = cc; - - if (buf[1] & 0x40) { // PUSI set - // offset to start of first section is in buf[p] - if (p+buf[p]>187) // trash if it points beyond packet - return -1; - - if (buf[p] && ccok) { // rest of previous section? - // did we have enough data in last packet to calc length? - int tmp = 3 - sec->secbufp; - if (tmp > 0 && tmp != 3) { - if (p + tmp >= 187) - return -1; - - demux->memcopy (feed, sec->secbuf+sec->secbufp, - buf+p+1, tmp); - - sec->seclen = section_length(sec->secbuf); - - if (sec->seclen > 4096) - return -1; +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + if(sec->secbufp < sec->tsfeedp) + { + int i, n = sec->tsfeedp - sec->secbufp; + + /* section padding is done with 0xff bytes entirely. + ** due to speed reasons, we won't check all of them + ** but just first and last + */ + if(sec->secbuf[0] != 0xff || sec->secbuf[n-1] != 0xff) + { + printk("dvb_demux.c section ts padding loss: %d/%d\n", + n, sec->tsfeedp); + printk("dvb_demux.c pad data:"); + for(i = 0; i < n; i++) + printk(" %02x", sec->secbuf[i]); + printk("\n"); } - - rest = sec->seclen - sec->secbufp; - - if (rest == buf[p] && sec->seclen) { - demux->memcopy (feed, sec->secbuf + sec->secbufp, - buf+p+1, buf[p]); - sec->secbufp += buf[p]; - dvb_dmx_swfilter_section_feed(feed); } - } - - p += buf[p] + 1; // skip rest of last section - count = 188 - p; +#endif - while (count) { + sec->tsfeedp = sec->secbufp = sec->seclen = 0; + sec->secbuf = sec->secbuf_base; + } - sec->crc_val = ~0; +/* +** Losless Section Demux 1.4 by Emard +*/ +static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len) +{ + struct dvb_demux *demux = feed->demux; + struct dmx_section_feed *sec = &feed->feed.sec; + u16 limit, seclen, n; - if ((count>2) && // enough data to determine sec length? - ((sec->seclen = section_length(buf+p)) <= count)) { - if (sec->seclen>4096) - return -1; + if(sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) + return 0; - demux->memcopy (feed, sec->secbuf, buf+p, - sec->seclen); + if(sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) + { +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + printk("dvb_demux.c section buffer full loss: %d/%d\n", + sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); +#endif + len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; + } - sec->secbufp = sec->seclen; - p += sec->seclen; - count = 188 - p; + if(len <= 0) + return 0; - dvb_dmx_swfilter_section_feed(feed); + demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); + sec->tsfeedp += len; - // filling bytes until packet end? - if (count && buf[p]==0xff) - count=0; + /* ----------------------------------------------------- + ** Dump all the sections we can find in the data (Emard) + */ - } else { // section continues to following TS packet - demux->memcopy(feed, sec->secbuf, buf+p, count); - sec->secbufp+=count; - count=0; - } + limit = sec->tsfeedp; + if(limit > DMX_MAX_SECFEED_SIZE) + return -1; /* internal error should never happen */ + + /* to be sure always set secbuf */ + sec->secbuf = sec->secbuf_base + sec->secbufp; + + for(n = 0; sec->secbufp + 2 < limit; n++) + { + seclen = section_length(sec->secbuf); + if(seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE + || seclen + sec->secbufp > limit) + return 0; + sec->seclen = seclen; + sec->crc_val = ~0; + /* dump [secbuf .. secbuf+seclen) */ + dvb_dmx_swfilter_section_feed(feed); + sec->secbufp += seclen; /* secbufp and secbuf moving together is */ + sec->secbuf += seclen; /* redundand but saves pointer arithmetic */ } return 0; } - // section continued below - if (!ccok) - return -1; - if (!sec->secbufp) // any data in last ts packet? - return -1; +static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) +{ + u8 p, count; + int ccok; + u8 cc; - // did we have enough data in last packet to calc section length? - if (sec->secbufp < 3) { - int tmp = 3 - sec->secbufp; + count = payload(buf); - if (tmp>count) + if (count == 0) /* count == 0 if no payload or out of range */ return -1; - sec->crc_val = ~0; - - demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, tmp); + p = 188-count; /* payload start */ - sec->seclen = section_length(sec->secbuf); - - if (sec->seclen > 4096) - return -1; + cc = buf[3] & 0x0f; + ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0; + feed->cc = cc; + if(ccok == 0) + { +#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 + dvb_dmx_swfilter_section_new(feed); + return 0; } - rest = sec->seclen - sec->secbufp; - - if (rest < 0) - return -1; - - if (rest <= count) { // section completed in this TS packet - demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, rest); - sec->secbufp += rest; - dvb_dmx_swfilter_section_feed(feed); - } else { // section continues in following ts packet - demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, count); - sec->secbufp += count; + if(buf[1] & 0x40) + { + // PUSI=1 (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_copy_dump(feed, before, before_len); + dvb_dmx_swfilter_section_new(feed); + dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); + } +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + else + if(count > 0) + printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); +#endif } + else + { + // PUSI=0 (is not set), no section boundary + const u8 *entire = buf+p; + u8 entire_len = count; + dvb_dmx_swfilter_section_copy_dump(feed, entire, entire_len); + } return 0; } @@ -439,6 +465,50 @@ bailout: spin_unlock(&demux->lock); } +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + int p = 0,i, j; + u8 tmppack[188]; + spin_lock(&demux->lock); + + if ((i = demux->tsbufp)) { + if (count < (j=204-i)) { + memcpy(&demux->tsbuf[i], buf, count); + demux->tsbufp += count; + goto bailout; + } + memcpy(&demux->tsbuf[i], buf, j); + if ((demux->tsbuf[0] == 0x47)|(demux->tsbuf[0]==0xB8)) { + memcpy(tmppack, demux->tsbuf, 188); + if (tmppack[0] == 0xB8) tmppack[0] = 0x47; + dvb_dmx_swfilter_packet(demux, tmppack); + } + demux->tsbufp = 0; + p += j; + } + + while (p < count) { + if ((buf[p] == 0x47)|(buf[p] == 0xB8)) { + if (count-p >= 204) { + memcpy(tmppack, buf+p, 188); + if (tmppack[0] == 0xB8) tmppack[0] = 0x47; + dvb_dmx_swfilter_packet(demux, tmppack); + p += 204; + } else { + i = count-p; + memcpy(demux->tsbuf, buf+p, i); + demux->tsbufp=i; + goto bailout; + } + } else { + p++; + } + } + +bailout: + spin_unlock(&demux->lock); +} + static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) { @@ -848,6 +918,9 @@ static int dmx_section_feed_start_filter up(&dvbdmx->mutex); return -EINVAL; } + + dvbdmxfeed->feed.sec.tsfeedp = 0; + dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp=0; dvbdmxfeed->feed.sec.seclen=0; @@ -946,7 +1019,9 @@ static int dvbdmx_allocate_section_feed( dvbdmxfeed->cb.sec=callback; dvbdmxfeed->demux=dvbdmx; dvbdmxfeed->pid=0xffff; - dvbdmxfeed->feed.sec.secbufp=0; + dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; + dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; + dvbdmxfeed->feed.sec.tsfeedp = 0; dvbdmxfeed->filter=0; dvbdmxfeed->buffer=0; diff -puN drivers/media/dvb/dvb-core/dvb_demux.h~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_demux.h --- 25/drivers/media/dvb/dvb-core/dvb_demux.h~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_demux.h Fri Dec 19 14:54:10 2003 @@ -127,7 +127,7 @@ struct dvb_demux { #define DMX_MAX_PID 0x2000 struct list_head feed_list; - u8 tsbuf[188]; + u8 tsbuf[204]; int tsbufp; struct semaphore mutex; @@ -140,6 +140,7 @@ int dvb_dmx_release(struct dvb_demux *dv void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf); void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend); int dvbdmx_disconnect_frontend(struct dmx_demux *demux); diff -puN drivers/media/dvb/dvb-core/dvb_filter.c~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_filter.c --- 25/drivers/media/dvb/dvb-core/dvb_filter.c~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_filter.c Fri Dec 19 14:54:10 2003 @@ -564,14 +564,18 @@ void dvb_filter_pes2ts_init(struct dvb_f p2ts->priv=priv; } -int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, int len) +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start) { unsigned char *buf=p2ts->buf; int ret=0, rest; //len=6+((pes[4]<<8)|pes[5]); + if (payload_start) buf[1]|=0x40; + else + buf[1]&=~0x40; while (len>=184) { buf[3]=0x10|((p2ts->cc++)&0x0f); memcpy(buf+4, pes, 184); diff -puN drivers/media/dvb/dvb-core/dvb_filter.h~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_filter.h --- 25/drivers/media/dvb/dvb-core/dvb_filter.h~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_filter.h Fri Dec 19 14:54:10 2003 @@ -37,7 +37,8 @@ struct dvb_filter_pes2ts { void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, dvb_filter_pes2ts_cb_t *cb, void *priv); -int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, int len); +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start); #define PROG_STREAM_MAP 0xBC diff -puN drivers/media/dvb/dvb-core/dvb_i2c.c~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_i2c.c --- 25/drivers/media/dvb/dvb-core/dvb_i2c.c~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_i2c.c Fri Dec 19 14:54:10 2003 @@ -51,6 +51,7 @@ static int register_i2c_client (struct d client->detach = dev->detach; client->owner = dev->owner; + client->data = dev->data; INIT_LIST_HEAD(&client->list_head); diff -puN drivers/media/dvb/dvb-core/dvb_ksyms.c~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_ksyms.c --- 25/drivers/media/dvb/dvb-core/dvb_ksyms.c~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_ksyms.c Fri Dec 19 14:54:10 2003 @@ -18,6 +18,7 @@ EXPORT_SYMBOL(dvb_dmx_release); EXPORT_SYMBOL(dvb_dmx_swfilter_packet); EXPORT_SYMBOL(dvb_dmx_swfilter_packets); EXPORT_SYMBOL(dvb_dmx_swfilter); +EXPORT_SYMBOL(dvb_dmx_swfilter_204); EXPORT_SYMBOL(dvbdmx_connect_frontend); EXPORT_SYMBOL(dvbdmx_disconnect_frontend); diff -puN drivers/media/dvb/dvb-core/dvb_ringbuffer.c~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_ringbuffer.c --- 25/drivers/media/dvb/dvb-core/dvb_ringbuffer.c~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_ringbuffer.c Fri Dec 19 14:54:10 2003 @@ -9,24 +9,18 @@ * & Marcus Metzler for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * - * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/dvb/ */ @@ -167,11 +161,11 @@ ssize_t dvb_ringbuffer_write(struct dvb_ } -EXPORT_SYMBOL_GPL(dvb_ringbuffer_init); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_empty); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_free); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_avail); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_flush); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_flush_spinlock_wakeup); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_read); -EXPORT_SYMBOL_GPL(dvb_ringbuffer_write); +EXPORT_SYMBOL(dvb_ringbuffer_init); +EXPORT_SYMBOL(dvb_ringbuffer_empty); +EXPORT_SYMBOL(dvb_ringbuffer_free); +EXPORT_SYMBOL(dvb_ringbuffer_avail); +EXPORT_SYMBOL(dvb_ringbuffer_flush); +EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); +EXPORT_SYMBOL(dvb_ringbuffer_read); +EXPORT_SYMBOL(dvb_ringbuffer_write); diff -puN drivers/media/dvb/dvb-core/dvb_ringbuffer.h~dvb-05-core-update drivers/media/dvb/dvb-core/dvb_ringbuffer.h --- 25/drivers/media/dvb/dvb-core/dvb_ringbuffer.h~dvb-05-core-update Fri Dec 19 14:54:10 2003 +++ 25-akpm/drivers/media/dvb/dvb-core/dvb_ringbuffer.h Fri Dec 19 14:54:10 2003 @@ -16,7 +16,7 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software _