view mplayer.c @ 1285:202d9e2dc202

-vcodec option (maybe some other name would be better though) to select between driver types without editing codecs.conf. mplayer will default to normal codec search loop if it does not find codec for the specified driver type. config range checking for the parameter (an integer) should be cleaned, IMHO
author lgb
date Fri, 06 Jul 2001 21:17:22 +0000
parents 94f2853ec6f4
children 543a94b241a2
line wrap: on
line source

// AVI & MPEG Player    v0.18   (C) 2000-2001. by A'rpi/ESP-team

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <signal.h>

#include <sys/ioctl.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "version.h"
#include "config.h"

#if	defined(sun)
#define	DEFAULT_CDROM_DEVICE	"/vol/dev/aliases/cdrom0"
#elif defined(__FreeBSD__)
#define DEFAULT_CDROM_DEVICE    "/dev/cdrom"
#include <sys/cdrio.h>
#else
#define	DEFAULT_CDROM_DEVICE	"/dev/cdrom"
#endif


#ifndef MAX_OUTBURST
#error "============================================="
#error "Please re-run ./configure and then try again!"
#error "============================================="
#endif

#include "cfgparser.h"
#include "cfg-mplayer-def.h"

#include "subreader.h"

#include "libvo/video_out.h"
#include "libvo/sub.h"

#include "libao2/audio_out.h"

// CODECS:
#include "mp3lib/mp3.h"
#include "libac3/ac3.h"
#include "libmpeg2/mpeg2.h"
#include "libmpeg2/mpeg2_internal.h"

#include "loader.h"
#include "wine/avifmt.h"

#include "codec-cfg.h"

#include "dvdauth.h"
#include "spudec.h"

#ifdef USE_DIRECTSHOW
#include "DirectShow/DS_VideoDec.h"
#include "DirectShow/DS_AudioDec.h"
#endif

#ifdef USE_LIBAVCODEC
#include "libavcodec/avcodec.h"
    AVCodec *lavc_codec=NULL;
    AVCodecContext lavc_context;
    AVPicture lavc_picture;
#endif

#include "opendivx/decore.h"


#ifdef X11_FULLSCREEN
extern int vo_screenwidth;
#endif

extern char* win32_codec_name;  // must be set before calling DrvOpen() !!!

extern int errno;

#include "linux/getch2.h"
#include "linux/keycodes.h"
#include "linux/timer.h"
#include "linux/shmem.h"

#ifdef HAVE_LIRC
#include "lirc_mp.h"
#endif

#include "help_mp.h"

#ifdef STREAMING
#include "url.h"
#include "network.h"
static URL_t* url;
#endif


#define DEBUG if(0)
#ifdef HAVE_GUI
 int nogui=1;
#endif
int verbose=0;

#define ABS(x) (((x)>=0)?(x):(-(x)))

static subtitle* subtitles=NULL;
void find_sub(subtitle* subtitles,int key);

static int
usec_sleep(int usec_delay)
{
#if	1
    struct timespec ts;
    ts.tv_sec  =  usec_delay / 1000000;
    ts.tv_nsec = (usec_delay % 1000000) * 1000;
    return nanosleep(&ts, NULL);
#else
    return usleep(usec_delay);
#endif
}

//**************************************************************************//
//             Config file
//**************************************************************************//

static int cfg_inc_verbose(struct config *conf){
    ++verbose;
    return 0;
}

static int cfg_include(struct config *conf, char *filename){
	return parse_config_file(conf, filename);
}

char *get_path(char *filename){
	char *homedir;
	char *buff;
	static char *config_dir = "/.mplayer";
	int len;

	if ((homedir = getenv("HOME")) == NULL)
		return NULL;
	len = strlen(homedir) + strlen(config_dir) + 1;
	if (filename == NULL) {
		if ((buff = (char *) malloc(len)) == NULL)
			return NULL;
		sprintf(buff, "%s%s", homedir, config_dir);
	} else {
		len += strlen(filename) + 1;
		if ((buff = (char *) malloc(len)) == NULL)
			return NULL;
		sprintf(buff, "%s%s/%s", homedir, config_dir, filename);
	}
	return buff;
}

static int max_framesize=0;

//static int show_packets=0;

//**************************************************************************//
//**************************************************************************//
//             Input media streaming & demultiplexer:
//**************************************************************************//

#include "stream.h"
#include "demuxer.h"

#include "stheader.h"

int avi_bitrate=0;

demuxer_t *demuxer=NULL;

//#include "aviprint.c"

sh_audio_t* new_sh_audio(int id){
    if(demuxer->a_streams[id]){
        printf("Warning! Audio stream header %d redefined!\n",id);
    } else {
        printf("==> Found audio stream: %d\n",id);
        demuxer->a_streams[id]=malloc(sizeof(sh_audio_t));
        memset(demuxer->a_streams[id],0,sizeof(sh_audio_t));
    }
    return demuxer->a_streams[id];
}

sh_video_t* new_sh_video(int id){
    if(demuxer->v_streams[id]){
        printf("Warning! video stream header %d redefined!\n",id);
    } else {
        printf("==> Found video stream: %d\n",id);
        demuxer->v_streams[id]=malloc(sizeof(sh_video_t));
        memset(demuxer->v_streams[id],0,sizeof(sh_video_t));
    }
    return demuxer->v_streams[id];
}

demux_stream_t *d_audio=NULL;
demux_stream_t *d_video=NULL;
demux_stream_t *d_dvdsub=NULL;

sh_audio_t *sh_audio=NULL;
sh_video_t *sh_video=NULL;

char* encode_name=NULL;
char* encode_index_name=NULL;
int encode_bitrate=0;

extern int asf_packetsize; // for seeking

extern float avi_audio_pts;
extern float avi_video_pts;
extern float avi_video_ftime;
extern int skip_video_frames;

void read_avi_header(demuxer_t *demuxer,int index_mode);
demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id);

int asf_check_header(demuxer_t *demuxer);
int read_asf_header(demuxer_t *demuxer);

// MPEG video stream parser:
#include "parse_es.c"

extern int num_elementary_packets100; // for MPEG-ES fileformat detection
extern int num_elementary_packets101;

extern picture_t *picture;	// exported from libmpeg2/decode.c

static const int frameratecode2framerate[16] = {
  0,
  // Official mpeg1/2 framerates:
  24000*10000/1001, 24*10000,25*10000, 30000*10000/1001, 30*10000,50*10000,60000*10000/1001, 60*10000,
  // libmpeg3's "Unofficial economy rates":
  1*10000,5*10000,10*10000,12*10000,15*10000,0,0
};

//**************************************************************************//
//             Audio codecs:
//**************************************************************************//

// MP3 decoder buffer callback:
int mplayer_audio_read(char *buf,int size){
  int len;
  len=demux_read_data(sh_audio->ds,buf,size);
  return len;
}

//#include "dec_audio.c"

#ifndef NEW_DECORE
//**************************************************************************//
//             The OpenDivX stuff:
//**************************************************************************//

unsigned char *opendivx_src[3];
int opendivx_stride[3];

// callback, the opendivx decoder calls this for each frame:
void convert_linux(unsigned char *puc_y, int stride_y,
	unsigned char *puc_u, unsigned char *puc_v, int stride_uv,
	unsigned char *bmp, int width_y, int height_y){

//    printf("convert_yuv called  %dx%d  stride: %d,%d\n",width_y,height_y,stride_y,stride_uv);

    opendivx_src[0]=puc_y;
    opendivx_src[1]=puc_u;
    opendivx_src[2]=puc_v;
    
    opendivx_stride[0]=stride_y;
    opendivx_stride[1]=stride_uv;
    opendivx_stride[2]=stride_uv;
}
#endif

//**************************************************************************//
//**************************************************************************//

// Common FIFO functions, and keyboard/event FIFO code
#include "fifo.c"

//**************************************************************************//

static vo_functions_t *video_out=NULL;
ao_functions_t *audio_out=NULL;

double video_time_usage=0;
double vout_time_usage=0;
double audio_time_usage=0;
int total_time_usage_start=0;
int benchmark=0;

static int play_in_bg=0;

extern void avi_fixate();

#ifdef HAVE_GUI
 #include "../Gui/mplayer/psignal.h"
 #define GUI_MSG(x) if ( !nogui ) { mplSendMessage( x ); usec_sleep( 10000 ); }
#else
 #define GUI_MSG(x)
#endif

// options:
int osd_level=2;
int divx_quality=0;
char *seek_to_sec=NULL;
int seek_to_byte=0;
int has_audio=1;
//int has_video=1;
int audio_format=0; // override

int force_vcodec=-1;

#ifdef USE_DIRECTSHOW
int allow_dshow=1;
#else
int allow_dshow=0;
#endif

//#ifdef ALSA_TIMER
//int alsa=1;
//#else
//int alsa=0;
//#endif

// streaming:
int audio_id=-1;
int video_id=-1;
int dvdsub_id=-1;
int vcd_track=0;
char *stream_dump_name=NULL;
int stream_dump_type=0;
int index_mode=-1;  // -1=untouched  0=don't use index  1=use (geneate) index
int force_ni=0;

float default_max_pts_correction=-1;//0.01f;
#ifdef AVI_SYNC_BPS
int pts_from_bps=1;
#else
int pts_from_bps=0;
#endif

float force_fps=0;
int force_srate=0;
float audio_delay=0;
int frame_dropping=0; // option  0=no drop  1= drop vo  2= drop decode
int play_n_frames=-1;

// screen info:
char* video_driver=NULL; //"mga"; // default
char* audio_driver=NULL;
int fullscreen=0;
int vidmode=0;
int softzoom=0;
int flip=-1;
int screen_size_x=0;//SCREEN_SIZE_X;
int screen_size_y=0;//SCREEN_SIZE_Y;
int screen_size_xy=0;

// sub:
char *font_name=NULL;
float font_factor=0.75;
char *sub_name=NULL;
float sub_delay=0;
float sub_fps=0;
int   sub_auto = 1;
/*DSP!!char *dsp=NULL;*/

float rel_seek_secs=0;

extern char *vo_subdevice;
extern char *ao_subdevice;

void exit_player(char* how){
 total_time_usage_start=GetTimer()-total_time_usage_start;

#ifdef HAVE_GUI
 if ( !nogui )
  {
   if ( how != NULL )
    {
     if ( !strcmp( how,"Quit" ) ) mplSendMessage( mplEndOfFile );
     if ( !strcmp( how,"End of file" ) ) mplSendMessage( mplEndOfFile );
     if ( !strcmp( how,"audio_init" ) ) mplSendMessage( mplAudioError );
    }
    else mplSendMessage( mplUnknowError );
  }
#endif

  if(how) printf("\nExiting... (%s)\n",how);
  if(verbose) printf("max framesize was %d bytes\n",max_framesize);
  if(benchmark){
      double tot=video_time_usage+vout_time_usage+audio_time_usage;
      double total_time_usage=(float)total_time_usage_start*0.000001;
      printf("BENCHMARKs: V:%8.3fs VO:%8.3fs A:%8.3fs Sys:%8.3fs = %8.3fs\n",
          video_time_usage,vout_time_usage,audio_time_usage,
	  total_time_usage-tot,total_time_usage);
      if(total_time_usage>0.0)
      printf("BENCHMARK%%: V:%8.4f%% VO:%8.4f%% A:%8.4f%% Sys:%8.4f%% = %8.4f%%\n",
          100.0*video_time_usage/total_time_usage,
	  100.0*vout_time_usage/total_time_usage,
	  100.0*audio_time_usage/total_time_usage,
	  100.0*(total_time_usage-tot)/total_time_usage,
	  100.0);
  }
  // restore terminal:
  #ifdef HAVE_GUI
   if ( nogui )
  #endif
     getch2_disable();
  if(video_out) video_out->uninit();
  if(audio_out && has_audio) audio_out->uninit();
  if(encode_name) avi_fixate();
#ifdef HAVE_LIRC
  #ifdef HAVE_GUI
   if ( nogui )
  #endif
  lirc_mp_cleanup();
#endif
  //if(play_in_bg) system("xsetroot -solid \\#000000");
  exit(1);
}

static char* current_module=NULL; // for debugging

void exit_sighandler(int x){
  static int sig_count=0;
  ++sig_count;
  if(sig_count==2) exit(1);
  if(sig_count>2){
    // can't stop :(
    kill(getpid(),SIGKILL);
  }
  fprintf(stderr,"\nMPlayer interrupted by signal %d in module: %s \n",x,
      current_module?current_module:"unknown"
  );
  #ifdef HAVE_GUI
   if ( !nogui )
    {
     mplShMem->items.error.signal=x;
     strcpy( mplShMem->items.error.module,current_module?current_module:"unknown" );
    }
  #endif
  exit_player(NULL);
}

extern int vcd_get_track_end(int fd,int track);
extern int init_audio(sh_audio_t *sh_audio);
extern int init_video_codec(sh_video_t *sh_video);
extern void mpeg2_allocate_image_buffers(picture_t * picture);
extern void write_avi_header_1(FILE *f,int fcc,float fps,int width,int height);
extern int vo_init(void);
extern int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen);


#include "mixer.h"
#include "cfg-mplayer.h"

void parse_cfgfiles( void )
{
char *conffile;
int conffile_fd;
if (parse_config_file(conf, "/etc/mplayer.conf") < 0)
  exit(1);
if ((conffile = get_path("")) == NULL) {
  printf("Can't find HOME dir\n");
} else {
  mkdir(conffile, 0777);
  free(conffile);
  if ((conffile = get_path("config")) == NULL) {
    printf("get_path(\"config\") sziiiivas\n");
  } else {
    if ((conffile_fd = open(conffile, O_CREAT | O_EXCL | O_WRONLY, 0666)) != -1) {
      printf("Creating config file: %s\n", conffile);
      write(conffile_fd, default_config, strlen(default_config));
      close(conffile_fd);
    }
    if (parse_config_file(conf, conffile) < 0)
      exit(1);
    free(conffile);
  }
}
}

#ifndef HAVE_GUI
 int main(int argc,char* argv[], char *envp[]){
#else
 int mplayer(int argc,char* argv[], char *envp[]){
#endif

char* filename=NULL; //"MI2-Trailer.avi";
stream_t* stream=NULL;
int file_format=DEMUXER_TYPE_UNKNOWN;
//
int delay_corrected=1;
float initial_pts_delay=0;
#ifdef VCD_CACHE
int vcd_cache_size=128;
#endif
#ifdef __FreeBSD__
int bsize = VCD_SECTOR_SIZE;
#endif
char* title="MPlayer";

// movie info:
int out_fmt=0;
//int user_bpp=0;

int osd_visible=100;
int osd_function=OSD_PLAY;
int osd_last_pts=-303;

float a_frame=0;    // Audio

float rel_seek_secs=0;

int i;
int f; // filedes

  printf("%s",banner_text);

#ifdef HAVE_GUI
  if ( nogui )
   {
#endif
    parse_cfgfiles();
    if (parse_command_line(conf, argc, argv, envp, &filename) < 0) exit(1);

    // Many users forget to include command line in bugreports...
    if(verbose){
      printf("CommandLine:");
      for(i=1;i<argc;i++)printf(" '%s'",argv[i]);
      printf("\n");
    }

    if(video_driver && strcmp(video_driver,"help")==0){
      printf("Available video output drivers:\n");
      i=0;
      while (video_out_drivers[i]) {
        const vo_info_t *info = video_out_drivers[i++]->get_info ();
      	printf("\t%s\t%s\n", info->short_name, info->name);
      }
      printf("\n");
      exit(0);
    }
    if(audio_driver && strcmp(audio_driver,"help")==0){
      printf("Available audio output drivers:\n");
      i=0;
      while (audio_out_drivers[i]) {
        const ao_info_t *info = audio_out_drivers[i++]->info;
	printf("\t%s\t%s\n", info->short_name, info->name);
      }
      printf("\n");
      exit(0);
    }
#ifdef HAVE_GUI
   }
#endif

if(!filename){
  if(vcd_track) filename=DEFAULT_CDROM_DEVICE;
  else {
    printf("%s",help_text); exit(0);
  }
}

// check video_out driver name:
    if (video_driver)
	if ((i = strcspn(video_driver, ":")) > 0)
	{
	    size_t i2 = strlen(video_driver);

	    if (video_driver[i] == ':')
	    {
		vo_subdevice = malloc(i2-i);
		if (vo_subdevice != NULL)
		    strncpy(vo_subdevice, (char *)(video_driver+i+1), i2-i);
		video_driver[i] = '\0';
	    }
//	    printf("video_driver: %s, subdevice: %s\n", video_driver, vo_subdevice);
	}
  if(!video_driver)
    video_out=video_out_drivers[0];
  else
  for (i=0; video_out_drivers[i] != NULL; i++){
    const vo_info_t *info = video_out_drivers[i]->get_info ();
    if(strcmp(info->short_name,video_driver) == 0){
      video_out = video_out_drivers[i];break;
    }
  }
  if(!video_out){
    fprintf(stderr,"Invalid video output driver name: %s\nUse '-vo help' to get a list of available video drivers.\n",video_driver);
    return 0;
  }
  
// check audio_out driver name:
    if (audio_driver)
	if ((i = strcspn(audio_driver, ":")) > 0)
	{
	    size_t i2 = strlen(audio_driver);

	    if (audio_driver[i] == ':')
	    {
		ao_subdevice = malloc(i2-i);
		if (ao_subdevice != NULL)
		    strncpy(ao_subdevice, (char *)(audio_driver+i+1), i2-i);
		audio_driver[i] = '\0';
	    }
//	    printf("audio_driver: %s, subdevice: %s\n", audio_driver, ao_subdevice);
	}
  if(!audio_driver)
    audio_out=audio_out_drivers[0];
  else
  for (i=0; audio_out_drivers[i] != NULL; i++){
    const ao_info_t *info = audio_out_drivers[i]->info;
    if(strcmp(info->short_name,audio_driver) == 0){
      audio_out = audio_out_drivers[i];break;
    }
  }
  if (!audio_out){
    fprintf(stderr,"Invalid audio output driver name: %s\nUse '-ao help' to get a list of available audio drivers.\n",audio_driver);
    return 0;
  }
/*DSP!!  if(dsp) audio_out->control(AOCONTROL_SET_DEVICE,(int)dsp);*/

// check codec.conf
if(!parse_codec_cfg(get_path("codecs.conf"))){
    printf("(copy/link DOCS/codecs.conf to ~/.mplayer/codecs.conf)\n");
    GUI_MSG( mplCodecConfNotFound )
    exit(1);
}

// check font
  if(font_name){
       vo_font=read_font_desc(font_name,font_factor,verbose>1);
       if(!vo_font) fprintf(stderr,"Can't load font: %s\n",font_name);
  } else {
      // try default:
       vo_font=read_font_desc(get_path("font/font.desc"),font_factor,verbose>1);
  }

// check .sub
  if(sub_name){
       subtitles=sub_read_file(sub_name);
       if(!subtitles) fprintf(stderr,"Can't load subtitles: %s\n",sub_name);
  } else {
    if ( sub_auto )
      {
       // auto load sub file ...
       subtitles=sub_read_file( sub_filename( get_path("sub/"), filename ) );
      }
      if ( subtitles == NULL ) subtitles=sub_read_file(get_path("default.sub")); // try default:
  }


if(vcd_track){
//============ Open VideoCD track ==============
  int ret,ret2;
  f=open(filename,O_RDONLY);
  if(f<0){ fprintf(stderr,"CD-ROM Device '%s' not found!\n",filename);return 1; }
  vcd_read_toc(f);
  ret2=vcd_get_track_end(f,vcd_track);
  if(ret2<0){ fprintf(stderr,"Error selecting VCD track!\n");return 1;}
  ret=vcd_seek_to_track(f,vcd_track);
  if(ret<0){ fprintf(stderr,"Error selecting VCD track!\n");return 1;}
  seek_to_byte+=ret;
  if(verbose) printf("VCD start byte position: 0x%X  end: 0x%X\n",seek_to_byte,ret2);
#ifdef VCD_CACHE
  vcd_cache_init(vcd_cache_size);
#endif
#ifdef __FreeBSD__
  if (ioctl (f, CDRIOCSETBLOCKSIZE, &bsize) == -1) {
        perror ( "Error in CDRIOCSETBLOCKSIZE");
  }
#endif
  stream=new_stream(f,STREAMTYPE_VCD);
  stream->start_pos=ret;
  stream->end_pos=ret2;
} else {
//============ Open plain FILE ============
  int len;
  if(!strcmp(filename,"-")){
      // read from stdin
      printf("Reading from stdin...\n");
      f=0; // 0=stdin
      stream=new_stream(f,STREAMTYPE_STREAM);
  } else {
#ifdef STREAMING
      url = url_new(filename);
      if(url==NULL) {
       // failed to create a new URL, so it's not an URL (or a malformed URL)
#endif
       f=open(filename,O_RDONLY);
       if(f<0){ fprintf(stderr,"File not found: '%s'\n",filename);return 1; }
       len=lseek(f,0,SEEK_END); lseek(f,0,SEEK_SET);
       stream=new_stream(f,STREAMTYPE_FILE);
       stream->end_pos=len;
#ifdef STREAMING
      } else {
        file_format=autodetectProtocol( url, &f );
        if( file_format==DEMUXER_TYPE_UNKNOWN ) { 
          fprintf(stderr,"Unable to open URL: %s\n", filename);
          url_free(url);
          return 1; 
        } else {
          f=streaming_start( &url, f, file_format );
          if(f<0){ fprintf(stderr,"Unable to open URL: %s\n", url->url); return 1; }
          printf("Connected to server: %s\n", url->hostname );
        }
        stream=new_stream(f,STREAMTYPE_STREAM);
      }
#endif
  }
}

#ifdef HAVE_LIBCSS
  if (dvdimportkey) {
    if (dvd_import_key(dvdimportkey)) {
	fprintf(stderr,"Error processing DVD KEY.\n");
        GUI_MSG( mplErrorDVDKeyProcess )
	exit(1);
    }
    printf("DVD command line requested key is stored for descrambling.\n");
  }
  if (dvd_auth_device) {
//  if (dvd_auth(dvd_auth_device,f)) {
    if (dvd_auth(dvd_auth_device,filename)) {
        GUI_MSG( mplErrorDVDAuth )
        exit(0);
      } 
    printf("DVD auth sequence seems to be OK.\n");
  }
#endif

//============ Open & Sync stream and detect file format ===============

if(!has_audio) audio_id=-2; // do NOT read audio packets...

//=============== Try to open as AVI file: =================
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_AVI){
  stream_reset(stream);
  demuxer=new_demuxer(stream,DEMUXER_TYPE_AVI,audio_id,video_id,dvdsub_id);
  stream_seek(demuxer->stream,seek_to_byte);
  //printf("stream3=0x%X vs. 0x%X\n",demuxer->stream,stream);
  { //---- RIFF header:
    int id=stream_read_dword_le(demuxer->stream); // "RIFF"
    if(id==mmioFOURCC('R','I','F','F')){
      stream_read_dword_le(demuxer->stream); //filesize
      id=stream_read_dword_le(demuxer->stream); // "AVI "
      if(id==formtypeAVI){ 
        printf("Detected AVI file format!\n");
        file_format=DEMUXER_TYPE_AVI;
      }
    }
  }
}
//=============== Try to open as ASF file: =================
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_ASF){
  stream_reset(stream);
  demuxer=new_demuxer(stream,DEMUXER_TYPE_ASF,audio_id,video_id,dvdsub_id);
  stream_seek(demuxer->stream,seek_to_byte);
  if(asf_check_header(demuxer)){
      printf("Detected ASF file format!\n");
      file_format=DEMUXER_TYPE_ASF;
  }
}
//=============== Try to open as MPEG-PS file: =================
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
  stream_reset(stream);
  demuxer=new_demuxer(stream,DEMUXER_TYPE_MPEG_PS,audio_id,video_id,dvdsub_id);
  stream_seek(demuxer->stream,seek_to_byte);
  if(audio_format) demuxer->audio->type=audio_format; // override audio format
  if(ds_fill_buffer(demuxer->video)){
    printf("Detected MPEG-PS file format!\n");
    file_format=DEMUXER_TYPE_MPEG_PS;
  } else {
    // some hack to get meaningfull error messages to our unhappy users:
//    if(num_elementary_packets100>16 &&
//       abs(num_elementary_packets101-num_elementary_packets100)<8){
    if(num_elementary_packets100>=2 && num_elementary_packets101>=2 &&
       abs(num_elementary_packets101-num_elementary_packets100)<8){
      file_format=DEMUXER_TYPE_MPEG_ES; //  <-- hack is here :)
    } else {
      if(demuxer->synced==2)
        printf("Missing MPEG video stream!? contact the author, it may be a bug :(\n");
      else
        printf("Not MPEG System Stream format... (maybe Transport Stream?)\n");
    }
  }
}
//=============== Try to open as MPEG-ES file: =================
if(file_format==DEMUXER_TYPE_MPEG_ES){ // little hack, see above!
  stream_reset(stream);
  demuxer=new_demuxer(stream,DEMUXER_TYPE_MPEG_ES,audio_id,video_id,dvdsub_id);
  stream_seek(demuxer->stream,seek_to_byte);
  if(!ds_fill_buffer(demuxer->video)){
    printf("Invalid MPEG-ES stream??? contact the author, it may be a bug :(\n");
    file_format=DEMUXER_TYPE_UNKNOWN;
  } else {
    printf("Detected MPEG-ES file format!\n");
  }
}
#ifdef MOV
//=============== Try to open as MOV file: =================
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MOV){
  stream_reset(stream);
  demuxer=new_demuxer(stream,DEMUXER_TYPE_MOV,audio_id,video_id,dvdsub_id);
//  stream_seek(demuxer->stream,seek_to_byte);
  if(mov_check_file(demuxer)){
      printf("Detected MOV file format!\n");
      file_format=DEMUXER_TYPE_MOV;
  }
}
#endif
//=============== Unknown, exiting... ===========================
if(file_format==DEMUXER_TYPE_UNKNOWN){
  fprintf(stderr,"============= Sorry, this file format not recognized/supported ===============\n");
  fprintf(stderr,"=== If this file is an AVI, ASF or MPEG stream, please contact the author! ===\n");
  GUI_MSG( mplUnknowFileType )
  exit(1);
}
//====== File format recognized, set up these for compatibility: =========
d_audio=demuxer->audio;
d_video=demuxer->video;
d_dvdsub=demuxer->sub;
//d_audio->sh=sh_audio; 
//d_video->sh=sh_video; 
//sh_audio=d_audio->sh;sh_audio->ds=d_audio;
//sh_video=d_video->sh;sh_video->ds=d_video;

sh_audio=NULL;
sh_video=NULL;

switch(file_format){
 case DEMUXER_TYPE_AVI: {
  //---- AVI header:
  read_avi_header(demuxer,(stream->type!=STREAMTYPE_STREAM)?index_mode:-2);
  stream_reset(demuxer->stream);
  stream_seek(demuxer->stream,demuxer->movi_start);
  demuxer->idx_pos=0;
  demuxer->idx_pos_a=0;
  demuxer->idx_pos_v=0;
  if(demuxer->idx_size>0){
    // decide index format:
    if(((AVIINDEXENTRY *)demuxer->idx)[0].dwChunkOffset<demuxer->movi_start)
      demuxer->idx_offset=demuxer->movi_start-4;
    else
      demuxer->idx_offset=0;
    if(verbose) printf("AVI index offset: %d\n",demuxer->idx_offset);
  }
//  demuxer->endpos=avi_header.movi_end;
  
  if(demuxer->idx_size>0){
      // check that file is non-interleaved:
      int i;
      int a_pos=-1;
      int v_pos=-1;
      for(i=0;i<demuxer->idx_size;i++){
        AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)demuxer->idx)[i];
        demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);
        int pos=idx->dwChunkOffset+demuxer->idx_offset;
        if(a_pos==-1 && ds==demuxer->audio){
          a_pos=pos;
          if(v_pos!=-1) break;
        }
        if(v_pos==-1 && ds==demuxer->video){
          v_pos=pos;
          if(a_pos!=-1) break;
        }
      }
      if(v_pos==-1){
        fprintf(stderr,"AVI_NI: missing video stream!? contact the author, it may be a bug :(\n");
        GUI_MSG( mplErrorAVINI )
        exit(1);
      }
      if(a_pos==-1){
        printf("AVI_NI: No audio stream found -> nosound\n");
        has_audio=0;sh_audio=NULL;
      } else {
        if(force_ni || abs(a_pos-v_pos)>0x100000){  // distance > 1MB
          printf("Detected NON-INTERLEAVED AVI file-format!\n");
          demuxer->type=DEMUXER_TYPE_AVI_NI; // HACK!!!!
	  pts_from_bps=1; // force BPS sync!
        }
      }
  } else {
      // no index
      if(force_ni){
          printf("Using NON-INTERLEAVED Broken AVI file-format!\n");
          demuxer->type=DEMUXER_TYPE_AVI_NINI; // HACK!!!!
	  demuxer->idx_pos_a=
	  demuxer->idx_pos_v=demuxer->movi_start;
	  pts_from_bps=1; // force BPS sync!
      }
  }
  if(!ds_fill_buffer(d_video)){
    fprintf(stderr,"AVI: missing video stream!? contact the author, it may be a bug :(\n");
    GUI_MSG( mplAVIErrorMissingVideoStream )
    exit(1);
  }
  sh_video=d_video->sh;sh_video->ds=d_video;
  if(has_audio){
    if(verbose) printf("AVI: Searching for audio stream (id:%d)\n",d_audio->id);
    if(!ds_fill_buffer(d_audio)){
      printf("AVI: No Audio stream found...  ->nosound\n");
      has_audio=0;sh_audio=NULL;
    } else {
      sh_audio=d_audio->sh;sh_audio->ds=d_audio;
      sh_audio->format=sh_audio->wf->wFormatTag;
    }
  }
  // calc. FPS:
  sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
  sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
  // calculating video bitrate:
  avi_bitrate=demuxer->movi_end-demuxer->movi_start-demuxer->idx_size*8;
  if(sh_audio) avi_bitrate-=sh_audio->audio.dwLength;
  if(verbose) printf("AVI video length=%d\n",avi_bitrate);
  avi_bitrate=((float)avi_bitrate/(float)sh_video->video.dwLength)*sh_video->fps;
  printf("VIDEO:  [%.4s]  %ldx%ld  %dbpp  %4.2f fps  %5.1f kbps (%4.1f kbyte/s)\n",
    (char *)&sh_video->bih->biCompression,
    sh_video->bih->biWidth,
    sh_video->bih->biHeight,
    sh_video->bih->biBitCount,
    sh_video->fps,
    avi_bitrate*0.008f,
    avi_bitrate/1024.0f );
  break;
 }
 case DEMUXER_TYPE_ASF: {
  //---- ASF header:
  read_asf_header(demuxer);
  stream_reset(demuxer->stream);
  stream_seek(demuxer->stream,demuxer->movi_start);
  demuxer->idx_pos=0;
//  demuxer->endpos=avi_header.movi_end;
  if(!ds_fill_buffer(d_video)){
    printf("ASF: no video stream found!\n");
    sh_video=NULL;
    //printf("ASF: missing video stream!? contact the author, it may be a bug :(\n");
    //GUI_MSG( mplASFErrorMissingVideoStream )
    //exit(1);
  } else {
    sh_video=d_video->sh;sh_video->ds=d_video;
    sh_video->fps=1000.0f; sh_video->frametime=0.001f; // 1ms
    printf("VIDEO:  [%.4s]  %ldx%ld  %dbpp\n",
      (char *)&sh_video->bih->biCompression,
      sh_video->bih->biWidth,
      sh_video->bih->biHeight,
      sh_video->bih->biBitCount);
  }
  if(has_audio){
    if(verbose) printf("ASF: Searching for audio stream (id:%d)\n",d_audio->id);
    if(!ds_fill_buffer(d_audio)){
      printf("ASF: No Audio stream found...  ->nosound\n");
      has_audio=0;sh_audio=NULL;
    } else {
      sh_audio=d_audio->sh;sh_audio->ds=d_audio;
      sh_audio->format=sh_audio->wf->wFormatTag;
    }
  }
  break;
 }
 case DEMUXER_TYPE_MPEG_ES: {
   d_audio->type=0;
   has_audio=0;sh_audio=NULL;   // ES streams has no audio channel
   d_video->sh=new_sh_video(0); // create dummy video stream header, id=0
   break;
 }
 case DEMUXER_TYPE_MPEG_PS: {
  if(has_audio) {
  if(!ds_fill_buffer(d_audio)){
    printf("MPEG: No Audio stream found...  ->nosound\n");
    has_audio=0;sh_audio=NULL;
  } else {
    sh_audio=d_audio->sh;sh_audio->ds=d_audio;
    if(verbose) printf("detected MPG-PS audio format: %d\n",d_audio->type);
    switch(d_audio->type){
      case 1: sh_audio->format=0x50;break; // mpeg
      case 2: sh_audio->format=0x10001;break;  // dvd pcm
      case 3: sh_audio->format=0x2000;break; // ac3
      default: has_audio=0;sh_audio=NULL; // unknown type
    }
  }
  }
  break;
 }
} // switch(file_format)

// DUMP STREAMS:
if(stream_dump_type){
  FILE *f;
  demux_stream_t *ds=NULL;
  // select stream to dump
  switch(stream_dump_type){
  case 1: ds=d_audio;break;
  case 2: ds=d_video;break;
  case 3: ds=d_dvdsub;break;
  }
  if(!ds){        
      fprintf(stderr,"dump: FATAL: selected stream missing!\n");
      exit(1);
  }
  // disable other streams:
  if(d_audio && d_audio!=ds) {ds_free_packs(d_audio); d_audio->id=-2; }
  if(d_video && d_video!=ds) {ds_free_packs(d_video); d_video->id=-2; }
  if(d_dvdsub && d_dvdsub!=ds) {ds_free_packs(d_dvdsub); d_dvdsub->id=-2; }
  // let's dump it!
  f=fopen(stream_dump_name?stream_dump_name:"stream.dump","wb");
  if(!f){ fprintf(stderr,"Can't open dump file!!!\n");exit(1); }
  while(!ds->eof){
    unsigned char* start;
    int in_size=ds_get_packet(ds,&start);
    if( (file_format==DEMUXER_TYPE_AVI || file_format==DEMUXER_TYPE_ASF)
	&& stream_dump_type==2) fwrite(&in_size,1,4,f);
    if(in_size>0) fwrite(start,in_size,1,f);
  }
  fclose(f);
  printf("core dumped :)\n");
  exit(1);
}


// Determine image properties:
switch(file_format){
 case DEMUXER_TYPE_AVI:
 case DEMUXER_TYPE_ASF: {
  // display info:
  if(sh_video){
    sh_video->format=sh_video->bih->biCompression;
    sh_video->disp_w=sh_video->bih->biWidth;
    sh_video->disp_h=abs(sh_video->bih->biHeight);
  }
  break;
 }
 case DEMUXER_TYPE_MPEG_ES:
 case DEMUXER_TYPE_MPEG_PS: {
   // Find sequence_header first:
   if(verbose) printf("Searching for sequence header... ");fflush(stdout);
   while(1){
      int i=sync_video_packet(d_video);
      if(i==0x1B3) break; // found it!
      if(!i || !skip_video_packet(d_video)){
        if(verbose)  printf("NONE :(\n");
        fprintf(stderr,"MPEG: FATAL: EOF while searching for sequence header\n");
        GUI_MSG( mplMPEGErrorSeqHeaderSearch )
        exit(1);
      }
   }
   if(verbose) printf("OK!\n");
   sh_video=d_video->sh;sh_video->ds=d_video;
   sh_video->format=0x10000001; // mpeg video
   mpeg2_init();
   // ========= Read & process sequence header & extension ============
   videobuffer=shmem_alloc(VIDEOBUFFER_SIZE);
   if(!videobuffer){ 
     fprintf(stderr,"Cannot allocate shared memory\n");
     GUI_MSG( mplErrorShMemAlloc )
     exit(0);
   }
   videobuf_len=0;
   if(!read_video_packet(d_video)){ 
     fprintf(stderr,"FATAL: Cannot read sequence header!\n");
     GUI_MSG( mplMPEGErrorCannotReadSeqHeader )
     exit(1);
   }
   if(header_process_sequence_header (picture, &videobuffer[4])) {
     printf ("bad sequence header!\n"); 
     GUI_MSG( mplMPEGErrorBadSeqHeader )
     exit(1);
   }
   if(sync_video_packet(d_video)==0x1B5){ // next packet is seq. ext.
    videobuf_len=0;
    if(!read_video_packet(d_video)){ 
      fprintf(stderr,"FATAL: Cannot read sequence header extension!\n");
      GUI_MSG( mplMPEGErrorCannotReadSeqHeaderExt )
      exit(1);
    }
    if(header_process_extension (picture, &videobuffer[4])) {
      printf ("bad sequence header extension!\n");  
      GUI_MSG( mplMPEGErrorBadSeqHeaderExt )
      exit(1);
    }
   }
   // display info:
   sh_video->fps=frameratecode2framerate[picture->frame_rate_code]*0.0001f;
   if(!sh_video->fps){
     if(!force_fps){
       fprintf(stderr,"FPS not specified (or invalid) in the header! Use the -fps option!\n");
       exit(1);
     }
     sh_video->frametime=0;
   } else {
     sh_video->frametime=10000.0f/(float)frameratecode2framerate[picture->frame_rate_code];
   }
   sh_video->disp_w=picture->display_picture_width;
   sh_video->disp_h=picture->display_picture_height;
   // info:
   if(verbose) printf("mpeg bitrate: %d (%X)\n",picture->bitrate,picture->bitrate);
   printf("VIDEO:  %s  %dx%d  (aspect %d)  %4.2f fps  %5.1f kbps (%4.1f kbyte/s)\n",
    picture->mpeg1?"MPEG1":"MPEG2",
    sh_video->disp_w,sh_video->disp_h,
    picture->aspect_ratio_information,
    sh_video->fps,
    picture->bitrate*0.5f,
    picture->bitrate/16.0f );
  break;
 }
} // switch(file_format)

//if(verbose) printf("file successfully opened  (has_audio=%d)\n",has_audio);

if(sh_video)
printf("[V] filefmt:%d  fourcc:0x%X  size:%dx%d  fps:%5.2f  ftime:=%6.4f\n",
   file_format,sh_video->format, sh_video->disp_w,sh_video->disp_h,
   sh_video->fps,sh_video->frametime
);

fflush(stdout);

if(!sh_video){
    fprintf(stderr,"Sorry, no video stream... it's unplayable yet\n");
    exit(1);
}

//================== Init AUDIO (codec) ==========================
if(has_audio){
  // Go through the codec.conf and find the best codec...
  sh_audio->codec=NULL;
  while(1){
    sh_audio->codec=find_codec(sh_audio->format,NULL,sh_audio->codec,1);
    if(!sh_audio->codec){
      printf("Can't find codec for audio format 0x%X !\n",sh_audio->format);
      printf("*** Try to upgrade %s from DOCS/codecs.conf\n",get_path("codecs.conf"));
      printf("*** If it's still not OK, then read DOCS/CODECS!\n");
      has_audio=0;
      break;
    }
    if(audio_format>0 && sh_audio->codec->driver!=audio_format) continue;
    printf("Found audio codec: [%s] drv:%d (%s)\n",sh_audio->codec->name,sh_audio->codec->driver,sh_audio->codec->info);
    //has_audio=sh_audio->codec->driver;
    break;
  }
}

if(has_audio){
  if(verbose) printf("Initializing audio codec...\n");
  if(!init_audio(sh_audio)){
    printf("Couldn't initialize audio codec! -> nosound\n");
    has_audio=0;
  } else {
    printf("AUDIO: srate=%d  chans=%d  bps=%d  sfmt=0x%X  ratio: %d->%d\n",sh_audio->samplerate,sh_audio->channels,sh_audio->samplesize,
        sh_audio->sample_format,sh_audio->i_bps,sh_audio->o_bps);
  }
}

//================== Init VIDEO (codec & libvo) ==========================

// Go through the codec.conf and find the best codec...
sh_video->codec=NULL;
if (force_vcodec!=-1) printf("Trying to use forced video codec driver %d ...\n",force_vcodec);
while(1){
  sh_video->codec=find_codec(sh_video->format,
    sh_video->bih?((unsigned int*) &sh_video->bih->biCompression):NULL,sh_video->codec,0);
  if(!sh_video->codec){
    if(force_vcodec!=-1) {
      sh_video->codec=NULL; /* re-search */
      printf("Can't find video codec for forced driver %d, defaulting to other drivers.\n",force_vcodec);
      force_vcodec=-1;
      continue;      
    }
    printf("Can't find codec for video format 0x%X !\n",sh_video->format);
      printf("*** Try to upgrade %s from DOCS/codecs.conf\n",get_path("codecs.conf"));
      printf("*** If it's still not OK, then read DOCS/CODECS!\n");
    #ifdef HAVE_GUI
     if ( !nogui )
      {
       mplShMem->items.videodata.format=sh_video->format;
       mplSendMessage( mplCantFindCodecForVideoFormat );
       usec_sleep( 10000 );
      }
    #endif
    exit(1);
  }
  if(sh_video->codec->driver==force_vcodec) break;  /* OK, we find our codec */
  if(force_vcodec!=-1&&sh_video->codec->driver!=force_vcodec) continue;
  if(!allow_dshow && sh_video->codec->driver==4) continue; // skip DShow
  break;
}
//has_video=sh_video->codec->driver;

printf("Found video codec: [%s] drv:%d (%s)\n",sh_video->codec->name,sh_video->codec->driver,sh_video->codec->info);

for(i=0;i<CODECS_MAX_OUTFMT;i++){
    int ret;
    out_fmt=sh_video->codec->outfmt[i];
    if(out_fmt==0xFFFFFFFF) continue;
    ret=video_out->query_format(out_fmt);
    if(verbose) printf("vo_debug: query(%s) returned 0x%X\n",vo_format_name(out_fmt),ret);
    if(ret) break;
}
if(i>=CODECS_MAX_OUTFMT){
    fprintf(stderr,"Sorry, selected video_out device is incompatible with this codec.\n");
    GUI_MSG( mplIncompatibleVideoOutDevice )
    exit(1);
}
sh_video->outfmtidx=i;

if(flip==-1){
    // autodetect flipping
    flip=0;
    if(sh_video->codec->outflags[i]&CODECS_FLAG_FLIP)
      if(!(sh_video->codec->outflags[i]&CODECS_FLAG_NOFLIP))
         flip=1;
}

if(verbose) printf("vo_debug1: out_fmt=%s\n",vo_format_name(out_fmt));

switch(sh_video->codec->driver){
 case 2: {
   if(!init_video_codec(sh_video)) {
     GUI_MSG( mplUnknowError )
     exit(1);
   }  
   if(verbose) printf("INFO: Win32 video codec init OK!\n");
   break;
 }
 case 4: { // Win32/DirectShow
#ifndef USE_DIRECTSHOW
   fprintf(stderr,"MPlayer was compiled WITHOUT directshow support!\n");
   GUI_MSG( mplCompileWithoutDSSupport )
   exit(1);
#else
   sh_video->our_out_buffer=NULL;
   if(DS_VideoDecoder_Open(sh_video->codec->dll,&sh_video->codec->guid, sh_video->bih, 0, &sh_video->our_out_buffer)){
//   if(DS_VideoDecoder_Open(sh_video->codec->dll,&sh_video->codec->guid, sh_video->bih, 0, NULL)){
        printf("ERROR: Couldn't open required DirectShow codec: %s\n",sh_video->codec->dll);
        printf("Maybe you forget to upgrade your win32 codecs?? It's time to download the new\n");
        printf("package from:  ftp://thot.banki.hu/esp-team/linux/MPlayer/w32codec.zip  !\n");
        printf("Or you should disable DShow support: make distclean;make -f Makefile.No-DS\n");
        #ifdef HAVE_GUI
         if ( !nogui )
          {
           strcpy(  mplShMem->items.videodata.codecdll,sh_video->codec->dll );
           mplSendMessage( mplDSCodecNotFound );
           usec_sleep( 10000 );
          }
        #endif
        exit(1);
   }
   
   switch(out_fmt){
   case IMGFMT_YUY2:
   case IMGFMT_UYVY:
     DS_VideoDecoder_SetDestFmt(16,out_fmt);break;        // packed YUV
   case IMGFMT_YV12:
   case IMGFMT_I420:
   case IMGFMT_IYUV:
     DS_VideoDecoder_SetDestFmt(12,out_fmt);break;        // planar YUV
   default:
     DS_VideoDecoder_SetDestFmt(out_fmt&255,0);           // RGB/BGR
   }

   DS_VideoDecoder_Start();

   printf("DivX setting result = %d\n", DS_SetAttr_DivX("Quality",divx_quality) );
//   printf("DivX setting result = %d\n", DS_SetValue_DivX("Brightness",60) );
   
   if(verbose) printf("INFO: Win32/DShow video codec init OK!\n");
   break;
#endif
 }
 case 3: {  // OpenDivX
   if(verbose) printf("OpenDivX video codec\n");
   { DEC_PARAM dec_param;
     DEC_SET dec_set;
#ifdef NEW_DECORE
     DEC_MEM_REQS dec_mem;
        dec_param.output_format=DEC_USER;
#else
        dec_param.color_depth = 32;
#endif
	dec_param.x_dim = sh_video->bih->biWidth;
	dec_param.y_dim = sh_video->bih->biHeight;
#ifdef NEW_DECORE
        // 0.50-CVS new malloc scheme
        decore(0x123, DEC_OPT_MEMORY_REQS, &dec_param, &dec_mem);
        dec_param.buffers.mp4_edged_ref_buffers=malloc(dec_mem.mp4_edged_ref_buffers_size);
        dec_param.buffers.mp4_edged_for_buffers=malloc(dec_mem.mp4_edged_for_buffers_size);
        dec_param.buffers.mp4_display_buffers=malloc(dec_mem.mp4_display_buffers_size);
        dec_param.buffers.mp4_state=malloc(dec_mem.mp4_state_size);
        dec_param.buffers.mp4_tables=malloc(dec_mem.mp4_tables_size);
        dec_param.buffers.mp4_stream=malloc(dec_mem.mp4_stream_size);
#endif
	decore(0x123, DEC_OPT_INIT, &dec_param, NULL);

	dec_set.postproc_level = divx_quality;
	decore(0x123, DEC_OPT_SETPP, &dec_set, NULL);

   }
   if(verbose) printf("INFO: OpenDivX video codec init OK!\n");
   break;
 }
 case 5: {  // FFmpeg's libavcodec
#ifndef USE_LIBAVCODEC
   fprintf(stderr,"MPlayer was compiled WITHOUT libavcodec support!\n");
   exit(1);
#else
   if(verbose) printf("FFmpeg's libavcodec video codec\n");
    avcodec_init();
    avcodec_register_all();
    lavc_codec = avcodec_find_decoder_by_name(sh_video->codec->dll);
    if(!lavc_codec){
	fprintf(stderr,"Can't find codec '%s' in libavcodec...\n",sh_video->codec->dll);
	exit(1);
    }
    memset(&lavc_context, 0, sizeof(lavc_context));
    lavc_context.width=sh_video->disp_w;
    lavc_context.height=sh_video->disp_h;
    printf("libavcodec.size: %d x %d\n",lavc_context.width,lavc_context.height);
    /* open it */
    if (avcodec_open(&lavc_context, lavc_codec) < 0) {
        fprintf(stderr, "could not open codec\n");
        exit(1);
    }
   
   if(verbose) printf("INFO: libavcodec init OK!\n");
   break;
#endif
 }

 case 1: {
   // init libmpeg2:
#ifdef MPEG12_POSTPROC
   picture->pp_options=divx_quality;
#else
   if(divx_quality){
       printf("WARNING! You requested image postprocessing for an MPEG 1/2 video,\n");
       printf("         but compiled MPlayer without MPEG 1/2 postprocessing support!\n");
       printf("         #define MPEG12_POSTPROC in config.h, and recompile libmpeg2!\n");
   }
#endif
   mpeg2_allocate_image_buffers (picture);
   break;
 }
}

if(verbose) printf("vo_debug2: out_fmt=%s\n",vo_format_name(out_fmt));

// ================== Init output files for encoding ===============
   if(encode_name){
     // encode file!!!
     FILE *encode_file=fopen(encode_name,"rb");
     if(encode_file){
       fclose(encode_file);
       fprintf(stderr,"File already exists: %s (don't overwrite your favourite AVI!)\n",encode_name);
       return 0;
     }
     encode_file=fopen(encode_name,"wb");
     if(!encode_file){
       fprintf(stderr,"Cannot create file for encoding\n");
       return 0;
     }
     write_avi_header_1(encode_file,mmioFOURCC('d', 'i', 'v', 'x'),sh_video->fps,sh_video->disp_w,sh_video->disp_h);
     fclose(encode_file);
     encode_index_name=malloc(strlen(encode_name)+8);
     strcpy(encode_index_name,encode_name);
     strcat(encode_index_name,".index");
     if((encode_file=fopen(encode_index_name,"wb")))
       fclose(encode_file);
     else encode_index_name=NULL;
     has_audio=0; // disable audio !!!!!
   }

// ========== Init keyboard FIFO (connection to libvo) ============

make_pipe(&keyb_fifo_get,&keyb_fifo_put);

// ========== Init display (sh_video->disp_w*sh_video->disp_h/out_fmt) ============

#ifdef X11_FULLSCREEN
   if(fullscreen){
     if(vo_init()){
       //if(verbose) printf("X11 running at %dx%d depth: %d\n",vo_screenwidth,vo_screenheight,vo_depthonscreen);
     }
     if(!screen_size_xy) screen_size_xy=vo_screenwidth; // scale with asp.ratio
   }
#endif

   if(screen_size_xy>0){
     if(screen_size_xy<=8){
       screen_size_x=screen_size_xy*sh_video->disp_w;
       screen_size_y=screen_size_xy*sh_video->disp_h;
     } else {
       screen_size_x=screen_size_xy;
       screen_size_y=screen_size_xy*sh_video->disp_h/sh_video->disp_w;
     }
   } else if(!vidmode){
     if(!screen_size_x) screen_size_x=SCREEN_SIZE_X;
     if(!screen_size_y) screen_size_y=SCREEN_SIZE_Y;
     if(screen_size_x<=8) screen_size_x*=sh_video->disp_w;
     if(screen_size_y<=8) screen_size_y*=sh_video->disp_h;
   }

   { const vo_info_t *info = video_out->get_info();
     printf("VO: [%s] %dx%d => %dx%d %s %s%s%s%s\n",info->short_name,
         sh_video->disp_w,sh_video->disp_h,
         screen_size_x,screen_size_y,
	 vo_format_name(out_fmt),
         fullscreen?"fs ":"",
         vidmode?"vm ":"",
         softzoom?"zoom ":"",
         (flip==1)?"flip ":""
//         fullscreen|(vidmode<<1)|(softzoom<<2)|(flip<<3)
     );
    printf("VO: Description: %s\n"
           "VO: Author: %s\n",
        info->name,
        info->author	
     );
    if(strlen(info->comment) > 0)
        printf("VO: Comment: %s\n", info->comment);
   }

//   if(verbose) printf("Destination size: %d x %d  out_fmt=%0X\n",
//                      screen_size_x,screen_size_y,out_fmt);

   if(verbose) printf("video_out->init(%dx%d->%dx%d,flags=%d,'%s',0x%X)\n",
                      sh_video->disp_w,sh_video->disp_h,
                      screen_size_x,screen_size_y,
                      fullscreen|(vidmode<<1)|(softzoom<<2)|(flip<<3),
                      title,out_fmt);

if(verbose) printf("vo_debug3: out_fmt=%s\n",vo_format_name(out_fmt));

   #ifdef HAVE_GUI
    if ( !nogui )
     {
      mplShMem->items.videodata.width=sh_video->disp_w;
      mplShMem->items.videodata.height=sh_video->disp_h;
      mplSendMessage( mplSetVideoData );
     }
   #endif

   if(video_out->init(sh_video->disp_w,sh_video->disp_h,
                      screen_size_x,screen_size_y,
                      fullscreen|(vidmode<<1)|(softzoom<<2)|(flip<<3),
                      title,out_fmt)){
     fprintf(stderr,"FATAL: Cannot initialize video driver!\n");
     GUI_MSG( mplCantInitVideoDriver )
     exit(1);
   }
   if(verbose) printf("INFO: Video OUT driver init OK!\n");

   fflush(stdout);
   
//================== MAIN: ==========================
{
//float audio_buffer_delay=0;

//float buffer_delay=0;
float frame_correction=0; // A-V timestamp kulonbseg atlagolas
int frame_corr_num=0;   //
float v_frame=0;    // Video
float time_frame=0; // Timer
float c_total=0;
float max_pts_correction=0;//default_max_pts_correction;
int eof=0;
int force_redraw=0;
float num_frames=0;      // number of frames played
int grab_frames=0;
char osd_text_buffer[64];
int drop_frame=0;
int drop_frame_cnt=0;

#ifdef HAVE_LIRC
 #ifdef HAVE_GUI
  if ( nogui )
 #endif
  lirc_mp_setup();
#endif

  #ifdef HAVE_GUI
   if ( nogui )
    {
  #endif
#ifdef USE_TERMCAP
  load_termcap(NULL); // load key-codes
#endif
  if(f) getch2_enable();
  #ifdef HAVE_GUI
   }
  #endif 

  //========= Catch terminate signals: ================
  // terminate requests:
  signal(SIGTERM,exit_sighandler); // kill
  signal(SIGHUP,exit_sighandler);  // kill -HUP  /  xterm closed

  #ifdef HAVE_GUI
   if ( nogui )
  #endif
     signal(SIGINT,exit_sighandler);  // Interrupt from keyboard

  signal(SIGQUIT,exit_sighandler); // Quit from keyboard
  // fatal errors:
  signal(SIGBUS,exit_sighandler);  // bus error
  signal(SIGSEGV,exit_sighandler); // segfault
  signal(SIGILL,exit_sighandler);  // illegal instruction
  signal(SIGFPE,exit_sighandler);  // floating point exc.
  signal(SIGABRT,exit_sighandler); // abort()

//================ SETUP AUDIO ==========================
  current_module="setup_audio";

if(has_audio){
  
  const ao_info_t *info=audio_out->info;
  printf("AO: [%s] %iHz %s %s\n"
         "AO: Description: %s\n"
         "AO: Author: %s\n",
      info->short_name,
      force_srate?force_srate:sh_audio->samplerate,
      sh_audio->channels>1?"Stereo":"Mono",
      audio_out_format_name(sh_audio->sample_format),
      info->name,
      info->author	
   );
  if(strlen(info->comment) > 0)
      printf("AO: Comment: %s\n", info->comment);

  if(!audio_out->init(force_srate?force_srate:sh_audio->samplerate,
      sh_audio->channels,sh_audio->sample_format,0)){
    printf("couldn't open/init audio device -> NOSOUND\n");
    has_audio=0;
  }

//  printf("Audio buffer size: %d bytes, delay: %5.3fs\n",audio_buffer_size,audio_buffer_delay);

  // fixup audio buffer size:
//  if(outburst<MAX_OUTBURST){
//    sh_audio->a_buffer_size=sh_audio->audio_out_minsize+outburst;
//    printf("Audio out buffer size reduced to %d bytes\n",sh_audio->a_buffer_size);
//  }

//  a_frame=-(audio_buffer_delay);
}

  a_frame=0;

if(!has_audio){
  printf("Audio: no sound\n");
  if(verbose) printf("Freeing %d unused audio chunks\n",d_audio->packs);
  ds_free_packs(d_audio); // free buffered chunks
  d_audio->id=-2;         // do not read audio chunks
  if(sh_audio) if(sh_audio->a_buffer) free(sh_audio->a_buffer);
  //alsa=1;
  // fake, required for timer:
#if 1
  sh_audio=NULL;
#else
  sh_audio=new_sh_audio(255); // FIXME!!!!!!!!!!
  sh_audio->samplerate=76800;
  sh_audio->samplesize=sh_audio->channels=2;
  sh_audio->o_bps=sh_audio->channels*sh_audio->samplerate*sh_audio->samplesize;
#endif
}

  current_module=NULL;

//==================== START PLAYING =======================

if(file_format==DEMUXER_TYPE_AVI && has_audio){
  //a_pts=d_audio->pts;
  printf("Initial frame delay  A: %d  V: %d\n",(int)sh_audio->audio.dwInitialFrames,(int)sh_video->video.dwInitialFrames);
  if(!pts_from_bps){
    float x=(float)(sh_audio->audio.dwInitialFrames-sh_video->video.dwInitialFrames)*sh_video->frametime;
    audio_delay-=x;
    printf("AVI Initial frame delay: %5.3f\n",x);
  }
  if(verbose){
//    printf("v: audio_delay=%5.3f  buffer_delay=%5.3f  a_pts=%5.3f  a_frame=%5.3f\n",
//             audio_delay,audio_buffer_delay,a_pts,a_frame);
    printf("START:  a_pts=%5.3f  v_pts=%5.3f  \n",d_audio->pts,d_video->pts);
  }
  delay_corrected=0; // has to correct PTS diffs
  d_video->pts=0;d_audio->pts=0; // PTS is outdated now!
} else {
  pts_from_bps=0; // it must be 0 for mpeg/asf !
}
if(force_fps){
  sh_video->fps=force_fps;
  sh_video->frametime=1.0f/sh_video->fps;
  printf("FPS forced to be %5.3f  (ftime: %5.3f)\n",sh_video->fps,sh_video->frametime);
}

printf("Start playing...\n");fflush(stdout);

InitTimer();

total_time_usage_start=GetTimer();

while(!eof){

    if(play_n_frames>=0){
      --play_n_frames;
      if(play_n_frames<0) exit_player("Requested number of frames played");
    }

/*========================== PLAY AUDIO ============================*/
//if(!has_audio){
//  int playsize=512;
//  a_frame+=playsize/(float)(sh_audio->o_bps);
//  a_pts+=playsize/(float)(sh_audio->o_bps);
  //time_frame+=playsize/(float)(sh_audio->o_bps);
//} else
while(has_audio){
  unsigned int t;
  int playsize=audio_out->get_space();
  
  if(!playsize) break; // buffer is full, do not block here!!!
  
  if(playsize>MAX_OUTBURST) playsize=MAX_OUTBURST; // we shouldn't exceed it!
  //if(playsize>outburst) playsize=outburst;

  // Update buffer if needed
  t=GetTimer();
  current_module="decode_audio";   // Enter AUDIO decoder module
  while(sh_audio->a_buffer_len<playsize && !d_audio->eof){
    int ret=decode_audio(sh_audio,&sh_audio->a_buffer[sh_audio->a_buffer_len],
        playsize-sh_audio->a_buffer_len,sh_audio->a_buffer_size-sh_audio->a_buffer_len);
    if(ret>0) sh_audio->a_buffer_len+=ret; else break;
  }
  current_module=NULL;   // Leave AUDIO decoder module
  t=GetTimer()-t;audio_time_usage+=t*0.000001;
  
  if(playsize>sh_audio->a_buffer_len) playsize=sh_audio->a_buffer_len;
  
  playsize=audio_out->play(sh_audio->a_buffer,playsize,0);

  if(playsize>0){
      sh_audio->a_buffer_len-=playsize;
      memcpy(sh_audio->a_buffer,&sh_audio->a_buffer[playsize],sh_audio->a_buffer_len);
      a_frame+=playsize/(float)(sh_audio->o_bps);
      //a_pts+=playsize/(float)(sh_audio->o_bps);
//      time_frame+=playsize/(float)(sh_audio->o_bps);
  }

  break;
} // if(has_audio)

/*========================== UPDATE TIMERS ============================*/
#if 0
  if(alsa){
    // Use system timer for sync, not audio card/driver
    time_frame-=GetRelativeTime();
    if(time_frame<-0.1 || time_frame>0.1){
      time_frame=0;
    } else {
        while(time_frame>0.022){
            usec_sleep(time_frame-0.022);
            time_frame-=GetRelativeTime();
        }
        while(time_frame>0.007){
            usec_sleep(1000);	// sleeps 1 clock tick (10ms)!
            time_frame-=GetRelativeTime();
        }
    }
  }
#endif

/*========================== PLAY VIDEO ============================*/

if(1)
  while(1){
  
    float frame_time=1;
    float pts1=d_video->pts;
    int blit_frame=1;

    current_module="decode_video";
    
//    if(!force_redraw && v_frame+0.1<a_frame) drop_frame=1; else drop_frame=0;
//    if(drop_frame) ++drop_frame_cnt;

  //--------------------  Decode a frame: -----------------------
switch(sh_video->codec->driver){
  case 3: {
    // OpenDivX
    unsigned int t=GetTimer();
    unsigned int t2;
    DEC_FRAME dec_frame;
#ifdef NEW_DECORE
    DEC_PICTURE dec_pic;
#endif
    unsigned char* start=NULL;
    int in_size=ds_get_packet(d_video,&start);
    if(in_size<0){ eof=1;break;}
    if(in_size>max_framesize) max_framesize=in_size;
    // let's decode
        dec_frame.length = in_size;
	dec_frame.bitstream = start;
	dec_frame.render_flag = 1;
#ifdef NEW_DECORE
        dec_frame.bmp=&dec_pic;
        dec_pic.y=dec_pic.u=dec_pic.v=NULL;
#endif
	decore(0x123, 0, &dec_frame, NULL);
      t2=GetTimer();t=t2-t;video_time_usage+=t*0.000001f;

#ifdef NEW_DECORE
      if(dec_pic.y){
        void* src[3];
        int stride[3];
        src[0]=dec_pic.y;
        src[1]=dec_pic.u;
        src[2]=dec_pic.v;
        stride[0]=dec_pic.stride_y;
        stride[1]=stride[2]=dec_pic.stride_uv;
        video_out->draw_slice(src,stride,
                            sh_video->disp_w,sh_video->disp_h,0,0);
      }
#else
      if(opendivx_src[0]){
        video_out->draw_slice(opendivx_src,opendivx_stride,
                            sh_video->disp_w,sh_video->disp_h,0,0);
        opendivx_src[0]=NULL;
      }
#endif
      t2=GetTimer()-t2;vout_time_usage+=t2*0.000001f;

    break;
  }
#ifdef USE_DIRECTSHOW
  case 4: {        // W32/DirectShow
    unsigned char* start=NULL;
    unsigned int t=GetTimer();
    unsigned int t2;
    int in_size=ds_get_packet(d_video,&start);
    if(in_size<0){ eof=1;break;}
    if(in_size>max_framesize) max_framesize=in_size;

    if(d_video->flags) if(verbose) printf("***keyframe***\n");

    if(drop_frame<2) DS_VideoDecoder_DecodeFrame(start, in_size, 0, !drop_frame);
    current_module="draw_frame";

    if(!drop_frame && sh_video->our_out_buffer){
      t2=GetTimer();t=t2-t;video_time_usage+=t*0.000001f;
      if(out_fmt==IMGFMT_YV12||out_fmt==IMGFMT_IYUV||out_fmt==IMGFMT_I420){
        uint8_t* dst[3];
        int stride[3];
        stride[0]=sh_video->disp_w;
        stride[1]=stride[2]=sh_video->disp_w/2;
        dst[0]=sh_video->our_out_buffer;
        dst[2]=dst[0]+sh_video->disp_w*sh_video->disp_h;
        dst[1]=dst[2]+sh_video->disp_w*sh_video->disp_h/4;
        video_out->draw_slice(dst,stride,sh_video->disp_w,sh_video->disp_h,0,0);
      } else
        video_out->draw_frame((uint8_t **)&sh_video->our_out_buffer);
      t2=GetTimer()-t2;vout_time_usage+=t2*0.000001f;
    }
    break;
  }
#endif
#ifdef USE_LIBAVCODEC
  case 5: {        // libavcodec
    unsigned char* start=NULL;
    unsigned int t=GetTimer();
    unsigned int t2;
    int got_picture=0;
    int in_size=ds_get_packet(d_video,&start);
    if(in_size<0){ eof=1;break;}
    if(in_size>max_framesize) max_framesize=in_size;

    if(d_video->flags) if(verbose) printf("***keyframe***\n");

    if(in_size<=0) blit_frame=0; else
    if(drop_frame<2){
        int ret = avcodec_decode_video(&lavc_context, &lavc_picture,
	     &got_picture, start, in_size);
	if(ret<0) fprintf(stderr, "Error while decoding frame!\n");
    }

    current_module="draw_frame";

    if(!drop_frame && got_picture){
      t2=GetTimer();t=t2-t;video_time_usage+=t*0.000001f;
      video_out->draw_slice(lavc_picture.data,lavc_picture.linesize,sh_video->disp_w,sh_video->disp_h,0,0);
      t2=GetTimer()-t2;vout_time_usage+=t2*0.000001f;
    }
    
    break;
  }
#endif
  case 2: {
    HRESULT ret;
    unsigned char* start=NULL;
    unsigned int t=GetTimer();
    unsigned int t2;
    int in_size=ds_get_packet(d_video,&start);
    if(in_size<0){ eof=1;break;}
    if(in_size>max_framesize) max_framesize=in_size;
    
    if(d_video->flags) if(verbose) printf("***keyframe***\n");
    
    if(in_size){
      sh_video->bih->biSizeImage = in_size;

//      sh_video->bih->biWidth = 1280;
//      sh_video->o_bih.biWidth = 1280;
	    //      ret = ICDecompress(avi_header.hic, ICDECOMPRESS_NOTKEYFRAME|(ICDECOMPRESS_HURRYUP|ICDECOMPRESS_PREROL), 
      ret = ICDecompress(sh_video->hic, 
	  ( (d_video->flags&1) ? 0 : ICDECOMPRESS_NOTKEYFRAME ) |
	  ( (drop_frame==2 && !(d_video->flags&1))?(ICDECOMPRESS_HURRYUP|ICDECOMPRESS_PREROL):0 ) , 
                         sh_video->bih,   start,
                        &sh_video->o_bih,
                        drop_frame ? 0 : sh_video->our_out_buffer);

      if(ret){ printf("Error decompressing frame, err=%d\n",(int)ret);break; }
    }
    current_module="draw_frame";
    if(!drop_frame){
      t2=GetTimer();t=t2-t;video_time_usage+=t*0.000001f;
//      if(out_fmt==IMGFMT_YV12){
      if(out_fmt==IMGFMT_YV12||out_fmt==IMGFMT_IYUV||out_fmt==IMGFMT_I420){
        uint8_t* dst[3];
        int stride[3];
        stride[0]=sh_video->disp_w;
        stride[1]=stride[2]=sh_video->disp_w/2;
        dst[0]=sh_video->our_out_buffer;
        dst[2]=dst[0]+sh_video->disp_w*sh_video->disp_h;
        dst[1]=dst[2]+sh_video->disp_w*sh_video->disp_h/4;
        video_out->draw_slice(dst,stride,sh_video->disp_w,sh_video->disp_h,0,0);
      } else
        video_out->draw_frame((uint8_t **)&sh_video->our_out_buffer);
      t2=GetTimer()-t2;vout_time_usage+=t2*0.000001f;
    }
    break;
  }
  case 1: {
        int in_frame=0;
        int t=0;
        float newfps;
        videobuf_len=0;
        while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
          int i=sync_video_packet(d_video);
          if(in_frame){
            if(i<0x101 || i>=0x1B0){  // not slice code -> end of frame
#if 1
              // send END OF FRAME code:
              videobuffer[videobuf_len+0]=0;
              videobuffer[videobuf_len+1]=0;
              videobuffer[videobuf_len+2]=1;
              videobuffer[videobuf_len+3]=0xFF;
              videobuf_len+=4;
#endif
              if(!i) eof=1; // EOF
              break;
            }
          } else {
            //if(i==0x100) in_frame=1; // picture startcode
            if(i>=0x101 && i<0x1B0) in_frame=1; // picture startcode
            else if(!i){ eof=1; break;} // EOF
          }
	  if(grab_frames==2 && (i==0x1B3 || i==0x1B8)) grab_frames=1;
          if(!read_video_packet(d_video)){ eof=1; break;} // EOF
          //printf("read packet 0x%X, len=%d\n",i,videobuf_len);
        }
        
        if(videobuf_len>max_framesize) max_framesize=videobuf_len; // debug
        //printf("--- SEND %d bytes\n",videobuf_len);
	if(grab_frames==1){
	      FILE *f=fopen("grab.mpg","ab");
	      fwrite(videobuffer,videobuf_len-4,1,f);
	      fclose(f);
	}
        
        t-=GetTimer();
          mpeg2_decode_data(video_out, videobuffer, videobuffer+videobuf_len,drop_frame);
        t+=GetTimer(); video_time_usage+=t*0.000001;

        newfps=frameratecode2framerate[picture->frame_rate_code]*0.0001f;
        if(ABS(sh_video->fps-newfps)>0.01f) if(!force_fps){
            printf("Warning! FPS changed %5.3f -> %5.3f  (%f) [%d]  \n",sh_video->fps,newfps,sh_video->fps-newfps,picture->frame_rate_code);
            sh_video->fps=newfps;
            sh_video->frametime=10000.0f/(float)frameratecode2framerate[picture->frame_rate_code];
        }
        
        frame_time=(100+picture->repeat_count)*0.01f;
        picture->repeat_count=0;

    break;
  }
} // switch
//------------------------ frame decoded. --------------------

    // Increase video timers:
    num_frames+=frame_time;
    frame_time*=sh_video->frametime;
    if(file_format==DEMUXER_TYPE_ASF && !force_fps){
        // .ASF files has no fixed FPS - just frame durations!
        float d=d_video->pts-pts1;
        if(d>=0 && d<5) frame_time=d;
        if(d>0){
          if(verbose)
            if((int)sh_video->fps==1000)
              printf("\rASF framerate: %d fps             \n",(int)(1.0f/d));
          sh_video->frametime=d; // 1ms
          sh_video->fps=1.0f/d;
        }
    }
    v_frame+=frame_time;
    //v_pts+=frame_time;
    time_frame+=frame_time;  // for nosound

    if(file_format==DEMUXER_TYPE_MPEG_PS) d_video->pts+=frame_time;
    
    if(verbose>1) printf("*** ftime=%5.3f ***\n",frame_time);

    if(drop_frame){

      if(has_audio){
          int delay=audio_out->get_delay();
          if(verbose>1)printf("delay=%d\n",delay);
          time_frame=v_frame;
          time_frame-=a_frame-(float)delay/(float)sh_audio->o_bps;
	  if(time_frame>-2*frame_time) {
	    drop_frame=0; // stop dropping frames
	    if (verbose>0) printf("\nstop frame drop %.2f\n", time_frame);
	  }else{
	    ++drop_frame_cnt;
	    if (verbose > 0 && drop_frame_cnt%10 == 0)
	      printf("\nstill dropping, %.2f\n", time_frame);
	  }
      }

    } else {
      // It's time to sleep...
      current_module="sleep";

      time_frame-=GetRelativeTime(); // reset timer

      if(has_audio){
          int delay=audio_out->get_delay();
          if(verbose>1)printf("delay=%d\n",delay);
          time_frame=v_frame;
          time_frame-=a_frame-(float)delay/(float)sh_audio->o_bps;
          // we are out of time... drop next frame!
	  if(time_frame<-2*frame_time){
	      drop_frame=frame_dropping; // tricky!
	      ++drop_frame_cnt;
	      if (verbose>0) printf("\nframe drop %d, %.2f\n", drop_frame, time_frame);
	  }
      } else {
          if( (time_frame<-3*frame_time || time_frame>3*frame_time) || benchmark)
	      time_frame=0;
	  
      }

      if(verbose>1)printf("sleep: %5.3f  a:%6.3f  v:%6.3f  \n",time_frame,a_frame,v_frame);
      
      while(time_frame>0.005){
          if(time_frame<=0.020)
             usec_sleep(10000); // sleeps 1 clock tick (10ms)!
          else
             usec_sleep(1000000*(time_frame-0.002));
          time_frame-=GetRelativeTime();
      }

        current_module="flip_page";
        if(blit_frame) video_out->flip_page();
//        usec_sleep(50000); // test only!

    }

    current_module=NULL;
    
    if(eof) break;
    if(force_redraw){
      --force_redraw;
      if(!force_redraw) osd_function=OSD_PLAY;
      continue;
    }

//    printf("A:%6.1f  V:%6.1f  A-V:%7.3f  frame=%5.2f   \r",d_audio->pts,d_video->pts,d_audio->pts-d_video->pts,a_frame);
//    fflush(stdout);

#if 1
/*================ A-V TIMESTAMP CORRECTION: =========================*/
  if(has_audio){
    float a_pts=0;
    float v_pts=0;

    // unplayed bytes in our and soundcard/dma buffer:
    int delay_bytes=audio_out->get_delay()+sh_audio->a_buffer_len;
    float delay=(float)delay_bytes/(float)sh_audio->o_bps;

    if(pts_from_bps){
      // PTS = (audio position)/(bytes per sec)
//      a_pts=(ds_tell(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
      a_pts=(ds_tell(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->wf->nAvgBytesPerSec;
      delay_corrected=1; // hack
      v_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
      if(verbose)printf("%5.3f|",v_pts-d_video->pts);
    } else {
      if(!delay_corrected && d_audio->pts){
        float x=d_audio->pts-d_video->pts-(delay+audio_delay);
        float y=-(delay+audio_delay);
        printf("Initial PTS delay: %5.3f sec  (calculated: %5.3f)\n",x,y);
	initial_pts_delay+=x;
        audio_delay+=x;
        delay_corrected=1;
        if(verbose)
        printf("v: audio_delay=%5.3f  buffer_delay=%5.3f  a.pts=%5.3f  v.pts=%5.3f\n",
               audio_delay,delay,d_audio->pts,d_video->pts);
      }
      // PTS = (last timestamp) + (bytes after last timestamp)/(bytes per sec)
      a_pts=d_audio->pts;
      a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
      v_pts=d_video->pts-frame_time;
    }

    if(verbose>1)printf("### A:%8.3f (%8.3f)  V:%8.3f  A-V:%7.4f  \n",a_pts,a_pts-audio_delay-delay,v_pts,(a_pts-delay-audio_delay)-v_pts);

    if(frame_corr_num==1){
      float x=frame_correction;
      if(delay_corrected){
//        printf("A:%6.1f  V:%6.1f  A-V:%7.3f",a_pts-audio_delay-delay,v_pts,x);
        printf("A:%6.1f (%6.1f)  V:%6.1f  A-V:%7.3f",a_pts,a_pts-audio_delay-delay,v_pts,x);
        x*=0.1f;
        if(x<-max_pts_correction) x=-max_pts_correction; else
        if(x> max_pts_correction) x= max_pts_correction;
        if(default_max_pts_correction>=0)
          max_pts_correction=default_max_pts_correction;
        else
          max_pts_correction=sh_video->frametime*0.10; // +-10% of time
        a_frame+=x; c_total+=x;
        printf(" ct:%7.3f  %3d  %2d%% %2d%% %4.1f%% %d\r",c_total,
        (int)num_frames,
        (v_frame>0.5)?(int)(100.0*video_time_usage/(double)v_frame):0,
        (v_frame>0.5)?(int)(100.0*vout_time_usage/(double)v_frame):0,
        (v_frame>0.5)?(100.0*audio_time_usage/(double)v_frame):0
        ,drop_frame_cnt
        );
        fflush(stdout);
      }
      frame_corr_num=0; frame_correction=0;
    }
    
    if(frame_corr_num>=0) frame_correction+=(a_pts-delay-audio_delay)-v_pts;
    
  } else {
    // No audio:
    //if(d_video->pts)
    float v_pts=d_video->pts;
    if(frame_corr_num==5){
//      printf("A: ---   V:%6.1f   \r",v_pts);
      printf("V:%6.1f  %3d  %2d%%  %2d%%  %3.1f%% \r",v_pts,
        (int)num_frames,
        (v_frame>0.5)?(int)(100.0*video_time_usage/(double)v_frame):0,
        (v_frame>0.5)?(int)(100.0*vout_time_usage/(double)v_frame):0,
        (v_frame>0.5)?(100.0*audio_time_usage/(double)v_frame):0
        );

      fflush(stdout);
      frame_corr_num=0;
    }
  }
  ++frame_corr_num;
#endif

  if(osd_visible){
    --osd_visible;
    if(!osd_visible) vo_osd_progbar_type=-1; // disable
  }

  if(osd_function==OSD_PAUSE){
      printf("\n------ PAUSED -------\r");fflush(stdout);
      if (audio_out && has_audio)
         audio_out->pause();	// pause audio, keep data if possible
#ifdef HAVE_GUI
      if ( nogui )
        {
#endif
         while(
#ifdef HAVE_LIRC
             lirc_mp_getinput()<=0 &&
#endif
             (!f || getch2(20)<=0) && mplayer_get_key()<=0){
	     video_out->check_events();
             if(!f) usec_sleep(1000); // do not eat the CPU
         }
         osd_function=OSD_PLAY;
#ifdef HAVE_GUI
        } else while( osd_function != OSD_PLAY ) usec_sleep( 1000 );
#endif
      if (audio_out && has_audio)
        audio_out->resume();	// resume audio
  }


    if(!force_redraw) break;
  } //  while(v_frame<a_frame || force_redraw)


//================= Keyboard events, SEEKing ====================

{ int c;
  while(
#ifdef HAVE_LIRC
      (c=lirc_mp_getinput())>0 ||
#endif
      (f && (c=getch2(0))>0) || (c=mplayer_get_key())>0) switch(c){
    // seek 10 sec
    case KEY_RIGHT:
      osd_function=OSD_FFW;
      rel_seek_secs+=10;break;
    case KEY_LEFT:
      osd_function=OSD_REW;
      rel_seek_secs-=10;break;
    // seek 1 min
    case KEY_UP:
      osd_function=OSD_FFW;
      rel_seek_secs+=60;break;
    case KEY_DOWN:
      osd_function=OSD_REW;
      rel_seek_secs-=60;break;
    // seek 10 min
    case KEY_PAGE_UP:
      rel_seek_secs+=600;break;
    case KEY_PAGE_DOWN:
      rel_seek_secs-=600;break;
    // delay correction:
    case '+':
      audio_delay+=0.1;  // increase audio buffer delay
      a_frame-=0.1;
      break;
    case '-':
      audio_delay-=0.1;  // decrease audio buffer delay
      a_frame+=0.1;
      break;
    // quit
    case KEY_ESC: // ESC
    case KEY_ENTER: // ESC
    case 'q': exit_player("Quit");
    case 'g': grab_frames=2;break;
    // pause
    case 'p':
    case ' ':
      osd_function=OSD_PAUSE;
      break;
    case 'o':  // toggle OSD
      osd_level=(osd_level+1)%3;
      break;
    case 'z':
      sub_delay -= 0.1;
      break;
    case 'x':
      sub_delay += 0.1;
      break;
    case '*':
    case '/': {
        float mixer_l, mixer_r;
        mixer_getvolume( &mixer_l,&mixer_r );
        if(c=='*'){
            mixer_l++; if ( mixer_l > 100 ) mixer_l = 100;
            mixer_r++; if ( mixer_r > 100 ) mixer_r = 100;
        } else {
            mixer_l--; if ( mixer_l < 0 ) mixer_l = 0;
            mixer_r--; if ( mixer_r < 0 ) mixer_r = 0;
        }
        mixer_setvolume( mixer_l,mixer_r );

        if(osd_level){
          osd_visible=sh_video->fps; // 1 sec
          vo_osd_progbar_type=OSD_VOLUME;
          vo_osd_progbar_value=(mixer_l+mixer_r)*5/4;
          //printf("volume: %d\n",vo_osd_progbar_value);
        }
      }
      break; 
    case 'm':
      mixer_usemaster=!mixer_usemaster;
      break;
    case 'd':
      frame_dropping=(frame_dropping+1)%3;
      printf("== drop: %d ==  \n",frame_dropping);
      break;
  }
  if (seek_to_sec) {
    int a,b; float d;
    
    if (sscanf(seek_to_sec, "%d:%d:%f", &a,&b,&d)==3)
	rel_seek_secs += 3600*a +60*b +d ;
    else if (sscanf(seek_to_sec, "%d:%f", &a, &d)==2)
	rel_seek_secs += 60*a +d;
    else if (sscanf(seek_to_sec, "%f", &d)==1)
	rel_seek_secs += d;

     seek_to_sec = NULL;
  }
  
  if(rel_seek_secs)
  if(file_format==DEMUXER_TYPE_AVI && demuxer->idx_size<=0){
    printf("Can't seek in raw .AVI streams! (index required, try with the -idx switch!)  \n");
  } else {
    int skip_audio_bytes=0;
    float skip_audio_secs=0;

    // clear demux buffers:
    if(has_audio){ ds_free_packs(d_audio);sh_audio->a_buffer_len=0;}
    ds_free_packs(d_video);
    
//    printf("sh_audio->a_buffer_len=%d  \n",sh_audio->a_buffer_len);
    

switch(file_format){

  case DEMUXER_TYPE_AVI: {
  //================= seek in AVI ==========================
    int rel_seek_frames=rel_seek_secs*sh_video->fps;
    int curr_audio_pos=0;
    int audio_chunk_pos=-1;
    int video_chunk_pos=d_video->pos;
    
      skip_video_frames=0;
      avi_audio_pts=0;

      // find nearest video keyframe chunk pos:
      if(rel_seek_frames>0){
        // seek forward
        while(video_chunk_pos<demuxer->idx_size){
          int id=((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].ckid;
          if(avi_stream_id(id)==d_video->id){  // video frame
            if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
            ++skip_audio_bytes;
          }
          ++video_chunk_pos;
        }
      } else {
        // seek backward
        while(video_chunk_pos>=0){
          int id=((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].ckid;
          if(avi_stream_id(id)==d_video->id){  // video frame
            if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
            --skip_audio_bytes;
          }
          --video_chunk_pos;
        }
      }
      demuxer->idx_pos_a=demuxer->idx_pos_v=demuxer->idx_pos=video_chunk_pos;
//      printf("%d frames skipped\n",skip_audio_bytes);

      // re-calc video pts:
      d_video->pack_no=0;
      for(i=0;i<video_chunk_pos;i++){
          int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid;
          if(avi_stream_id(id)==d_video->id) ++d_video->pack_no;
      }
      num_frames=d_video->pack_no;
      avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;

      if(has_audio){
        int i;
        int apos=0;
        int last=0;
        int len=0;

        // calc new audio position in audio stream: (using avg.bps value)
        curr_audio_pos=(avi_video_pts) * sh_audio->wf->nAvgBytesPerSec;
        if(curr_audio_pos<0)curr_audio_pos=0;
#if 1
        curr_audio_pos&=~15; // requires for PCM formats!!!
#else
        curr_audio_pos/=sh_audio->wf->nBlockAlign;
        curr_audio_pos*=sh_audio->wf->nBlockAlign;
        demuxer->audio_seekable=1;
#endif

        // find audio chunk pos:
          for(i=0;i<video_chunk_pos;i++){
            int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid;
            if(avi_stream_id(id)==d_audio->id){
                len=((AVIINDEXENTRY *)demuxer->idx)[i].dwChunkLength;
                last=i;
                if(apos<=curr_audio_pos && curr_audio_pos<(apos+len)){
                  if(verbose)printf("break;\n");
                  break;
                }
                apos+=len;
            }
          }
          if(verbose)printf("XXX i=%d  last=%d  apos=%d  curr_audio_pos=%d  \n",
           i,last,apos,curr_audio_pos);
//          audio_chunk_pos=last; // maybe wrong (if not break; )
          audio_chunk_pos=i; // maybe wrong (if not break; )
          skip_audio_bytes=curr_audio_pos-apos;

          // update stream position:
          d_audio->pos=audio_chunk_pos;
          d_audio->dpos=apos;
	  d_audio->pts=initial_pts_delay+(float)apos/(float)sh_audio->wf->nAvgBytesPerSec;
          demuxer->idx_pos_a=demuxer->idx_pos_v=demuxer->idx_pos=audio_chunk_pos;

          if(!(sh_audio->codec->flags&CODECS_FLAG_SEEKABLE)){
#if 0
//             curr_audio_pos=apos; // selected audio codec can't seek in chunk
             skip_audio_secs=(float)skip_audio_bytes/(float)sh_audio->wf->nAvgBytesPerSec;
             //printf("Seek_AUDIO: %d bytes --> %5.3f secs\n",skip_audio_bytes,skip_audio_secs);
             skip_audio_bytes=0;
#else
             int d=skip_audio_bytes % sh_audio->wf->nBlockAlign;
             skip_audio_bytes-=d;
//             curr_audio_pos-=d;
             skip_audio_secs=(float)d/(float)sh_audio->wf->nAvgBytesPerSec;
             //printf("Seek_AUDIO: %d bytes --> %5.3f secs\n",d,skip_audio_secs);
#endif
          }
          // now: audio_chunk_pos=pos in index
          //      skip_audio_bytes=bytes to skip from that chunk
          //      skip_audio_secs=time to play audio before video (if can't skip)
          
          // calc skip_video_frames & adjust video pts counter:
//          i=last;
	  for(i=demuxer->idx_pos;i<video_chunk_pos;i++){
            int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid;
            if(avi_stream_id(id)==d_video->id) ++skip_video_frames;
          }
          // requires for correct audio pts calculation (demuxer):
          avi_video_pts-=skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
          
      }

      if(verbose) printf("SEEK: idx=%d  (a:%d v:%d)  v.skip=%d  a.skip=%d/%4.3f  \n",
        demuxer->idx_pos,audio_chunk_pos,video_chunk_pos,
        skip_video_frames,skip_audio_bytes,skip_audio_secs);

  }
  break;

  case DEMUXER_TYPE_ASF: {
  //================= seek in ASF ==========================
    float p_rate=10; // packets / sec
    int rel_seek_packs=rel_seek_secs*p_rate;
    int rel_seek_bytes=rel_seek_packs*asf_packetsize;
    int newpos;
    //printf("ASF: packs: %d  duration: %d  \n",(int)fileh.packets,*((int*)&fileh.duration));
//    printf("ASF_seek: %d secs -> %d packs -> %d bytes  \n",
//       rel_seek_secs,rel_seek_packs,rel_seek_bytes);
    newpos=demuxer->filepos+rel_seek_bytes;
    if(newpos<0 || newpos<demuxer->movi_start) newpos=demuxer->movi_start;
//    printf("\r -- asf: newpos=%d -- \n",newpos);
    stream_seek(demuxer->stream,newpos);

    ds_fill_buffer(d_video);
    if(has_audio) ds_fill_buffer(d_audio);
    
    while(1){
	if(has_audio){
	  // sync audio:
          if (d_video->pts > d_audio->pts){
	      if(!ds_fill_buffer(d_audio)) has_audio=0; // skip audio. EOF?
	      continue;
	  }
	}
	if(d_video->flags&1) break; // found a keyframe!
	if(!ds_fill_buffer(d_video)) break; // skip frame.  EOF?
    }

  }
  break;
  
  case DEMUXER_TYPE_MPEG_ES:
  case DEMUXER_TYPE_MPEG_PS: {
  //================= seek in MPEG ==========================
        int newpos;
        if(picture->bitrate==0x3FFFF) // unspecified?
          newpos=demuxer->filepos+2324*75*rel_seek_secs; // 174.3 kbyte/sec
        else
          newpos=demuxer->filepos+(picture->bitrate*1000/16)*rel_seek_secs;

        if(newpos<seek_to_byte) newpos=seek_to_byte;
        newpos&=~(STREAM_BUFFER_SIZE-1);  /* sector boundary */
        stream_seek(demuxer->stream,newpos);
        // re-sync video:
        videobuf_code_len=0; // reset ES stream buffer
        while(1){
          int i=sync_video_packet(d_video);
          if(i==0x1B3 || i==0x1B8) break; // found it!
          if(!i || !skip_video_packet(d_video)){ eof=1; break;} // EOF
        }
  }
  break;

} // switch(file_format)

        // Set OSD:
      if(osd_level){
        int len=((demuxer->movi_end-demuxer->movi_start)>>8);
        if(len>0){
          osd_visible=sh_video->fps; // 1 sec
          vo_osd_progbar_type=0;
          vo_osd_progbar_value=(demuxer->filepos-demuxer->movi_start)/len;
        }
        //printf("avi filepos = %d  (len=%d)\n",vo_osd_progbar_value,len);
      }

      //====================== re-sync audio: =====================
      if(has_audio){

        if(skip_audio_bytes){
          demux_read_data(d_audio,NULL,skip_audio_bytes);
          //d_audio->pts=0; // PTS is outdated because of the raw data skipping
        }
        
        current_module="resync_audio";

        switch(sh_audio->codec->driver){
        case 1:
          MP3_DecodeFrame(NULL,-2); // resync
          MP3_DecodeFrame(NULL,-2); // resync
          MP3_DecodeFrame(NULL,-2); // resync
          break;
        case 3:
          ac3_bitstream_reset();    // reset AC3 bitstream buffer
    //      if(verbose){ printf("Resyncing AC3 audio...");fflush(stdout);}
          sh_audio->ac3_frame=ac3_decode_frame(); // resync
    //      if(verbose) printf(" OK!\n");
          break;
        case 4:
        case 7:
          sh_audio->a_in_buffer_len=0;        // reset ACM/DShow audio buffer
          break;
        }

        // re-sync PTS (MPEG-PS only!!!)
        if(file_format==DEMUXER_TYPE_MPEG_PS)
        if(d_video->pts && d_audio->pts){
          if (d_video->pts < d_audio->pts){
          
          } else {
            while(d_video->pts > d_audio->pts){
              switch(sh_audio->codec->driver){
                case 1: MP3_DecodeFrame(NULL,-2);break; // skip MPEG frame
                case 3: sh_audio->ac3_frame=ac3_decode_frame();break; // skip AC3 frame
                default: ds_fill_buffer(d_audio);  // skip PCM frame
              }
            }
          }
        }

        current_module=NULL;

        audio_out->reset(); // stop audio, throwing away buffered data

        c_total=0; // kell ez?
        printf("A:%6.1f  V:%6.1f  A-V:%7.3f",d_audio->pts,d_video->pts,0.0f);
        printf("  ct:%7.3f   \r",c_total);fflush(stdout);
      } else {
        printf("A: ---   V:%6.1f   \r",d_video->pts);fflush(stdout);
      }

      max_pts_correction=0.1;
      frame_corr_num=0; // -5
      frame_correction=0;
      force_redraw=5;
      a_frame=-skip_audio_secs;
      v_frame=0; // !!!!!!
      audio_time_usage=0; video_time_usage=0; vout_time_usage=0;
//      num_frames=real_num_frames=0;

  }
 rel_seek_secs=0;
} // keyboard event handler

//================= Update OSD ====================
{ if(osd_level>=2){
      int pts=d_video->pts;
      if(pts==osd_last_pts-1) ++pts; else osd_last_pts=pts;
      vo_osd_text=osd_text_buffer;
      sprintf(vo_osd_text,"%c %02d:%02d:%02d",osd_function,pts/3600,(pts/60)%60,pts%60);
  } else {
      vo_osd_text=NULL;
  }
//  for(i=1;i<=11;i++) osd_text_buffer[10+i]=i;osd_text_buffer[10+i]=0;
//  vo_osd_text=osd_text_buffer;
  
  // find sub
  if(subtitles && d_video->pts>0){
      int pts=d_video->pts;
      if(sub_fps==0) sub_fps=sh_video->fps;
      current_module="find_sub";
      find_sub(subtitles,sub_uses_time?(100*(pts+sub_delay)):((pts+sub_delay)*sub_fps)); // FIXME! frame counter...
      current_module=NULL;
  }
  
  // DVD sub:
  { unsigned char* packet=NULL;
    int len=ds_get_packet_sub(d_dvdsub,&packet);
    if(len>=2){
      int len2;
      len2=(packet[0]<<8)+packet[1];
      if(verbose) printf("\rDVD sub: %d / %d  \n",len,len2);
      if(len==len2)
        spudec_decode(packet,len);
      else
        printf("fragmented dvd-subs not yet supported!!!\n");
    } else if(len>=0) {
      printf("invalud dvd sub\n");
    }
  }
  
}

} // while(!eof)

exit_player("End of file");
}
return 1;
}