/*************************************************************
 *   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);



}





