/*
 * ts2pes.cpp
 *
 * code from mpegtools for the Siemens Fujitsu DVB PCI card
 * Copyright (C) 2000,2001 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 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "ts2pes.h"

#define FILE_LIMIT 1024*1024*2047



/*QFile fileOutPes;
QString fileOutName;
int fileOutNum;
char fileOutIndex[10]={'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
int fileLength;*/

unsigned int g_bitrates[3][16] =
{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
 {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
 {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};

uint32_t g_freq[4] = {441, 480, 320, 0};



uint64_t Ts2Pes::trans_pts_dts(uint8_t *pts)
{
	uint64_t wts;

	wts = ((uint64_t)((pts[0] & 0x0E) << 5) |
	       ((pts[1] & 0xFC) >> 2)) << 24;
	wts |= (((pts[1] & 0x03) << 6) |
		((pts[2] & 0xFC) >> 2)) << 16;
	wts |= (((pts[2] & 0x02) << 6) |
		((pts[3] & 0xFE) >> 1)) << 8;
	wts |= (((pts[3] & 0x01) << 7) |
		((pts[4] & 0xFE) >> 1));
	return wts;
}



uint16_t Ts2Pes::get_pid(uint8_t *pid)
{
	uint16_t pp = 0;

	pp = (pid[0] & PID_MASK_HI)<<8;
	pp |= pid[1];

	return pp;
}



void Ts2Pes::reset_ipack(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;
	p->size = p->size_orig;
}



void Ts2Pes::init_ipack(ipack *p, int size, void (*func)(uint8_t *buf,  int size, void *priv), int ps)
{
	if ( !(p->buf = (uint8_t*)malloc(size)) ){
		fprintf(stderr,"Couldn't allocate memory for ipack\n");
		//exit(1);
	}
	p->ps = ps;
	p->size_orig = size;
	p->func = func;
	reset_ipack(p);
	p->has_ai = 0;
	p->has_vi = 0;
	p->start = 0;
}



void Ts2Pes::write_ipack(ipack *p, uint8_t *data, int count)
{

	uint8_t headr[3] = { 0x00, 0x00, 0x01} ;
	int diff =0;

	if (p->count < 6){
		if (trans_pts_dts(p->pts) > trans_pts_dts(p->last_pts))
			memcpy(p->last_pts, p->pts, 5);
		p->count = 0;
		memcpy(p->buf+p->count, headr, 3);
		p->count += 6;
	}
	if ( p->size == p->size_orig && p->plength &&
	     (diff = 6+p->plength - p->found + p->count +count) > p->size &&
	     diff < 3*p->size/2){

			p->size = diff/2;
//			fprintf(stderr,"size: %d \n",p->size);
	}
	if (p->count + count < p->size){
		memcpy(p->buf+p->count, data, count);
		p->count += count;
	} else {
		int rest = p->size - p->count;
		if (rest < 0) rest = 0;
		memcpy(p->buf+p->count, data, rest);
		p->count += rest;
//		fprintf(stderr,"count: %d \n",p->count);
		send_ipack(p);
		if (count - rest > 0)
			write_ipack(p, data+rest, count-rest);
	}
}



int Ts2Pes::getVinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr)
{
	uint8_t *headr;
	int found = 0;
        int sw;
	int form = -1;
	int c = 0;

	while (found < 4 && c+4 < count){
		uint8_t *b;

		b = mbuf+c;
		if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
		     && b[3] == 0xb3) found = 4;
		else {
			c++;
		}
	}

	if (! found) return -1;
	c += 4;
	if (c+12 >= count) return -1;
	headr = mbuf+c;

	vi->horizontal_size	= ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
	vi->vertical_size	= ((headr[1] &0x0F) << 8) | (headr[2]);

        sw = (int)((headr[3]&0xF0) >> 4) ;

        switch( sw ){
	case 1:
		if (pr)
			fprintf(stderr,"Videostream: ASPECT: 1:1");
		vi->aspect_ratio = 100;
		break;
	case 2:
		if (pr)
			fprintf(stderr,"Videostream: ASPECT: 4:3");
                vi->aspect_ratio = 133;
		break;
	case 3:
		if (pr)
			fprintf(stderr,"Videostream: ASPECT: 16:9");
                vi->aspect_ratio = 177;
		break;
	case 4:
		if (pr)
			fprintf(stderr,"Videostream: ASPECT: 2.21:1");
                vi->aspect_ratio = 221;
		break;

        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
		if (pr)
			fprintf(stderr,"Videostream: ASPECT: reserved");
                vi->aspect_ratio = 0;
		break;

        default:
                vi->aspect_ratio = 0;
                return -1;
	}

	if (pr)
		fprintf(stderr,"  Size = %dx%d",vi->horizontal_size,
			vi->vertical_size);

        sw = (int)(headr[3]&0x0F);

        switch ( sw ) {
	case 1:
		if (pr)
			fprintf(stderr,"  FRate: 23.976 fps");
                vi->framerate = 24000/1001.;
		form = -1;
		break;
	case 2:
		if (pr)
			fprintf(stderr,"  FRate: 24 fps");
                vi->framerate = 24;
		form = -1;
		break;
	case 3:
		if (pr)
			fprintf(stderr,"  FRate: 25 fps");
                vi->framerate = 25;
		form = VIDEO_MODE_PAL;
		break;
	case 4:
		if (pr)
			fprintf(stderr,"  FRate: 29.97 fps");
                vi->framerate = 30000/1001.;
		form = VIDEO_MODE_NTSC;
		break;
	case 5:
		if (pr)
			fprintf(stderr,"  FRate: 30 fps");
                vi->framerate = 30;
		form = VIDEO_MODE_NTSC;
		break;
	case 6:
		if (pr)
			fprintf(stderr,"  FRate: 50 fps");
                vi->framerate = 50;
		form = VIDEO_MODE_PAL;
		break;
	case 7:
		if (pr)
			fprintf(stderr,"  FRate: 60 fps");
                vi->framerate = 60;
		form = VIDEO_MODE_NTSC;
		break;
	}

	vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL)
			    | ((headr[5] << 2) & 0x000003FCUL) |
			    (((headr[6] & 0xC0) >> 6) & 0x00000003UL));

	if (pr){
		fprintf(stderr,"  BRate: %.2f Mbit/s",(vi->bit_rate)/1000000.);
		fprintf(stderr,"\n");
	}
        vi->video_format = form;

	vi->off = c-4;
	return c-4;
}



int Ts2Pes::getAinfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr)
{
	uint8_t *headr;
	int found = 0;
	int c = 0;
	int fr =0;

	while (!found && c < count){
		uint8_t *b = mbuf+c;

		if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
			found = 1;
		else {
			c++;
		}
	}

	if (!found) return -1;

	if (c+3 >= count) return -1;
        headr = mbuf+c;

	ai->layer = (headr[1] & 0x06) >> 1;

        if (pr)
		fprintf(stderr,"Audiostream: Layer: %d", 4-ai->layer);


	ai->bit_rate = g_bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;

	if (pr){
		if (ai->bit_rate == 0)
			fprintf (stderr,"  Bit rate: free");
		else if (ai->bit_rate == 0xf)
			fprintf (stderr,"  BRate: reserved");
		else
			fprintf (stderr,"  BRate: %d kb/s", ai->bit_rate/1000);
	}

	fr = (headr[2] & 0x0c ) >> 2;
	ai->frequency = g_freq[fr]*100;

	if (pr){
		if (ai->frequency == 3)
			fprintf (stderr, "  Freq: reserved\n");
		else
			fprintf (stderr,"  Freq: %2.1f kHz\n",
				 ai->frequency/1000.);
	}
	ai->off = c;
	return c;
}



void Ts2Pes::psPes(ipack *p)
{
	int check;
	uint8_t pbuf[PS_HEADER_L2];
	static int muxr = 0;
	static int ai = 0;
	static int vi = 0;
	static int start = 0;
	static uint32_t SCR = 0;

	if (p->mpeg == 2){
		if ( (p->buf[3]>=VIDEO_STREAM_S) && (p->buf[3]<=VIDEO_STREAM_E) ) {
			if (!p->has_vi){
				if(getVinfo(p->buf, p->count, &p->vi,1) >=0) {
					p->has_vi = 1;
					vi = p->vi.bit_rate;
				}
			}
		}
		else if ( (p->buf[3]>=AUDIO_STREAM_S) && (p->buf[3]<=AUDIO_STREAM_E) ) {
			if (!p->has_ai){
				if(getAinfo(p->buf, p->count, &p->ai,1) >=0) {
					p->has_ai = 1;
					ai = p->ai.bit_rate;
				}
			}
		}

		if (p->has_vi && vi && !muxr){
			muxr = (vi+ai)/400;
		}

		if ( start && muxr && (p->buf[7] & PTS_ONLY) && (p->has_ai ||
				       p->buf[9+p->buf[8]+4] == 0xb3)){
			SCR = trans_pts_dts(p->pts)-3600;

			check = write_ps_header(pbuf,
						SCR,
						muxr, 1, 0, 0, 1, 1, 1,
						0, 0, 0, 0, 0, 0);

			p->func(pbuf, check , p->data);
		}

		if (muxr && !start && vi){
			SCR = trans_pts_dts(p->pts)-3600;
			check = write_ps_header(pbuf,
						SCR,
						muxr, 1, 0, 0, 1, 1, 1,
						0xC0, 0, 64, 0xE0, 1, 460);
			start = 1;
			p->func(pbuf, check , p->data);
		}

		if (start)
			p->func(p->buf, p->count, p->data);
	}
}



void Ts2Pes::init_ps(ps_packet *p)
{
	p->stuff_length=0xF8;
	p->data = NULL;
	p->sheader_length = 0;
	p->audio_bound = 0;
	p->video_bound = 0;
	p->npes = 0;
	p->mpeg = 2;
}



void Ts2Pes::kill_ps(ps_packet *p)
{
	if (p->data)
		free(p->data);
	init_ps(p);
}



int Ts2Pes::cwrite_ps(uint8_t *buf, ps_packet *p, long length)
{
	long count, i=length;
	uint8_t headr1[4] = {0x00, 0x00, 0x01, 0xBA };
	uint8_t headr2[4] = {0x00, 0x00, 0x01, 0xBB };
	uint8_t buffy = 0xFF;


	memcpy(buf,headr1,4);
	count = 4;
	if (p->mpeg == 2){
		memcpy(buf+count,p->scr,6);
		count += 6;
		memcpy(buf+count,p->mux_rate,3);
		count += 3;
		memcpy(buf+count,&p->stuff_length,1);
		count++;
		for(i=0; i< (p->stuff_length & 3); i++){
			memcpy(buf+count,&buffy,1);
			count++;
		}
	} else {
		memcpy(buf+count,p->scr,5);
		count += 5;
		memcpy(buf+count,p->mux_rate,3);
		count += 3;
	}
	if (p->sheader_length){
		memcpy(buf+count,headr2,4);
		count += 4;
		memcpy(buf+count,p->sheader_llength,2);
		count += 2;
		if ( p->mpeg == 2){
			memcpy(buf+count,p->rate_bound,3);
			count += 3;
			memcpy(buf+count,&p->audio_bound,1);
			count++;
			memcpy(buf+count,&p->video_bound,1);
			count++;
			memcpy(buf+count,&p->reserved,1);
			count++;
		}
		memcpy(buf+count,p->data,p->sheader_length);
		count += p->sheader_length;
	}

	return count;
}



void Ts2Pes::setl_ps(ps_packet *p)
{
	short *ll;

	ll = (short *) p->sheader_llength;
	if (p->mpeg == 2) p->sheader_length = ntohs(*ll) - 6;
	else p->sheader_length = ntohs(*ll);
	p->data = (uint8_t *) malloc(p->sheader_length);
}



int Ts2Pes::write_ps_header( uint8_t *buf, uint32_t SCR, long muxr, uint8_t audio_bound, uint8_t fixed,
		    uint8_t CSPS, uint8_t audio_lock, uint8_t video_lock, uint8_t video_bound, uint8_t stream1,
		    uint8_t buffer1_scale, uint32_t buffer1_size, uint8_t stream2, uint8_t buffer2_scale, uint32_t buffer2_size)
{
	ps_packet p;
	uint8_t *pts;
	long lpts;
	init_ps(&p);

	lpts = htonl(SCR);
	pts = (uint8_t *) &lpts;


	p.mpeg = 2;
// SCR = 0
	p.scr[0] = 0x44;
	p.scr[1] = 0x00;
	p.scr[2] = 0x04;
	p.scr[3] = 0x00;
	p.scr[4] = 0x04;
	p.scr[5] = 0x01;

// SCR = PTS
	p.scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03);
	p.scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F);
	p.scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08)
		| ((pts[2] >> 5)&0x03);
	p.scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07);
	p.scr[4] = 0x04 | ((pts[3] << 3)&0xF8);
	p.scr[5] = 0x01;

	p.mux_rate[0] = (uint8_t)(muxr >> 14);
	p.mux_rate[1] = (uint8_t)(0xff & (muxr >> 6));
	p.mux_rate[2] = (uint8_t)(0x03 | ((muxr & 0x3f) << 2));

	p.stuff_length = 0xF8;

	if (stream1 && stream2){
		p.sheader_llength[0] = 0x00;
		p.sheader_llength[1] = 0x0c;

		setl_ps(&p);

		p.rate_bound[0] = (uint8_t)(0x80 | (muxr >>15));
		p.rate_bound[1] = (uint8_t)(0xff & (muxr >> 7));
		p.rate_bound[2] = (uint8_t)(0x01 | ((muxr & 0x7f)<<1));


		p.audio_bound = (uint8_t)((audio_bound << 2)|(fixed << 1)|CSPS);
		p.video_bound = (uint8_t)((audio_lock << 7)|
				     (video_lock << 6)|0x20|video_bound);
		p.reserved = (uint8_t)(0xFF >> 1);

		p.data[0] =  stream2;
		p.data[1] =  (uint8_t) (0xc0 | (buffer2_scale << 5) |
				   (buffer2_size >> 8));
		p.data[2] =  (uint8_t) (buffer2_size & 0xff);
		p.data[3] =  stream1;
		p.data[4] =  (uint8_t) (0xc0 | (buffer1_scale << 5) |
				   (buffer1_size >> 8));
		p.data[5] =  (uint8_t) (buffer1_size & 0xff);

		cwrite_ps(buf, &p, PS_HEADER_L2);
		kill_ps(&p);
		return PS_HEADER_L2;
	} else {
		cwrite_ps(buf, &p, PS_HEADER_L1);
		kill_ps(&p);
		return PS_HEADER_L1;
	}
}



void Ts2Pes::send_ipack(ipack *p)
{
	//int streamid=0;
	//int off;
	//int ac3_off = 0;
	//AudioInfo ai;
	//int nframes= 0;
	//int f=0;

	if (p->count < 10) return;
	p->buf[3] = p->cid;
	p->buf[4] = (uint8_t)(((p->count-6) & 0xFF00) >> 8);
	p->buf[5] = (uint8_t)((p->count-6) & 0x00FF);


	/*if (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=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;
			}
		}
	}*/

	if (p->ps) psPes(p);
	else p->func(p->buf, p->count, p->data);

	switch ( p->mpeg ){
	case 2:

		p->buf[6] = 0x80;
		p->buf[7] = 0x00;
		p->buf[8] = 0x00;
		p->count = 9;

		/*if (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:
		p->buf[6] = 0x0F;
		p->count = 7;
		break;
	}

}



void Ts2Pes::instant_repack (uint8_t *buf, int count, ipack *p)
{

	int l;
	unsigned short *pl;
	int c=0;
	int tmp;

	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;
			tmp = p->found;
			p->found = 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->found = tmp;
					p->done = 1;
			}
			if ( ( (buf[c]>=VIDEO_STREAM_S) && (buf[c]<=VIDEO_STREAM_E) )
				|| ( (buf[c]>=AUDIO_STREAM_S) && (buf[c]<=AUDIO_STREAM_E) )
				|| (buf[c]==PRIVATE_STREAM1) ) {
				p->found = tmp;
				p->found++;
				p->cid = buf[c];
				c++;
			}
			break;
		case 4:
			if (count-c > 1){
				pl = (unsigned short *) (buf+c);
				p->plength =  ntohs(*pl);
				p->plen[0] = buf[c];
				c++;
				p->plen[1] = buf[c];
				c++;
				p->found+=2;
			} else {
				p->plen[0] = buf[c];
				p->found++;
				return;
			}
			break;
		case 5:
			p->plen[1] = buf[c];
			c++;
			pl = (unsigned short *) p->plen;
			p->plength = ntohs(*pl);
			p->found++;
			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;

		default:

			break;
		}
	}


	if (c == count) return;

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


	if ( p->done || ((p->mpeg == 2 && p->found >= 9)  || (p->mpeg == 1 && p->found >= 7)) ) {
		 if ( ( (p->cid>=VIDEO_STREAM_S) && (p->cid<=VIDEO_STREAM_E) )
		 	|| ( (p->cid>=AUDIO_STREAM_S) && (p->cid<=AUDIO_STREAM_E) )
			|| (p->cid==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;
			}

			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;

				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;
					p->check = buf[c];
					write_ipack(p, buf+c, 1);
					c++;
					p->found++;
					p->hlength++;
					p->which = 2;
					if ( c == count) return;
				}

				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;
				}

				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;
				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;
					} 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;
					}
					p->which = 2000;
				}

			}

			while ( c<count && p->found<(int)p->plength+6){
				l = count -c;
				if (l+p->found > (int)p->plength+6)
					l = p->plength+6-p->found;
				write_ipack(p, buf+c, l);
				p->found += l;
				c += l;
			}
		}


		if ( p->done ){
			if( p->found + count - c < (int)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 == (int)p->plength+6) {
			send_ipack(p);
			reset_ipack(p);
			if (c < count)
				instant_repack(buf+c, count-c, p);
		}
	}
	return;
}




void Ts2Pes::write_out( uint8_t *buf, int count, void  *p)
{
	Ts2Pes *tp = (Ts2Pes*)(p);
	/*if ( (fileLength+count)>FILE_LIMIT ) {
		fileOutPes.close();
		fileOutNum++;
		if ( fileOutNum>9 ) {
			return;
		}
		fileOutPes.setName( fileOutName+"_"+fileOutIndex[fileOutNum]+".mpg" );
		if ( !fileOutPes.open( IO_WriteOnly | IO_Truncate ) ) {
			return;
		}
		fileLength = 0;
	}*/
	//fileLength+=
	tp->fileOutPes.writeBlock( (char*)buf, count );
}



Ts2Pes::Ts2Pes( QString outfile, uint16_t pida, uint16_t pidv, int ps, bool *ok )
{
	*ok = true;

	pa.data = this;
	pv.data = this;
	pidAudio = pida;
	pidVideo = pidv;
	pType = ps;
	fileOutPes.setName( outfile+".mpg" );
	if ( !fileOutPes.open( IO_WriteOnly | IO_Truncate ) ) *ok = false;
}



void Ts2Pes::run( uint8_t *buf, int count )
{
	int i;
	uint16_t pid;

	for( i = 0; i < count; i+= TS_SIZE){
		uint8_t off = 0;
		if ( count - i < TS_SIZE) break;
		pid = get_pid(buf+i+1);
		if (!(buf[3+i]&0x10)) // no payload?
			continue;
		if (pid == pidVideo){
			p = &pv;
		} else {
			if (pid == pidAudio){
				p = &pa;
			} else continue;
		}
		if ( buf[1+i]&0x40) {
			if (p->plength == MMAX_PLENGTH-6){
				p->plength = p->found-6;
				p->found = 0;
				send_ipack(p);
				reset_ipack(p);
			}
		}

		if ( buf[3+i] & 0x20) {  // adaptation field?
			off = buf[4+i] + 1;
		}

		instant_repack(buf+4+off+i, TS_SIZE-4-off, p);
	}
}



void Ts2Pes::go()
{
	init_ipack(&pa, IPACKS,write_out, pType);
	init_ipack(&pv, IPACKS,write_out, pType);
}



void Ts2Pes::stop()
{
	fileOutPes.close();
}



Ts2Pes::~Ts2Pes()
{
	fileOutPes.close();
}
