/*************************************************************
 *   mpgtx an mpeg toolbox                                   *
 *   by Laurent Alacoque <laureck@users.sourceforge.net>     *
 *   (c) 2001                                                *
 *   You may copy, modify and redistribute this              *
 *   source file under the terms of the GNU Public License   *
 ************************************************************/


#include "mpegOut.hh"
#include "common.hh"
#include <stdio.h>
#include <stdlib.h>
// original was 0.015
#define base_TS_correction 0.015
// hate me for the globals ... Begin philipp mod
// 
extern bool aspect_correction; // flag if corretion is needed
extern byte forced_sequence_header; // the new aspect ratio
extern bool preserve_header; // flag if junk at the start of a file should be preserved
extern bool print_progress;  // print more info while processing
void print_ts(byte *p); // prints the timestamp of a mpeg2 gop - only for testing
// end philipp mod
//  #define _DEBUG_

#ifdef _DEBUG_
int count=0;
#endif


mpegOut::mpegOut(char* filename) {
	BTRACK;
	//	fprintf(stderr, "constructing mpegOut %s\n",filename);
	if (!access(filename, F_OK)) {
		// file already exist
		//fprintf(stderr,"File %s already exist\n",filename);
	}
	//open file for writing/truncate
	MpegOut = fopen(filename, "wb");

	if (MpegOut == 0) {
		// Gosh ! unable to open
		fprintf(stderr, "Unable to open %s for writing\n", filename);
		perror("reason: ");
	}

	HasAudio = HasVideo = false;
	FileType = mpeg_EMPTY;	
}


mpegOut::mpegOut(FILE* filehandle) {
	BTRACK;
	//	fprintf(stderr,"constructing mpegOut with filehandle\n");
	MpegOut = filehandle;	
	HasAudio = HasVideo = false;
	FileType = mpeg_EMPTY;	
}


mpegOut::~mpegOut() {
	BTRACK;
	//	printf("destructing mpegOut \n");
	if (MpegOut != 0) fclose (MpegOut);
}


void mpegSystemOut::WriteHeader(mpeg* Mpeg){
	header_buf *pbfix;
	int mpeg2stuff_bytes;
	BTRACK;
	//Have to write system headers and video sequence
	if (!MpegOut) return;
	if (!Mpeg) return;
 	if (preserve_header) {
		fprintf(stderr,"now reapplying junk-header ....\n"); 
		/* read original bytes of header */
		/* from 0 to offset to video */
		pbfix = readHeader(MpegOut,0,2);
		// fprintf(stderr,"Size of header still: 0x%qx\n",pbfix->size);
		fwrite(pbfix->buf,pbfix->size,1,MpegOut);
	} 
	mpeg_version = Mpeg->Version();
	if (!preserve_header) { // alternatively, create our own header

	if(Mpeg->System->video_system_header)
		fwrite(Mpeg->System->video_system_header,
			1,	Mpeg->System->video_system_header_length,	MpegOut); 
	if (Mpeg->System->audio_system_header)
		fwrite(Mpeg->System->audio_system_header,
			1,	Mpeg->System->audio_system_header_length,	MpegOut);
	}

	// okay system headers are written...
	// let's write the PACK + video packet header
	// we keep the remaining in mem because we need to 
	// correct the packet length before outputing it (stdout is not
	// seekable:/
	off_t PACKlength = 0;
        mpeg2stuff_bytes = 4;
	if ((Mpeg->System->first_video_packet[4] & 0xF0) == 0x20) {
		//standard mpeg1 pack
		PACKlength = 12;
	} else {
		if ((Mpeg->System->first_video_packet[4] & 0xC0) == 0x40) {
			//new mpeg2 pack : 14 bytes + what stuffing ?
			mpeg2stuff_bytes = Mpeg->System->first_video_packet[13] & 0x07;
			PACKlength = 14;
#ifdef _DEBUG_
			fprintf(stderr,"packlength %qx\n",PACKlength);
			fprintf(stderr,"firstVideopacket: \n");
			for (count = 0; count < Mpeg->System->first_video_packet_length; ++count)
			{
				fprintf(stderr,"%02x ",Mpeg->System->first_video_packet[count]);

			}		
			fprintf(stderr,"\n-------\n");
#endif
		} else {
			//wazup?
			// May 28 2001: maybe there's no pack at all...
			byte packetcode = Mpeg->System->first_video_packet[3] & 0xF0;
			if (packetcode == 0xE0 || packetcode == 0xD0 ) {
				// this is a video packet that dosnt have a pack before
				PACKlength = 0;
			} else {

				if(Mpeg->System->first_video_packet[3] != 0xba) {
					//neither a PACK nor a video packet
					fprintf(stderr, "I'm lost, ciao\n");
					exit(1);
				}
				fprintf(stderr, "Weird PACK encountered don't seem to be mpeg 1 nor mpeg 2.\n");
				fprintf(stderr, "I most certainly crash in a minute but I love risk.\n");

				// try to find the end of the pack "manually" i.e. till the first video packet
				bool endofpackfound = false;
				PACKlength = 12;
				for (; PACKlength < Mpeg->System->first_video_packet_length; PACKlength++)
				{
					if (	Mpeg->System->first_video_packet[PACKlength] == 0x0 &&
							Mpeg->System->first_video_packet[PACKlength + 1] == 0x0 &&
							Mpeg->System->first_video_packet[PACKlength + 2] == 0x1 &&
							((Mpeg->System->first_video_packet[PACKlength + 3] & 0xF0) == 0xE0||
							 (Mpeg->System->first_video_packet[PACKlength + 3] & 0xF0) == 0xD0)
						)
					{
						endofpackfound=true;
						break;
						PACKlength--;	// TODO: Laurent what's this? break exits..
					} //if
				} //for

				if ((!endofpackfound) ||
						(Mpeg->System->first_video_packet_length-PACKlength-4-2 <=0))
				{
					fprintf(stderr,"Now I'm really lost, ciao\n");
					exit(1);
				}
			}
			// end May 28
		}
	}
	fwrite(Mpeg->System->first_video_packet,
			1, PACKlength + mpeg2stuff_bytes, MpegOut);
	// now allocate required mem
	partial_packet_length = Mpeg->System->first_video_packet_length-PACKlength - mpeg2stuff_bytes - (mpeg2stuff_bytes  == 0?0:2);
	//after the size field
	partial_packet_length += Mpeg->Video->video_header_size;
	partial_packet = new byte[partial_packet_length];
	//	printf("allocating %ld bytes\n",partial_packet_length);

	memcpy(partial_packet,
			(Mpeg->System->first_video_packet) + PACKlength + mpeg2stuff_bytes + (mpeg2stuff_bytes  == 0?0:2),
			Mpeg->System->first_video_packet_length - PACKlength - mpeg2stuff_bytes - (mpeg2stuff_bytes  == 0?0:2));

	memcpy(&partial_packet[(Mpeg->System->first_video_packet_length) - PACKlength - mpeg2stuff_bytes - (mpeg2stuff_bytes  == 0?0:2)],
			Mpeg->Video->video_header,
			Mpeg->Video->video_header_size);

	HasAudio = HasVideo = true;
	FileType = mpeg_SYSTEM;
	currentTS = Mpeg->System->initial_TS;
#ifdef _DEBUG_
	fprintf(stderr,"Mpeg initial_TS: %lf\n",currentTS);
#endif
	fflush(MpegOut);
}


void mpegVideoOut::WriteHeader(mpeg* Mpeg) {
	BTRACK;
	//Have to write video sequence
	if (!MpegOut) return;
	fwrite(Mpeg->Video->video_header,
		1, Mpeg->Video->video_header_size, MpegOut);		
}


int mpegVideoOut::WriteChunk(
		mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to, bool to_included)
{
	BTRACK;
	if (!MpegOut) return 0;

	off_t real_from, real_to;

	if ((from > to) || (from < 0) || (to < 0)) {	
		//pffff
		return 0;
	}	

	if (from_included) {
		real_from = Mpeg->bdFindNextMarker(from, 0xB8);
		if (real_from == -1) {
			//couldn't find a GOP before from!
			real_from = Mpeg->FindNextMarker(from, 0xB8);
			if (real_from == -1) {
				//gosh couldn't find GOP at all!
				return 0;
			}	
		}
	} else {
		real_from = Mpeg->FindNextMarker(from, 0xB8);
		if (real_from == -1) {
			real_from = Mpeg->bdFindNextMarker(from, 0xB8);
			if(real_from == -1) {
				//couldn't find any GOP!
				return 0;
			}
		}
	}

	//okay we have a real from
	if (to_included) {
		real_to = Mpeg->FindNextMarker(to, 0xB8);
		if (real_to == -1) real_to = Mpeg->FileSize;
	} else {
		real_to = Mpeg->bdFindNextMarker(to, 0xB8);
		if (real_to == -1) {
			//couldn't find any GOP!
			return 0;
		}
	}

	if (real_from >= real_to) return 0;

	//now let's Copy from GOP boundary to GOP boundary
	if (print_progress) fprintf(stderr, "        ");
	Copy(Mpeg->MpegFile, real_from,real_to);
	return 1;
}

int mpegAudioOut::WriteChunk(
		mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to,bool to_included)
{
	BTRACK;

	if (!MpegOut) return 0;
	off_t real_from,real_to;

	// 23 March 2001, real_to an real_from are now seeked
	// because there are plenty of variable bitrates mp3

	/*	real_from=from -(from% Mpeg->Audio->frame_length);
		if ((real_from!=from)&&(!from_included))
		real_from+=Mpeg->Audio->frame_length;

		real_to= to -(from%Mpeg->Audio->frame_length);
		if ((real_to!=to)&&(to_included)) 
		real_to += Mpeg->Audio->frame_length;
		if (real_to > Mpeg->Size()) real_to=Mpeg->Size();		
	 */	
	if (from_included)
		real_from = Mpeg->bdFindMatchingAudio(from);
	else 
		real_from = Mpeg->FindMatchingAudio(from);

	if (to_included)
		real_to=Mpeg->FindMatchingAudio(to);
	else 
		real_to=Mpeg->bdFindMatchingAudio(to);


	if (real_to==-1 || real_from==-1 || real_from >= real_to)
		return false;

	if(print_progress) fprintf(stderr,"        ");

	Copy(Mpeg->MpegFile, real_from, real_to);
	return 1;
}


int mpegSystemOut::WriteChunk(
		mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to, bool to_included)
{
	int count;
	BTRACK;
	if (!MpegOut) return 0;
#ifdef _DEBUG_
	fprintf(stderr,"new Chunk: from:0x%qx, to:0x%qx\n",from,to);
#endif
	off_t real_from, real_to;
	int sequence_header; 

	//given the from and to offsets, find GOP boundaries
	if ((from > to) || (from < 0) || (to < 0)) {
		//pffff
		return 0;
	}	
	if (from_included) {
		real_from = Mpeg->bdFindNextMarker(from, 0xB8);
		if (real_from == -1) {
			//couldn't find a GOP before from!
			real_from = Mpeg->FindNextMarker(from, 0xB8);
			if (real_from == -1) {
				//gosh couldn't find GOP at all!
				return 0;
			}
		}
	} else {
		real_from= Mpeg->FindNextMarker(from, 0xB8);

		if (real_from == -1) {
			//couldn't find any GOP!
			return 0;
		}
	}

	//okay we have a real from
	if (to_included) {
		real_to = Mpeg->FindNextMarker(to, 0xB8);
		if (real_to == -1) real_to = Mpeg->FileSize;
	} else {
		real_to = Mpeg->bdFindNextMarker(to, 0xB8);
		if (real_to == -1) {
			//couldn't find any GOP!
			return 0;
		}
	}

	if (real_from >= real_to) return 0;

	//	printf("[%ld - %ld ] becomes [%ld - %ld]\n",from,to, real_from,real_to);
	//	while(getchar()!='\n');

	//okay the file is there but artifacts too..
	//we have to correct the packet length
	//we already know the data size we have,
	//let's compute what we just added : from GOP to end of packet

	off_t EOP = real_from - 1;
	marker mark;
	while (true) {
		EOP = Mpeg->FindNextMarker(EOP + 1, &mark);
		if (((mark & 0xF0) != 0x0) && (mark != 0xB8)) {
			// this is neither a slice, nor a pic nor a gop : 
			// we are then at the end of the packet
			break;
		}
		if (EOP == -1) break;
	}
	off_t GOP2EOP = EOP - real_from;

	//if FindNextMarker returned -1 there was no pack after->take filesize
	if (GOP2EOP < 0) GOP2EOP = Mpeg->FileSize-real_from;
	//okay the packet size must now be ::partial_packet_length+GOP2EOP
	//let's write that 
	off_t real_packet_length = partial_packet_length+GOP2EOP;
#ifdef _DEBUG_
	fprintf(stderr,"real_packet_length: [" _OFF_x "]\n", real_packet_length );
#endif
	byte low = real_packet_length & 0xFF;
	byte high = (real_packet_length >> 8) & 0xFF;
	//fseeko(MpegOut, size_field_offset, SEEK_SET);
	if (Mpeg->Version() == 2) {
		// dont touch valuable data,  maybe mpeg1 files have a size here but mpeg2 wont play 
		// if filesize is written here
		// this is not good, who nows what the effect will be on other mpeg2s ?
		// but currently I dont know it better
		;
	}
	else
	{	
	fwrite(&high, 1, 1, MpegOut);
	fwrite(&low, 1, 1, MpegOut);
	//fseeko(MpegOut, 0, SEEK_END);
	}
	fflush(MpegOut);	
	
	//write what we kept in mem and free memory

	// fprintf(stderr,"partial_packet_length %qd\n",partial_packet_length);

        // for (count = 0; count < partial_packet_length; ++count) {
        //        fprintf(stderr, "%02x.",*(partial_packet + count));
        // }
        // fprintf(stderr,"\n");
	sequence_header = -1;
	for (count = 0; count < partial_packet_length - 4; ++count) {
                if (
			(*(partial_packet + 0 + count) == 0x00) &&
                        (*(partial_packet + 1 + count) == 0x00) &&
                        (*(partial_packet + 2 + count) == 0x01) &&
			(*(partial_packet + 3 + count) == 0xb3) )
			{	
				sequence_header = count + 4;
				// fprintf(stderr, "found sequence header at: %d\n",sequence_header);
				count = partial_packet_length;
				// this is the important sequence header in the file!
			}
	}
	if ((sequence_header != -1) && ((partial_packet_length - sequence_header) > 4) && (aspect_correction)) {
	// found it, room to change is there, user wants it
		if (print_progress)
		fprintf(stderr,"\nCurrent Value of aspect ratio is: %2x ",*(partial_packet + sequence_header + 3));
		// fprintf(stderr, "position: %d is: %2x\n", sequence_header + 3,*(partial_packet + sequence_header + 3));
		 *(partial_packet + sequence_header + 3) = ((*(partial_packet + sequence_header + 3) & 0xf) | forced_sequence_header  );
		// fprintf(stderr, "position: %d is new: %2x\n", sequence_header + 3,*(partial_packet + sequence_header + 3));
		if (print_progress)
		fprintf(stderr,"New Value of aspect ratio is: %2x\n",*(partial_packet + sequence_header + 3));

	}



 
	fwrite(partial_packet, 1, partial_packet_length, MpegOut);
	fflush(MpegOut);


	//	printf("deleting partial_packet in WriteChunk\n");
	delete[] partial_packet;

	//now recreate buffer with everything from start of packet
	//to GOP end (real_to) and copy it in partial_packet
	off_t last_packet_offset= Mpeg->bdFindNextMarker(real_to, 0xE0);
	// fprintf(stderr,"last_packet_offset: [" _OFF_x "]\n",last_packet_offset); 
	partial_packet_length = real_to-last_packet_offset - 6;
	partial_packet = new byte[partial_packet_length];
	//	printf("allocating %ld bytes\n",partial_packet_length);
	FSEEK(Mpeg->MpegFile, last_packet_offset + 6, SEEK_SET);

	fread(partial_packet, 1, partial_packet_length, Mpeg->MpegFile);

	//now let's Copy from start of packet boundary to beg of last packet
	if (print_progress) fprintf(stderr,"        ");
#ifdef _DEBUG_
	fprintf(stderr,"Starting copy %qd %qd \n",real_from,last_packet_offset);
#endif
	Copy(Mpeg->MpegFile, real_from,last_packet_offset + 4);

	// Copy updated the current time stamp.
	// we must now correct the partial packet timestamp.
	byte* OldBuffer = buffer;
	buffer = partial_packet;
	if (CorrectTS(partial_packet_length) != 0) {
		fprintf(stderr,"unhandled result code of CorrectTS, results in playback or sync problem!\n");
	}
	buffer = OldBuffer;

	return 1;
}

void mpegSystemOut::Copy(FILE* file, off_t from, off_t to) {
	BTRACK;
#ifdef ENABLE_OPTIMIZATION
	double Copy_time_start=Clock_Now();
#endif

	if (!MpegOut) return ;
	//	long DBGsize;
	off_t size = to - from;
	off_t read_size = 0;
	off_t prev_read_size = 0;
	long rewind_pos = 0; // if buffer at end and TS could not be corrected, reread from correct position
	float percent;
	first_TS_correction = true;
	// fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut));
	size_t size2read = (size > COPYBUFFERSIZE)?COPYBUFFERSIZE:size;
	buffer = new byte[size2read];
	while(read_size < size) {
		size2read = ((size - read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size;
		if (rewind_pos != 0) { // last buffer was at end, and  a TS could not be corrected 
					
			FSEEK(file, from + read_size - (prev_read_size - rewind_pos), SEEK_SET);
#ifdef _DEBUG_
			// fprintf(stderr,"rewinded by %qd bytes to prevent short buffer problem\n",(prev_read_size - rewind_pos));
#endif
			prev_read_size = 0;
			rewind_pos = 0;
		}
		else
			FSEEK(file, from + read_size, SEEK_SET);

		read_size += fread(buffer, 1, size2read, file);
		// fprintf(stderr,"read bytes: %qd\n",read_size);
		if (first_TS_correction) {
#ifdef _DEBUG_ 
		fprintf(stderr,"The bytes from start...: %02x %02x %02x %02x %02x %02x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5] );
#endif
			// hehe we have to set the broken link flag on the first GOP!
			// why? because those players will try to play the leading B frames
			// wich are predicted from former frames (and they're not any, cause
			// we just happen to cut them, remember?)
			// broken_link flag is just for that!
			// we must be on a GOP start here
			// broken link is 27 bit after GOP start sequence
			// it is @ 4 + 3 bytes + 3 bits
			buffer[7] |= 0x20;
			// pfiouuu that one line was hard to find!

			// now that broken link is set we must unset the closed gop bit
			buffer[7] &= 0xBF;

			//TODO: some players ignore this broken link flag...
			// (I hate them)
			// another dirty way to do that is to find all B (and P?)
			// frames preceding the first I frame and change their type
			// (offset of frame type : 00 00 01 00 +10bits /3bits
			// to something like 000b wich is not a valid frame type,
			// they may be discarded by the player

			// I guess the best way to make it robust is to parse the whole
			// GOP, delete the preceding B frames and change the temporal ref
			// of every other frames...
			// This is a though job because a single frame can span over multiple
			// video packets...

			// final versions of this soft might cut mpg files on frame
			// boundaries... we'll take care of that at this very moment.
		}
		rewind_pos = CorrectTS(size2read); // correct TS of buffer
		if (rewind_pos) {
#ifdef _DEBUG_
			// fprintf(stderr,"we now take care of the buffer problem! %ld size2read: %ld\n",rewind_pos,size2read);
#endif
			fwrite(buffer,1,rewind_pos,MpegOut); // only write the part which is ok!
			prev_read_size = size2read;
		}
		else
			fwrite(buffer, 1, size2read, MpegOut);
		//printf("Written %ld bytes on %ld wanted\n",DBGsize,size2read);
		if (print_progress) {
			START_CLOCK

			percent = (read_size*1.0) / (size/100.0);
			percent = (percent>100.0)?100.0:percent;
			fprintf(stderr,"\b\b\b\b\b\b\b\b%5.2f%%  ", percent);
			fflush(stdout);

			STOP_CLOCK(PRINTF);

		}
	}
	delete buffer;
	
#ifdef ENABLE_OPTIMIZATION
	AddTime(Copy_time_start,COPY);
#endif
}

void mpegAudioOut::Finish() {
	// write id3 tag if present
}

void mpegSystemOut::Finish(){
	BTRACK;

	if (!MpegOut) return;
	if (partial_packet) {
		byte low = partial_packet_length & 0xFF;
		byte high = (partial_packet_length >> 8) & 0xFF;
		fwrite(&high, 1, 1, MpegOut);
		fwrite(&low, 1, 1, MpegOut);
		fwrite(partial_packet, 1, partial_packet_length, MpegOut);
		//		printf("deleting partial packet in finish\n");
		delete[] partial_packet;
	}
	fclose(MpegOut);
}


void mpegVideoOut::Copy(FILE* file, off_t from, off_t to){
	BTRACK;
#ifdef ENABLE_OPTIMIZATION
	double Copy_time_start=Clock_Now();
#endif
	if (!MpegOut) return ;
	off_t size = to - from;
	off_t read_size = 0;
	first_TS_correction = true;
	float percent;
	//	fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut));
	size_t size2read = (size > COPYBUFFERSIZE)?COPYBUFFERSIZE:size;
	buffer = new byte[size2read];

	while (read_size < size) {
		size2read = ((size - read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size;

		FSEEK(file, from + read_size, SEEK_SET);

		read_size += fread(buffer, 1, size2read, file);
		if (first_TS_correction) {
			buffer[7] |= 0x20;
			first_TS_correction = false;
		}
		fwrite(buffer, 1, size2read, MpegOut);
		if (print_progress) {
			//lperc=(read_size*100)/(size/100);
			START_CLOCK;
			percent = (read_size*1.0) / (size/100.0);
			fprintf(stderr, "\b\b\b\b\b\b\b\b%5.2f%%  ", percent);
			fflush(stderr);
			STOP_CLOCK(PRINTF);
		}
	}
	delete buffer;
#ifdef ENABLE_OPTIMIZATION
		AddTime(Copy_time_start,COPY);
#endif
}

void mpegAudioOut::Copy(FILE* file, off_t from, off_t to) {
	BTRACK;
#ifdef ENABLE_OPTIMIZATION
	double Copy_time_start=Clock_Now();
#endif	

	if (!MpegOut) return;
	off_t size = to - from;
	off_t read_size = 0;
	float percent;
	//	fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut));
	size_t size2read = (size > COPYBUFFERSIZE)?COPYBUFFERSIZE:size;
	buffer = new byte[size2read];

	while (read_size < size) {
		size2read = ((size - read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size;


		FSEEK(file, from + read_size, SEEK_SET);

		read_size += fread(buffer, 1, size2read, file);
		fwrite(buffer, 1, size2read, MpegOut);
		if (print_progress) {
			START_CLOCK;
			//lperc=(read_size*100)/(size/100);
			percent = (read_size*1.0) / (size/100);
			percent = (percent>100.0)?100.0:percent;
			fprintf(stderr, "\b\b\b\b\b\b\b\b%5.2f%%  ", percent);
			fflush(stderr);
			STOP_CLOCK(PRINTF);
		}
	}
	delete buffer;
#ifdef ENABLE_OPTIMIZATION
	AddTime(Copy_time_start,COPY);
#endif
}


void foo(){
	printf("ici");
}

#ifndef _WIN32
inline
#endif

long mpegOutWithVideo::CorrectTS(long bufferlength) {
	BTRACK;
	// for each pack we encounter in that buffer, 
	// get the timestamp
	long nix; // stores the location of the a GOP in the buffer
	double ts;
	double ts2;
	double ts3;
	//added April 24 2001
	if	(first_TS_correction) 
		ts_correction = 0.0;
	//end added
	
	int nbofTS;
	long i;
	long saved_i;
	nix = -1;
	//9 is for 4 bytes PACKstartcode + 5 bytes PACKTS
	for ( i=0; i < bufferlength - 9; i++){	
		//	printf("i vaut %d\n",i);
		if ((buffer[i]== 0x00) &&
				(buffer[i + 1] == 0x00) &&
				(buffer[i + 2] == 0x01))
		{
			switch(buffer[i + 3]) {
				case 0xB3:	// found a sequence header
					if (aspect_correction) 
					{
						buffer[i + 7] = ((buffer[i + 7] & 0xf ) | forced_sequence_header);

					}
					break;
				case 0xB8: // found a GOP
					if (mpeg_version != 2) { // it worked before without correction of GOPS in mpeg1 so why change ?
						break;
					}
					else {

#ifdef _DEBUG_ 
						fprintf(stderr,"mpeg2 GOP found!\n");  
						fprintf(stderr,"TS GOP mpeg2: %f     before : %f (delta %f) [pack]\n",ts+ts_correction,ts,ts_correction);
#endif
						memReadTS(i + 4, &ts, true);
						if (first_TS_correction) {
						// did another GOP appear before a pack ? - problem
							if (nix != -1)
								fprintf(stderr,"lost one gop correction, this should not happen!\n");								
							nix = i; // do that later impossible to know now the correct value
							// I figured out the the TS of GOPS most time are higher then in the PACKs
							// TS must be corrected, but if the value would be taken from the GOP TS
							// that would be wrong, so do it later
#ifdef _DEBUG_
							fprintf(stderr,"first TS correction delayed\n");
#endif

						}
					} 
					break;
				case 0xBA:
					//we have a PACK
					//DBG
					//	printf("PACK ");
					if (mpeg_version == 2) {
							memReadTS(i + 4, &ts, true,true);
					}
					else memReadTS(i + 4, &ts);
					if (first_TS_correction) {
						first_TS_correction = false;
						ts_correction=currentTS - ts + base_TS_correction;
#ifdef _DEBUG_
						fprintf(stderr,"FirstTS Corr: current: %f, ts: %f, base_TS_corr %f\n",currentTS,ts,base_TS_correction);
#endif

					if ( nix != -1)
					{
						memReadTS(nix + 4, &ts3,true);
#ifdef _DEBUG_
						fprintf(stderr,"delayed correction executed now: at: %ld ts: %lf tscorrection: %lf TS: %lf \n",nix,ts3,ts_correction, ts3 + ts_correction);
#endif
						memWriteTS(nix + 4, ts3 + ts_correction,true);
						nix = -1; // clear

					}

					}		
#ifdef _DEBUG_
					fprintf(stderr,"TS: %f     before : %f (delta %f) [pack]\n",ts+ts_correction,ts,ts_correction);
#endif					
					currentTS=ts + ts_correction;
#ifdef _DEBUG
					fprintf(stderr, "pack current TS is now %f\n",currentTS);
#endif
					if (currentTS < 0.0 ){
						currentTS = 0.0;
						fprintf(stderr,"PACK: TS <0, corrected to 0, movie will have problems playing!\n");
					}
			
					if (mpeg_version == 2) {
#ifdef _DEBUG_
						fprintf(stderr,"memwriteTS mpeg2\n");
#endif
						memWriteTS(i + 4, currentTS, true,true);
					}
					else memWriteTS(i + 4, currentTS);
					

#ifdef _DEBUG_			
					// debug
					fprintf(stderr,"PACK ");
					memReadTS(i+4,&ts,true);

#endif
					break;
// philipp xxx
				case 0xC0 : // Found a mpeg audio PES header
				case 0xE0 : // Found a mpeg video PED header
				// for processing DVDs, this must be expanded in a future version !
#ifdef _DEBUG_
					fprintf(stderr,"PES HEADER, ");
					if (buffer[i + 3] == 0xE0)
						fprintf(stderr,"video stream\n" );
					else
						fprintf(stderr,"audio stream\n" );
#endif						
					//skip packet start code & length field
#ifdef _DEBUG_
					fprintf(stderr,"\nOffset: %ld The bytes...: %2x %2x %2x %2x %2x %2x\n",i,buffer[i + 0],buffer[i + 1],buffer[i + 2],buffer[i + 3],buffer[i + 4],buffer[i + 5] );
#endif
					saved_i = i + 6;
					i += 6;
#ifdef _DEBUG_
					fprintf(stderr,"Offset: %ld The bytes...: %2x %2x %2x %2x %2x %2x\n",i,buffer[i + 0],buffer[i + 1],buffer[i + 2],buffer[i + 3],buffer[i + 4],buffer[i + 5] );
#endif				
					nbofTS = memReadPktTS(&i, &ts, &ts2, bufferlength);
					if (first_TS_correction) {
						//ooops ts_correction not initialized... cheat.
						if (nbofTS >= 1) ts_correction=currentTS - ts + base_TS_correction;
					}
#ifdef _DEBUG_
					if (nbofTS != 0)
						fprintf(stderr,"!!!!!!!!1nbofTS: %d\n",nbofTS);
#endif
					if (nbofTS == 1) {
						//only one pts to change
						ts += ts_correction;
						if (ts < 0) {
							ts = 0;
							fprintf(stderr,"PES01: TS <0, corrected to 0, movie will have problems playing!\n");
							// negative TS are no good, better set to 0 but what about playback ..?
						}
						// ts = (ts < 0)?0:ts; //I know this is dirty
						// for what ever reason my compile did ignore the above statement replaced by above it
						// printf("pts current TS is now %f\n",ts);
						if (mpeg_version == 2)
							memWriteTS(i - 5, ts);
						else   
							memWriteTS(i - 5, ts);
						// fprintf(stderr,"1 TS written at %d\n", (i - 5) - saved_i);
						// if (i - 5 - saved_i == 0) fprintf(stderr, "ZERO FOUND\n");
						// fprintf(stderr,"-3");
						break;
					}
					if (nbofTS == 2) {

						//two ts to change
						ts  += ts_correction;
						ts2 += ts_correction;
						if ( ts < 0 ) {
							ts = 0;
							fprintf(stderr,"PES02: TS <0, corrected to 0, movie will have problems playing!\n");
						}
						if ( ts2 < 0 ) {
							ts2 = 0;
							fprintf(stderr,"PES03: TS <0, corrected to 0, movie will have problems playing!\n");
						}


						//				fprintf(stderr,"pts current TS is now %f\n",ts);
						//				fprintf(stderr,"dts current TS is now %f\n",ts2);
						/*				memWriteTS(i-5,ts);
										memWriteTS(i,ts2);
						 */
                                                if (mpeg_version == 2) {
                                                        memWriteTS(i - 10, ts);
                                                        memWriteTS(i - 5, ts2);
						}
						else
						{
							memWriteTS(i - 10, ts);
							memWriteTS(i - 5, ts2);
						}
						//fprintf(stderr,"2 TS written at %d and %d\n",
						//		(i - 10) - saved_i, (i - 5) - saved_i);
						// fprintf(stderr,"--3");
						break;
					}
					if (nbofTS == -1) {

						// fprintf(stderr,"buffer problem here not handled, taking care later buffer: %ld\n",i);
						return i;
						break;

					}
					if (nbofTS) { // all other return codes are impossible!
						fprintf(stderr,"we should not get to this point please report this error! nbofTS:  %d\n",nbofTS);
						return -1;
						break;
					}						
					break;

			} //switch
		} //if
	} //for
	return 0;
}


void mpegOutWithVideo::memReadTS(long offset, double* ts, bool mpeg2pack, bool pack){
	BTRACK;
	byte highbit;
	unsigned long low4Bytes;
	double TS;
	byte *nix;
#ifdef _DEBUG_
	printf("\nReading TS at offset [" _OFF_x "]\n", offset + FTELL(MpegOut));
	print_ts(&(buffer[offset ]));
#endif //debug
	if (!mpeg2pack) { // mpeg1 is different from 2!
		highbit= (buffer[offset]>>3)&0x01;	

		low4Bytes = ((buffer[offset] >> 1) & 0x03) << 30;
		low4Bytes |= buffer[offset + 1] << 22; // hours
		low4Bytes |= (buffer[offset + 2] >> 1) <<15; // minutes
		low4Bytes |= buffer[offset + 3] << 7;
		low4Bytes |= buffer[offset + 4] >> 1;

#define FLOAT_0x10000 (double)((unsigned long)1 << 16)
#define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000

		TS =  (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000);
		TS += (double)(low4Bytes);
		TS /= (double)(STD_SYSTEM_CLOCK_FREQ);

		*ts = TS;
#ifdef _DEBUG_
			printf("TS1 : base : 0x%d,%032lx ",highbit,low4Bytes);
			printf ("TS1 : %lf\n",TS);
			fprintf(stderr,"\nTS mpeg 1 : %02x, %02x %02x %02x %02x, [%lx]\n",
				highbit,
				byte((low4Bytes>>24)&0xFF),
				byte((low4Bytes>>16)&0xFF),
				byte((low4Bytes>>8)&0xFF),
				byte((low4Bytes)&0xFF),
				(unsigned long) (offset)
				);
		fprintf(stderr,"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x   highBit=%d  low4Bytes=%ld\n",
			buffer[offset-4],
			buffer[offset-3],
			buffer[offset-2],
			buffer[offset-1],
			buffer[offset-0],
			buffer[offset+1],
			buffer[offset+2],
			buffer[offset+3],
			buffer[offset+4],
			buffer[offset+5],
			highbit,
			low4Bytes
			 );
#endif

	} else {
		//mpeg2  header PACK or GOP

		unsigned long sys_clock_ref;	
		highbit= (buffer[offset] & 0x20) >> 5;	
		if (pack) {
#ifdef _DEBUG
			fprintf(stderr,"NO gop!\n");
#endif
			low4Bytes = ((buffer[offset] & 0x18) >> 3) << 30;
			low4Bytes |= (buffer[offset] & 0x03) << 28;
			low4Bytes |= buffer[offset + 1] << 20;

			low4Bytes |= ((buffer[offset + 2] & 0xF8)) << 12;

			low4Bytes |= (buffer[offset + 2] & 0x03) << 13;

			low4Bytes |= buffer[offset + 3] << 5;
			low4Bytes |= (buffer[offset + 4]) >> 3; 
		}
		else // a GOP
		{  // move the 32 bit in a long
			low4Bytes = ( (buffer[offset] & 0x7c) >> 2) << 24; 
			low4Bytes |= (buffer[offset] & 0x3) << 20; 
			low4Bytes |= (buffer[offset +1 ] & 0xF0) << 12; 
			low4Bytes |= (buffer[offset +1 ] & 0x7) << 11; 
			low4Bytes |= (buffer[offset +2 ] & 0xE0) << 3; 
			low4Bytes |= (buffer[offset +2 ] & 0x1F) << 1; 
			low4Bytes |= (buffer[offset +3 ] & 0x80) >> 7; 
		}
		sys_clock_ref=(buffer[offset + 4] & 0x3) << 7;
		sys_clock_ref|=(buffer[offset + 5] >> 1);
		 
		if (pack) { 
			TS =  (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000);
			TS += (double)(low4Bytes); //  + (double) ((double) sys_clock_ref / 512);
		}
		else { // I love "nix"
			nix = (byte *) &low4Bytes;
			TS = 60 * 60 * *nix;
			TS += 60 * *(nix +1);
			TS += *(nix +2);
			TS += ((double) *(nix +3)) / 60;		
		}
		if (pack) {
			if (sys_clock_ref == 0)	
			{
				TS /= (double)(STD_SYSTEM_CLOCK_FREQ);
#ifdef _DEBUG_
				fprintf(stderr,"**ts divided by std_sysclock_fewq, now: %lf\n",TS);
#endif
			}
			else {
				// this is what I understood... CHECK
				// if not zero, then we have a 27 MHz accuracy with a max of 27 MHz
				// so clockfreq might well be 27MHz / sys_clock_ref
				// this is nonsense ... 
				// sysclockref is only the remainder of the division of 27MHZ/300
				// I guess we can safely ignore it
				// fprintf(stderr,"syslockref: %ld\n",sys_clock_ref);
				// TS /= (double)(27000000 / sys_clock_ref);
				TS /= (double)(STD_SYSTEM_CLOCK_FREQ);
				// if sysclock ref != 0, this is the remainder of the divison of 27mhz by300
				
#ifdef _DEBUG_
				fprintf(stderr,"XXts divided by sys_clock_ref, now: %lf\n",TS);
#endif
			}
		} 
		//debug

#ifdef _DEBUG_
			printf("TS2 : base : 0x%d,%032lx ref : %016lx\n",highbit,low4Bytes,sys_clock_ref);
			printf ("TS2 : %lf\n",TS);
			fprintf(stderr,"\nTS mpeg 2 : %02x, %02x %02x %02x %02x, %lx [%lx]\n",
				highbit,
				byte((low4Bytes>>24)&0xFF),
				byte((low4Bytes>>16)&0xFF),
				byte((low4Bytes>>8)&0xFF),
				byte((low4Bytes)&0xFF),
				sys_clock_ref,
				(unsigned long) (offset)
				);
		fprintf(stderr,"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x   highBit=%d  low4Bytes=%ld sysclockref=%ld\n",
			buffer[offset-4],
			buffer[offset-3],
			buffer[offset-2],
			buffer[offset-1],
			buffer[offset-0],
			buffer[offset+1],
			buffer[offset+2],
			buffer[offset+3],
			buffer[offset+4],
			buffer[offset+5],
			highbit,
			low4Bytes,
			sys_clock_ref
			 );
#endif

		*ts=TS;
	}
	//DBG
	// fprintf(stderr,"------ TS = %f ",TS);
}


void mpegOutWithVideo::memWriteTS (long offset, double ts, bool mpeg2pack, bool pack){
	BTRACK;

	// fprintf(stderr, " ts is %f\n",ts);

	byte uppercode = buffer[offset] & 0xF0;
	byte hiBit;
	long lowInt=0;
	double TS=ts;
	int hour;
	int minute;
	int sec;
	int pics;

        if (!mpeg2pack) {
		;
	}

		TS *= STD_SYSTEM_CLOCK_FREQ;
		if (TS > FLOAT_0x10000 * FLOAT_0x10000) {
			hiBit = 1;
			TS -= FLOAT_0x10000 * FLOAT_0x10000;
		} 	else {
				hiBit = 0;

	lowInt = (long) TS;
	}

	if (!mpeg2pack){
		uppercode = uppercode |
			(hiBit << 3) |
			((lowInt & 0xC0000000) >> 29) |
			0x01;

		lowInt = 0x00010001 |
			((lowInt & 0x3FFF8000) << 2) |
			((lowInt & 0x00007FFF) << 1);

		buffer[offset] = uppercode;
		buffer[offset+1] = (byte)(lowInt>>24);
		buffer[offset+2] = (byte)((lowInt>>16)&0xFF);
		buffer[offset+3] = (byte)((lowInt>>8)&0xFF);
		buffer[offset+4] = (byte)(lowInt&0xFF);	
	} else {
		if (pack) { // mpeg 2 PACK

		byte work;
		work = 0x40; //marker bit
		work |= hiBit << 5; //hiBit
		work |= lowInt >> 27 ; // two MSBs
		work |= 0x04; //marker bit
		work &= 0xFC; // clear the two LSB
		work |= (lowInt >> 28) & 0x03; // two more MSBs
		buffer[offset] = work; // marker
		buffer[offset+1] = (byte)((lowInt>>20)&0xFF);
		buffer[offset+2] = (byte)((((lowInt>>12)&0xF8))|((lowInt>>13)&0x03)|0x04);
		buffer[offset+3] = (byte)((lowInt>>5)&0xFF);
		buffer[offset+4] = (byte)(((lowInt<<3)&0xFF)|0x04);
		buffer[offset+5] = 0x01;//sys clock ref extension =0 
		}
		else
		{ // mpeg2 GOP
			hour = int(TS / 60 / 60);
			minute = int(TS / 60);
			sec = int(TS);
			pics = int((TS - ((long) TS)) * 60);
			buffer[offset] &= 0x7f; // clear hour & 2 bits from minute
			buffer[offset +1] &= 0x8; // clear minutes & seconds
			buffer[offset +2] &= 0;
			buffer[offset +3] &= 0x7f;
			
			buffer[offset] |= ( hour << 2);
			buffer[offset] |= ( minute >> 4);
			buffer[offset +1] |= (( minute & 0xf) << 4);
			buffer[offset +1] |= ( sec >> 3);
			buffer[offset +2] |= ( sec & 0x7) << 5;
			buffer[offset +2] |= ( pics >> 1);
			buffer[offset +3] |= ( pics & 0x1) << 7;
		}
	}
	// fprintf(stderr,"TS Write %lf ------\n",ts);
	//if (mpeg2pack) {
	//	fprintf(stderr,"\n xxxxxxxxxxx");
	//	memReadTS(offset,&ts9,true,true);
	//	fprintf(stderr," xxxxxxxxxxxx\n"); 
	//} 
}






int  mpegOutWithVideo::memReadPktTS(long* off, double* pts, double* dts, long bufferlength) {
	BTRACK;
	//just after the packet start code. and the length field
	byte mybyte;
	off_t offset=*off;
	//get rid of stuffing bytes
	mybyte=buffer[offset];
	if (mpeg_version != 2) // currenlty I dont believe in stuffing bytes here in case of mpeg2!
	{                      // also stuffing bytes should be FF and not 80 ?
			       // next time check if this is not better with mpeg1 also....!
	while((mybyte & 0x80) && (offset <= bufferlength - 5)) {
		//this has to be a stuffing byte
//		fprintf(stderr,"removed a stuffing byte ??\n");
		mybyte = buffer[++offset];
	}
	}
	//here mybyte is the first valid byte
	if (mpeg_version == 2){
		//skip the first byte
		++offset;
		mybyte = buffer[offset];
		mybyte >>= 6;
		switch (mybyte) {
			case 0: return 0;
			case 1: 
#ifdef _DEBUG_		
					  fprintf(stderr,"Invalid PTS DTS flag at [" _OFF_x "]\n", offset);
#endif
					  return 0;
			case 2: //only PTS;
                        if (offset > bufferlength - 7) {
                                // we have a valid header but no room to read the entire TS
                                // fprintf(stderr,"Copy Buffer-problem! -1\n");
                                return -1;
                        }
					  offset += 2;
					  memReadTS(offset,pts);
					  offset += 5;
					  *off = offset;
					  return 1;
			case 3: //both PTS and DTS
                        if (offset > bufferlength - 5) {
                                // we have a valid header but no room to read the entire TS
                                // fprintf(stderr,"Copy Buffer-problem! -1\n");
                                return -1;
                        }

					  offset += 2;
					  memReadTS(offset, pts);
					  offset += 5;
                        if (offset > bufferlength - 5) {
                                // we have a valid header but no room to read the entire TS
                                // fprintf(stderr,"Copy Buffer-problem! -1\n");
                                return -1;
                        }

					  memReadTS(offset, dts);
					  offset += 5;
					  *off = offset;
					  return 2;
		} //switch
		return 0;
	} else { // MPEG 1
		if ((mybyte >> 6) == 0x01) {
			//std buffer scale stuff... let's skip it
			offset += 2;
			mybyte = buffer[offset];
		}

		if ((mybyte >> 4) == 0x02) {
			// dts Time stamp

			if (offset > bufferlength - 5) {
				// we have a valid header but no room to read the entire TS
				// fprintf(stderr,"Copy Buffer-problem! -1\n");
				return -1;
			}

			//DBG
			//			printf("PTS "); 

			memReadTS(offset, pts);
			offset += 5;
			*off = offset;
			return 1;
		}
		else if ((mybyte >> 4) == 0x03) {
			//both pts and dts time stamps
			if (offset > bufferlength - 5) {
				// we have a valid header but no room to read the entire TS
				// fprintf(stderr,"Copy Buffer-problem! -2\n");

				return -1;
			}
			*off = offset;
			//DBG
			// printf("PTS "); 

			memReadTS(offset, pts);
			offset += 5;
			if (offset > bufferlength - 5) {
				// we have a valid header but no room to read the entire TS
				*off = offset;
				return 1; //1 for one valid TS found
			}
			//DBG
			//	printf("DTS "); 

			memReadTS(offset, dts);
			offset += 5;
			*off = offset;
			return 2;
		}
	}
	return 0;
}



mpegOut* mpegOutFactory::NewMpegFrom(mpeg* MpegIn, char* filename){
	BTRACK;
	mpegOut* object;
	switch(MpegIn->MpegType) {
		case mpeg_AUDIO:
			object = new mpegAudioOut(filename);
			break;
		case mpeg_VIDEO:
			object = new mpegVideoOut(filename);
			break;
		case mpeg_SYSTEM:
			object = new mpegSystemOut(filename);
			break;
		default:
			object = 0;
			break;
	}

	if (object) {
		if (object->OutFile())
			object->WriteHeader(MpegIn);
		else {
			delete object;
			object = 0;
		}
	}
	return object;
}




mpegOut* mpegOutFactory::NewMpegFrom(mpeg* MpegIn, FILE* filehandle){
	BTRACK;
	mpegOut* object;
	switch (MpegIn->MpegType) {
		case mpeg_AUDIO:
			object = new mpegAudioOut(filehandle);
			break;
		case mpeg_VIDEO:
			object = new mpegVideoOut(filehandle);
			break;
		case mpeg_SYSTEM:
			object = new mpegSystemOut(filehandle);
			break;
		default:
			object = 0;
			break;
	}
	if (object) object->WriteHeader(MpegIn);
	return object;
}







/*
	class demuxer{
	public:
	demuxer(mpeg* _Mpeg,char* videofile, char* audiofile);
	WriteChunk(off_t from, off_t to, bool from_included, bool to_included);
	protected:
	demuxer(){};	
	FILE* AudioOut;
	FILE* VideoOut;
	mpeg* Mpeg;
	};
 */





demuxer::demuxer(mpeg* _Mpeg, char* _basename, bool _confirm)
:n_audio(0),n_video(0),n_programs(0),Mpeg(_Mpeg),confirm(_confirm),buffer(0)
{
	BTRACK;
	basename = new char[strlen(_basename) + 1];
	strcpy(basename,_basename);
	// convention for Audiofile and Videofile :
	// if Audiofile[i]==0 : file is to be opened with basename
	// if Audiofile[i]==-1  stream is to be ignored.
	// this way piping a stream to stdout is eq to Audiofile[i]=stdout 
	
	for(int i = 0; i < 16; i++){
		AudioFile[i] = VideoFile[i] = 0;
	}

}







demuxer::~demuxer() {
	BTRACK;
	if (buffer) delete[]buffer;
	for (int i = 0; i < 16; i++) {
		if (AudioFile[i]) fclose(AudioFile[i]);
		if (VideoFile[i]) fclose(VideoFile[i]);
	}
}








int demuxer::Process(){
	BTRACK;
	if (Mpeg == 0) return 0;
//	fprintf(stderr,"start demux run \n");
	if (Mpeg->MpegType == mpeg_SYSTEM) {
//		fprintf(stderr,"ProcessProgramStream\n");
		return ProcessProgramStream();
	}
	if (Mpeg->MpegType == mpeg_TRANSPORT) {
//		fprintf(stderr,"ProcessTransportStream\n");
		return ProcessTransportStream();
	}
	//else :)

	fprintf(stderr,"mpeg file %s can not be demultiplexed"
			" (neither System nor Program stream)\n", Mpeg->FileName);
	return 0;
}




int demuxer::ProcessTransportStream() {
	BTRACK;
	if (!Mpeg->Transport) return 0;
	int pr;
	int stream_num;
	off_t offset = 0;
	off_t FileSize = Mpeg->Size();
	PID pid;
	EStream *currentStream;
	off_t start, end;
	n_programs = Mpeg->Transport->n_progs;
	int feedback = 0;
	while (true) {
		pid = Mpeg->NextTrPacket(&offset,&start,&end);
		if (start == -1) {
			if (print_progress){
			fprintf(stderr," Demultiplexing : [Programs %02d audio %02d  video %02d] [100.00%%]\n",
				n_programs,n_audio,n_video);
			}
			return n_audio + n_video;
		}

		if (start == end) continue;

		for (pr = 0; pr < Mpeg->Transport->n_progs; pr++)
		{
			currentStream = Mpeg->Transport->programs[pr].TStreams;
			stream_num = 0;
			while (currentStream !=0){
				stream_num++;
				if (currentStream->pid == pid) {
					// this is the good one
					if (currentStream->demuxFileOk) {
						if (currentStream->demuxFile == 0x0) {
							// file is not created 
							char* tempname = new char[300];
							sprintf(tempname, "%s-%d-%d.",
									basename, Mpeg->Transport->programs[pr].prog_num, stream_num);
							switch (currentStream->type) {
								case 1: strcat(tempname, "m1v"); n_video++; break;
								case 2: strcat(tempname, "m2v"); n_video++; break;
								case 3: strcat(tempname, "mp3"); n_audio++; break;
								case 4: strcat(tempname, "mp3"); n_audio++; break;
								default: strcat(tempname, "unk"); break;
							}
							currentStream->demuxFile = openfile(tempname);
							delete[] tempname;
						}
						// if currentStream->demuxFile still 0 : problem
						if (currentStream->demuxFile == 0x0) {
							fprintf(stderr, "skipping Program %d stream %d\n",
									Mpeg->Transport->programs[pr].prog_num, stream_num);
							currentStream->demuxFileOk = false;
						} else {
							//		Copy(currentStream->demuxFile,start,end);
							DemuxTrPkt(currentStream->demuxFile, start, end);
							if ((feedback++ == 100)) {
								feedback = 0;
								if (print_progress){
								fprintf(stderr,
									" Demultiplexing : [Programs %02d audio %02d  video %02d] [%6.2f%%]\r",
									n_programs, n_audio, n_video, offset*100.0/FileSize);
								}
							}
						} //else
					} //if
				} //if
				currentStream = currentStream->next;
			} //while
		} //for

#ifdef _DEBUG_
//		printf("PID %d has payload [%llx %llx]\n", pid, start, end);
#endif
	} //while (true)
	return 0;
}




int demuxer::DemuxTrPkt(FILE* out, off_t start, off_t end){
	BTRACK;
	// we have a transport packet, let's remove the program packet headers
	marker mark;
	off_t packetheader = Mpeg->FindNextMarker(start, &mark);
	off_t packetend = Mpeg->SkipPacketHeader(packetheader);
	mark &= 0xF0;

	if (mark==0xC0 || mark==0xE0 || mark==0xD0) {
		if (packetheader < 0 || packetheader > end) {
			// no packet header in the boundaries
			Copy(out, start, end);
			return 0;
		}
		if (packetend > end) {
			//serious problem
			return -1;
		}
		//here we have to issue two Copy
		Copy(out, start, packetheader);
		Copy(out, packetend, end);
		return 1;
	} else {
		Copy(out, start, end);
		return 1;
	}
}

int demuxer::ProcessProgramStream(){
	BTRACK;
	marker mark;
	off_t from, to;
	off_t FileSize = Mpeg->Size();
	off_t bytestoskip = 1;
	FILE* outfile;
	char* filename;
	int streamnumber;
	off_t offset;
	int progress = 0;
	
//	fprintf(stderr,"sizeof Mpeg->Size(): %ld \n", sizeof(Mpeg->Size()));
//	fprintf(stderr,"Mpeg->Size(): %qd \n", Mpeg->Size());
	for (offset = 0; offset < Mpeg->Size(); offset += bytestoskip) {
		// fprintf(stderr,"Mpeg->Size(): %qd, offset: %qd\n", Mpeg->Size(), offset);
		
		offset = Mpeg->FindNextMarker(offset,&mark);
//		fprintf(stderr,"ok, next marker found offset: %qd\n",offset);
		if (offset == -1) {
			// either we finished or unrecoverable error
			if (print_progress){
			fprintf(stderr," Demultiplexing : [audio %02d  video %02d] [100.00%%]\n",
					n_audio,n_video);
			}
			return n_audio+n_video;			
		}
		++progress;
		if ((print_progress)  && (progress % 100 == 0)){
		progress = 0;
		fprintf(stderr," DemultiplexingXXX : [audio %02d  video %02d] [%6.2f%%]\r",
				n_audio,n_video, offset*100.0/FileSize);
		}
		fflush(stderr);
		if (((mark&0xF0) == 0xC0) || ((mark&0xF0) == 0xD0)) {
			//new in mpeg 2 : audio streams are : 110x xxxx
			//audio packet
			streamnumber = mark&0x0F;
			if (AudioFile[streamnumber]) {
				//file is already opened or stream has to be ignored
			} else {
				//file has to be opened
				filename  = new char[300];
				n_audio++;
				sprintf(filename,"%s-%d.mp%d", basename, streamnumber, Mpeg->Audio->layer);
				AudioFile[streamnumber] = openfile(filename);					
				delete[] filename;
			}
			outfile = AudioFile[streamnumber];
		}
		else
			if ((mark&0xF0)==0xE0){
			//	fprintf(stderr,"here 01\n");

				//video packet
				streamnumber=mark&0x0F;
				if (VideoFile[streamnumber]){
					//file is already opened
				}
				else{
					//file has to be opened
					filename=new char[300];
					n_video++;			
					sprintf(filename,"%s-%d.m%dv",basename,streamnumber,Mpeg->mpeg_version);
					VideoFile[streamnumber]=openfile(filename);					
					delete[] filename;
				}
				outfile=VideoFile[streamnumber];

			} else {
				//neither Audio nor Video
				continue;
			}
			// fprintf(stderr,"here 02\n");

		//whatever it is it outfile mustn't be 0 nor 1
		// if outfile is still 0 there was a problem opening it
		// if outfile is -1 we were asked to skip it
		if (outfile==0 || outfile==(FILE*)(0x1)) {
//			fprintf(stderr,"skipped stream %x\n",mark);
			continue;
		}

		// now we have to find out where it begins and where it ends
		int length = ((Mpeg->Byte(offset+4)<<8) | Mpeg->Byte(offset+5));
		from = Mpeg->SkipPacketHeader(offset);
		to = offset + length + 6;
		if (to <= from) {
			fprintf(stderr, "Erroneous packet size, skipping\n");
			offset++;
			continue;
		}
		START_CLOCK
		Copy(outfile, from, to);
		STOP_CLOCK(COPY)
		offset = to - 1;

		if (to >= FileSize) offset = FileSize;		
	}
	START_CLOCK
	if ((print_progress ) && (progress % 1000 == 0)){
	progress = 0;
	fprintf(stderr," Demultiplexing: [audio %02d  video %02d] [100.00%%]\n",
			n_audio,n_video);
	}
	STOP_CLOCK(PRINTF)
	return 1;
}


off_t demuxer::Copy(FILE* into, off_t from, off_t to) {
	BTRACK;
	off_t size = to -from;
	off_t read_size = 0;
	//	float percent;
	//	fprintf(stderr,"Starting copy @%lx\n",ftell(MpegOut));
	size_t size2read=(size>COPYBUFFERSIZE)?COPYBUFFERSIZE:size;
	if(!buffer) buffer= new byte[COPYBUFFERSIZE];
	while (read_size < size) {
		size2read = ((size-read_size) > COPYBUFFERSIZE)?COPYBUFFERSIZE:size-read_size;
	        FSEEK(Mpeg->MpegFile, from + read_size, SEEK_SET);
		read_size += fread(buffer, 1, size2read, Mpeg->MpegFile);
		fwrite(buffer, 1, size2read, into);
		//	if(print_progress){
		//lperc=(read_size*100)/(size/100);
		//		percent= (read_size*1.0)/(size/100);
		//		fprintf(stderr,"\b\b\b\b\b\b\b\b%5.2f%%  ",percent);
		//		fflush(stderr);
		//	}
	}
	//	delete buffer;
	return to;
}


FILE* demuxer::openfile(char* filename) {
	BTRACK;
	FILE* temp;
	if (!confirm){
		temp = fopen(filename, "wb");
		if (temp==0){
			// problem
			fprintf(stderr,"\n");
			perror(filename);
		}
		return temp;
	} else {
		//must check if file exist
		temp = fopen(filename, "rb");
		if (temp != 0) {
			//file is readable, it exists
			fprintf(stderr,"file %s exists, overwrite ? [N/y/a]:     \b\b\b\b",filename);
			fflush(stderr);
			char answer = getchar();
			switch (answer) {
				case 'a':
				case 'A': confirm = false;
					  break;
				case 'y':
				case 'Y':
					 temp = fopen(filename, "wb");
					 if (temp == 0) {

						 // problem
						 fprintf(stderr, "\n");
						 perror(filename);
					 }
					 return temp;
					 break;			
				// default: return 0;
				default:
					fprintf(stderr,"Aborted\n"); 
					exit(1);
			} //switch
		} else {
			//file does not exist
			temp = fopen(filename, "wb");
			if (temp == 0) {
				// problem
				fprintf(stderr, "\n");
				perror(filename);
			}
			return temp;
		}
	}
	fprintf(stderr,"we should not get here!\n");
	return NULL;
}



void print_ts(byte *p) {
int hour, min, sec, pictures, drop, closed, broken;
byte  *head;	
	head = (byte *) (p);
        // calculate GOP information .. this is from gop Chop, thanks!
        /*
            4         5         6        7
                 |         |        |         |
        7 65432 107654 3 210765 432107 6 543210
        1 11111 111111 1 111111 111111 1 1
        d hour  min    m sec    pic    c b
        r              a               l roken
        o              r               osed
        p              k
        */
	fprintf(stderr,"data: %2x %2x %2x %2x\n",head[0],head[1],head[2],head[3]);
        drop=((head[0]&0x80)>0);
        hour=((head[0]&0x7C)>>2);
        min=((head[0]&0x3)<<4)|((head[1]&0xF0)>>4);
        sec=((head[1]&0x7)<<3)|((head[2]&0xE0)>>6);
        pictures=((head[2]&0x3F)<<1)|((head[3]&0x80)>>7);
        closed=((head[3]&0x40)>0);
        broken=((head[3]&0x20)>0);

	fprintf(stderr,"TS mpg2 INFO: %02d:%02d:%02d.%02d\n",hour,min,sec,pictures);



}




