[BACK]Return to av7110_ipack.c CVS log [TXT][DIR] Up to [Development] / linux-2.6-xfs / drivers / media / dvb / ttpci

File: [Development] / linux-2.6-xfs / drivers / media / dvb / ttpci / av7110_ipack.c (download)

Revision 1.2, Thu Jan 29 19:23:16 2004 UTC (13 years, 9 months ago) by nathans
Branch: MAIN
Changes since 1.1: +62 -58 lines

Merge up to 2.6.2-rc2

#include "dvb_filter.h"
#include "av7110_ipack.h"
#include <linux/string.h>	/* for memcpy() */
#include <linux/vmalloc.h>


void av7110_ipack_reset(struct ipack *p)
{
	p->found = 0;
	p->cid = 0;
	p->plength = 0;
	p->flag1 = 0;
	p->flag2 = 0;
	p->hlength = 0;
	p->mpeg = 0;
	p->check = 0;
	p->which = 0;
	p->done = 0;
	p->count = 0;
}


int av7110_ipack_init(struct ipack *p, int size,
		       void (*func)(u8 *buf, int size, void *priv))
{
	if ( !(p->buf = vmalloc(size*sizeof(u8))) ){
		printk ("Couldn't allocate memory for ipack\n");
		return -ENOMEM;
	}
	p->size = size;
	p->func = func;
	p->repack_subids = 0;
	av7110_ipack_reset(p);
	return 0;
}


void av7110_ipack_free(struct ipack * p)
{
	if (p->buf)
		vfree(p->buf);
}


static void send_ipack(struct ipack *p)
{
	int off;
	struct dvb_audio_info ai;
	int ac3_off = 0;
	int streamid=0;
	int nframes= 0;
	int f=0;

	switch ( p->mpeg ){
	case 2:		
		if (p->count < 10)
			return;
		p->buf[3] = p->cid;
		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
		if (p->repack_subids && p->cid == PRIVATE_STREAM1){
			off = 9+p->buf[8];
			streamid = p->buf[off];
			if ((streamid & 0xf8) == 0x80) {
				ai.off = 0;
				ac3_off = ((p->buf[off+2] << 8)| 
					   p->buf[off+3]);
				if (ac3_off < p->count)
					f=dvb_filter_get_ac3info(p->buf+off+3+ac3_off, 
						      p->count-ac3_off, &ai,0);
				if ( !f ){
					nframes = (p->count-off-3-ac3_off)/ 
						ai.framesize + 1;
					p->buf[off + 2] = (ac3_off >> 8) & 0xff;
					p->buf[off + 3] = (ac3_off) & 0xff;
					p->buf[off+1] = nframes;
					ac3_off +=  nframes * ai.framesize - p->count;
				}
			}
		} 
		p->func(p->buf, p->count, p->data);
	
		p->buf[6] = 0x80;
		p->buf[7] = 0x00;
		p->buf[8] = 0x00;
		p->count = 9;
		if (p->repack_subids && p->cid == PRIVATE_STREAM1 
		    && (streamid & 0xf8) == 0x80) {
			p->count += 4;
			p->buf[9] = streamid;
			p->buf[10] = (ac3_off >> 8) & 0xff;
			p->buf[11] = (ac3_off) & 0xff;
			p->buf[12] = 0;
		}
		break;

	case 1:
		if (p->count < 8)
			return;
		p->buf[3] = p->cid;
		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
		p->func(p->buf, p->count, p->data);
	
		p->buf[6] = 0x0f;
		p->count = 7;
		break;
	}
}


void av7110_ipack_flush(struct ipack *p)
{
	if (p->plength != MMAX_PLENGTH-6 || p->found<=6)
		return;
	p->plength = p->found-6;
	p->found = 0;
	send_ipack(p);
	av7110_ipack_reset(p);
}


static void write_ipack(struct ipack *p, const u8 *data, int count)
{
	u8 headr[3] = { 0x00, 0x00, 0x01} ;

	if (p->count < 6){
		memcpy(p->buf, headr, 3);
		p->count = 6;
	}

	if (p->count + count < p->size){
		memcpy(p->buf+p->count, data, count);
		p->count += count;
	} else {
		int rest = p->size - p->count;
		memcpy(p->buf+p->count, data, rest);
		p->count += rest;
		send_ipack(p);
		if (count - rest > 0)
			write_ipack(p, data+rest, count-rest);
	}
}


int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
{
	int l;
	int c=0;

	while (c < count && (p->mpeg == 0 ||
			     (p->mpeg == 1 && p->found < 7) ||
			     (p->mpeg == 2 && p->found < 9))
	       &&  (p->found < 5 || !p->done)){
		switch ( p->found ){
		case 0:
		case 1:
			if (buf[c] == 0x00)
				p->found++;
			else
				p->found = 0;
			c++;
			break;
		case 2:
			if (buf[c] == 0x01)
				p->found++;
			else if (buf[c] == 0)
				p->found = 2;
			else
				p->found = 0;
			c++;
			break;
		case 3:
			p->cid = 0;
			switch (buf[c]){
			case PROG_STREAM_MAP:
			case PRIVATE_STREAM2:
			case PROG_STREAM_DIR:
			case ECM_STREAM     :
			case EMM_STREAM     :
			case PADDING_STREAM :
			case DSM_CC_STREAM  :
			case ISO13522_STREAM:
				p->done = 1;
				/* fall through */
			case PRIVATE_STREAM1:
			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
				p->found++;
				p->cid = buf[c];
				c++;
				break;
			default:
				p->found = 0;
				break;
			}
			break;
			
		case 4:
			if (count-c > 1){
				p->plen[0] = buf[c];
				c++;
				p->plen[1] = buf[c];
				c++;
				p->found+=2;
				p->plength=(p->plen[0]<<8)|p->plen[1];
 			} else {
				p->plen[0] = buf[c];
				p->found++;
				return count;
			}
			break;
		case 5:
			p->plen[1] = buf[c];
			c++;
			p->found++;
			p->plength=(p->plen[0]<<8)|p->plen[1];
			break;
		case 6:
			if (!p->done){
				p->flag1 = buf[c];
				c++;
				p->found++;
				if ((p->flag1 & 0xc0) == 0x80)
					p->mpeg = 2;
				else {
					p->hlength = 0;
					p->which = 0;
					p->mpeg = 1;
					p->flag2 = 0;
				}
			}
			break;

		case 7:
			if ( !p->done && p->mpeg == 2) {
				p->flag2 = buf[c];
				c++;
				p->found++;
			}	
			break;

		case 8:
			if ( !p->done && p->mpeg == 2) {
				p->hlength = buf[c];
				c++;
				p->found++;
			}
			break;
		}
	}

	if (c == count)
		return count;

	if (!p->plength)
		p->plength = MMAX_PLENGTH - 6;

	if ( p->done || ((p->mpeg == 2 && p->found >= 9) || 
	     (p->mpeg == 1 && p->found >= 7)) ){
		switch (p->cid){
			
		case AUDIO_STREAM_S ... AUDIO_STREAM_E:			
		case VIDEO_STREAM_S ... VIDEO_STREAM_E:
		case PRIVATE_STREAM1:
			
			if (p->mpeg == 2 && p->found == 9) {
				write_ipack(p, &p->flag1, 1);
				write_ipack(p, &p->flag2, 1);
				write_ipack(p, &p->hlength, 1);
			}

			if (p->mpeg == 1 && p->found == 7) 
				write_ipack(p, &p->flag1, 1);
			
			if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&  
			    p->found < 14) {
				while (c < count && p->found < 14) {
					p->pts[p->found-9] = buf[c];
					write_ipack(p, buf+c, 1);
					c++;
					p->found++;
				}
				if (c == count)
					return count;
			}

			if (p->mpeg == 1 && p->which < 2000) {

				if (p->found == 7) {
					p->check = p->flag1;
					p->hlength = 1;
				}

				while (!p->which && c < count && 
				       p->check == 0xff){
					p->check = buf[c];
					write_ipack(p, buf+c, 1);
					c++;
					p->found++;
					p->hlength++;
				}
				
				if (c == count)
					return count;
				
				if ((p->check & 0xc0) == 0x40 && !p->which) {
					p->check = buf[c];
					write_ipack(p, buf+c, 1);
					c++;
					p->found++;
					p->hlength++;
					
					p->which = 1;
					if (c == count)
						return count;
					p->check = buf[c];
					write_ipack(p, buf+c, 1);
					c++;
					p->found++;
					p->hlength++;
					p->which = 2;
					if (c == count)
						return count;
				}
				
				if (p->which == 1){
					p->check = buf[c];
					write_ipack(p, buf+c, 1);
					c++;
					p->found++;
					p->hlength++;
					p->which = 2;
					if (c == count)
						return count;
				}
				
				if ((p->check & 0x30) && p->check != 0xff) {
					p->flag2 = (p->check & 0xf0) << 2;
					p->pts[0] = p->check;
					p->which = 3;
				} 
			
				if (c == count)
					return count;
				if (p->which > 2){
					if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
						while (c < count && p->which < 7) {
							p->pts[p->which - 2] = buf[c];
							write_ipack(p,buf+c,1);
							c++;
							p->found++;
							p->which++;
							p->hlength++;
						}
						if (c == count)
							return count;
					} else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
						while (c < count && p->which < 12) {
							if (p->which< 7)
								p->pts[p->which - 2] = buf[c];
							write_ipack(p,buf+c,1);
							c++;
							p->found++;
							p->which++;
							p->hlength++;
						}
						if (c == count)
							return count;
					}
					p->which = 2000;
				}
				
			}
			
			while (c < count && p->found < p->plength+6){
				l = count -c;
				if (l+p->found > p->plength+6)
					l = p->plength+6-p->found;
				write_ipack(p, buf+c, l);
				p->found += l;
				c += l;
			}	
			
			break;
		}


		if ( p->done ){
			if( p->found + count - c < p->plength+6){
				p->found += count-c;
				c = count;
			} else {
				c += p->plength+6 - p->found;
				p->found = p->plength+6;
			}
		}

		if (p->plength && p->found == p->plength+6) {
			send_ipack(p);
			av7110_ipack_reset(p);
			if (c < count)
				av7110_ipack_instant_repack(buf+c, count-c, p);
		}
	}
	return count;
}