changeset 746:cd1f0d4de0b8

new audio playback and A-V sync code
author arpi_esp
date Thu, 10 May 2001 03:39:54 +0000
parents c653430f0789
children cc99cea3c7bd
files DOCS/codecs.conf TOOLS/audio-block2.c configure dec_audio.c demuxer.c demuxer.h dll_init.c mplayer.c stheader.h
diffstat 9 files changed, 249 insertions(+), 102 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/codecs.conf	Wed May 09 23:41:01 2001 +0000
+++ b/DOCS/codecs.conf	Thu May 10 03:39:54 2001 +0000
@@ -88,12 +88,12 @@
 
 videocodec indeo4
   info "Intel Indeo 4.1"
-  status buggy
-  comment "upside-down"
+  status working
+;  comment "upside-down"
   fourcc IV41,iv41
   driver vfw
   dll "ir41_32.dll"
-  out BGR24,BGR15 flip
+  out BGR24,BGR15
 
 videocodec indeo3
   info "Intel Indeo 3.1/3.2"
--- a/TOOLS/audio-block2.c	Wed May 09 23:41:01 2001 +0000
+++ b/TOOLS/audio-block2.c	Thu May 10 03:39:54 2001 +0000
@@ -50,16 +50,18 @@
   }
 
 //  ioctl(audio_fd, SNDCTL_DSP_RESET, NULL);
-//  print_info(audio_fd);
 
-  ioctl(audio_fd, SNDCTL_DSP_RESET, NULL);
+//  ioctl(audio_fd, SNDCTL_DSP_RESET, NULL);
   
   r=AFMT_S16_LE;ioctl (audio_fd, SNDCTL_DSP_SETFMT, &r);
   r=1; ioctl (audio_fd, SNDCTL_DSP_STEREO, &r);
   r=44100; if(ioctl (audio_fd, SNDCTL_DSP_SPEED, &r)==-1)
       printf("audio_setup: your card doesn't support %d Hz samplerate\n",r);
 
-//  print_info(audio_fd);
+  r=0; ioctl (audio_fd, SNDCTL_DSP_GETBLKSIZE, &r);
+  printf("fragment size = %d\n",r);
+
+  print_info(audio_fd);
 
   t0=t1=GetTimer();
 
--- a/configure	Wed May 09 23:41:01 2001 +0000
+++ b/configure	Thu May 10 03:39:54 2001 +0000
@@ -1058,6 +1058,7 @@
 #define XMMP_AUDIO_DRIVER PLUGINDIR "/Sound/oss.so"
 
 /* set up audio OUTBURST. Do not change this! */
+#define MAX_OUTBURST 32768
 #ifdef USE_XMMP_AUDIO
 #define OUTBURST 4096
 #else
--- a/dec_audio.c	Wed May 09 23:41:01 2001 +0000
+++ b/dec_audio.c	Thu May 10 03:39:54 2001 +0000
@@ -52,16 +52,19 @@
 sh_audio->samplerate=0;
 //sh_audio->pcm_bswap=0;
 
-sh_audio->a_buffer_size=16384;  // default size, maybe not enough for Win32/ACM
+sh_audio->a_buffer_size=2*MAX_OUTBURST;  // default size, maybe not enough for Win32/ACM
 sh_audio->a_buffer=NULL;
 
+sh_audio->a_in_buffer_len=0;
+
 if(driver==4){
   // Win32 ACM audio codec:
   if(init_acm_audio_codec(sh_audio)){
+    sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec;
     sh_audio->channels=sh_audio->o_wf.nChannels;
     sh_audio->samplerate=sh_audio->o_wf.nSamplesPerSec;
-    if(sh_audio->a_buffer_size<sh_audio->audio_out_minsize+OUTBURST)
-        sh_audio->a_buffer_size=sh_audio->audio_out_minsize+OUTBURST;
+    if(sh_audio->a_buffer_size<sh_audio->audio_out_minsize+MAX_OUTBURST)
+        sh_audio->a_buffer_size=sh_audio->audio_out_minsize+MAX_OUTBURST;
   } else {
     printf("Could not load/initialize Win32/ACM AUDIO codec (missing DLL file?)\n");
     driver=0;
@@ -80,6 +83,7 @@
     printf("ERROR: Could not load/initialize Win32/DirctShow AUDIO codec: %s\n",sh_audio->codec->dll);
     driver=0;
   } else {
+    sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec;
     sh_audio->channels=sh_audio->wf->nChannels;
     sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
     sh_audio->audio_in_minsize=2*sh_audio->wf->nBlockAlign;
@@ -111,6 +115,7 @@
 case 2: {
     // AVI PCM Audio:
     WAVEFORMATEX *h=sh_audio->wf;
+    sh_audio->i_bps=h->nAvgBytesPerSec;
     sh_audio->channels=h->nChannels;
     sh_audio->samplerate=h->nSamplesPerSec;
     sh_audio->samplesize=(h->wBitsPerSample+7)/8;
@@ -120,6 +125,7 @@
     // DVD PCM Audio:
     sh_audio->channels=2;
     sh_audio->samplerate=48000;
+    sh_audio->i_bps=2*2*48000;
 //    sh_audio->pcm_bswap=1;
     break;
 }
@@ -138,8 +144,12 @@
   ac3_init();
   sh_audio->ac3_frame = ac3_decode_frame();
   if(sh_audio->ac3_frame){
-    sh_audio->samplerate=((ac3_frame_t*)sh_audio->ac3_frame)->sampling_rate;
+    ac3_frame_t* fr=(ac3_frame_t*)sh_audio->ac3_frame;
+    sh_audio->samplerate=fr->sampling_rate;
     sh_audio->channels=2;
+    // 1 frame: 6*256 samples     1 sec: sh_audio->samplerate samples
+    //sh_audio->i_bps=fr->frame_size*fr->sampling_rate/(6*256);
+    sh_audio->i_bps=fr->bit_rate*(1000/8);
   } else {
     driver=0; // bad frame -> disable audio
   }
@@ -150,6 +160,7 @@
   Gen_aLaw_2_Signed(); // init table
   sh_audio->channels=sh_audio->wf->nChannels;
   sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
+  sh_audio->i_bps=sh_audio->channels*sh_audio->samplerate;
   break;
 }
 case 6: {
@@ -157,6 +168,10 @@
   GSM_Init();
   sh_audio->channels=sh_audio->wf->nChannels;
   sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
+  // decodes 65 byte -> 320 short
+  // 1 sec: sh_audio->channels*sh_audio->samplerate  samples
+  // 1 frame: 320 samples
+  sh_audio->i_bps=65*(sh_audio->channels*sh_audio->samplerate)/320;  // 1:10
   break;
 }
 case 1: {
@@ -172,6 +187,7 @@
 //  printf("]\n");
   sh_audio->channels=2; // hack
   sh_audio->samplerate=MP3_samplerate;
+  sh_audio->i_bps=MP3_bitrate*(1000/8);
   break;
 }
 }
@@ -191,9 +207,12 @@
   return driver;
 }
 
-// Audio decoding
+// Audio decoding:
 
-int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int maxlen){
+// Decode a single frame (mp3,acm etc) or 'minlen' bytes (pcm/alaw etc)
+// buffer length is 'maxlen' bytes, it shouldn't be exceeded...
+
+int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){
     int len=-1;
     switch(sh_audio->codec->driver){
       case 1: // MPEG layer 2 or 3
@@ -201,13 +220,14 @@
         sh_audio->channels=2; // hack
         break;
       case 2: // AVI PCM
-      { len=demux_read_data(sh_audio->ds,buf,OUTBURST);
+      { len=demux_read_data(sh_audio->ds,buf,minlen);
         break;
       }
       case 8: // DVD PCM
       { int j;
-        len=demux_read_data(sh_audio->ds,buf,OUTBURST);
+        len=demux_read_data(sh_audio->ds,buf,minlen);
           //if(i&1){ printf("Warning! pcm_audio_size&1 !=0  (%d)\n",i);i&=~1; }
+          // swap endian:
           for(j=0;j<len;j+=2){
             char x=buf[j];
             buf[j]=buf[j+1];
@@ -216,7 +236,7 @@
         break;
       }
       case 5:  // aLaw decoder
-      { int l=demux_read_data(sh_audio->ds,buf,OUTBURST/2);
+      { int l=demux_read_data(sh_audio->ds,buf,minlen/2);
         unsigned short *d=(unsigned short *) buf;
         unsigned char *s=buf;
         len=2*l;
@@ -228,13 +248,10 @@
       }
       case 6:  // MS-GSM decoder
       { unsigned char buf[65]; // 65 bytes / frame
-            len=0;
-            while(len<OUTBURST){
-                if(demux_read_data(sh_audio->ds,buf,65)!=65) break; // EOF
-                XA_MSGSM_Decoder(buf,(unsigned short *) buf); // decodes 65 byte -> 320 short
-//  		XA_GSM_Decoder(buf,(unsigned short *) &sh_audio->a_buffer[sh_audio->a_buffer_len]); // decodes 33 byte -> 160 short
-                len+=2*320;
-            }
+        if(demux_read_data(sh_audio->ds,buf,65)!=65) break; // EOF
+        XA_MSGSM_Decoder(buf,(unsigned short *) buf); // decodes 65 byte -> 320 short
+//  	    XA_GSM_Decoder(buf,(unsigned short *) &sh_audio->a_buffer[sh_audio->a_buffer_len]); // decodes 33 byte -> 160 short
+        len=2*320;
         break;
       }
       case 3: // AC3 decoder
@@ -249,9 +266,10 @@
         //printf("{3:%d}",avi_header.idx_pos);fflush(stdout);
         break;
       case 4:
-      { len=acm_decode_audio(sh_audio,buf,maxlen);
+        len=acm_decode_audio(sh_audio,buf,maxlen);
+//        len=acm_decode_audio(sh_audio,buf,minlen);
         break;
-      }
+
 #ifdef USE_DIRECTSHOW
       case 7: // DirectShow
       { int ret;
@@ -267,7 +285,8 @@
         }
         DS_AudioDecoder_Convert(sh_audio->a_in_buffer,sh_audio->a_in_buffer_len,
             buf,maxlen, &size_in,&size_out);
-        if(verbose>2)printf("DShow: audio %d -> %d converted  (in_buf_len=%d of %d)\n",size_in,size_out,sh_audio->a_in_buffer_len,sh_audio->a_in_buffer_size);
+        //if(verbose>2)
+        printf("DShow: audio %d -> %d converted  (in_buf_len=%d of %d)  %d\n",size_in,size_out,sh_audio->a_in_buffer_len,sh_audio->a_in_buffer_size,ds_tell_pts(sh_audio->ds));
         if(size_in>=sh_audio->a_in_buffer_len){
           sh_audio->a_in_buffer_len=0;
         } else {
--- a/demuxer.c	Wed May 09 23:41:01 2001 +0000
+++ b/demuxer.c	Thu May 10 03:39:54 2001 +0000
@@ -13,6 +13,7 @@
   ds->buffer_pos=ds->buffer_size=0;
   ds->buffer=NULL;
   ds->pts=0;
+  ds->pts_bytes=0;
   ds->eof=0;
   ds->pos=0;
   ds->dpos=0;
@@ -120,7 +121,11 @@
       ds->buffer_size=p->len;
       ds->pos=p->pos;
       ds->dpos+=p->len; // !!!
-      ds->pts=p->pts;
+      if(p->pts){
+        ds->pts=p->pts;
+        ds->pts_bytes=0;
+      }
+      ds->pts_bytes+=p->len; // !!!
       // free packet:
       ds->bytes-=p->len;
       ds->first=p->next;
@@ -164,6 +169,24 @@
 return bytes;
 }
 
+int demux_read_data_pack(demux_stream_t *ds,unsigned char* mem,int len){
+int x;
+int bytes=0;
+while(len>0){
+  x=ds->buffer_size-ds->buffer_pos;
+  if(x==0){
+    if(!ds_fill_buffer(ds)) return bytes;
+  } else {
+    if(x>len) x=len;
+    if(mem) memcpy(mem+bytes,&ds->buffer[ds->buffer_pos],x);
+    bytes+=x;len-=x;ds->buffer_pos+=x;
+    return bytes; // stop at end of package! (for correct timestamping)
+  }
+}
+return bytes;
+}
+
+
 void ds_free_packs(demux_stream_t *ds){
   demux_packet_t *dp=ds->first;
   while(dp){
--- a/demuxer.h	Wed May 09 23:41:01 2001 +0000
+++ b/demuxer.h	Thu May 10 03:39:54 2001 +0000
@@ -29,6 +29,7 @@
   int buffer_size;         // current buffer size
   unsigned char* buffer;   // current buffer
   float pts;               // current buffer's pts
+  int pts_bytes;           // number of bytes read after last pts stamp
   int eof;                 // end of demuxed stream? (true if all buffer empty)
   int pos;                 // position in the input stream (file)
   int dpos;                // position in the demuxed stream
@@ -106,7 +107,12 @@
   return (ds->dpos-ds->buffer_size)+ds->buffer_pos;
 }
 
+inline static int ds_tell_pts(demux_stream_t *ds){
+  return (ds->pts_bytes-ds->buffer_size)+ds->buffer_pos;
+}
+
 int demux_read_data(demux_stream_t *ds,unsigned char* mem,int len);
+int demux_read_data_pack(demux_stream_t *ds,unsigned char* mem,int len);
 
 #if 1
 #define demux_getc(ds) (\
--- a/dll_init.c	Wed May 09 23:41:01 2001 +0000
+++ b/dll_init.c	Thu May 10 03:39:54 2001 +0000
@@ -60,11 +60,12 @@
     if(verbose) printf("Audio codec opened OK! ;-)\n");
 
     acmStreamSize(sh_audio->srcstream, in_fmt->nBlockAlign, &srcsize, ACM_STREAMSIZEF_SOURCE);
-    if(srcsize<OUTBURST) srcsize=OUTBURST;
+    srcsize*=2;
+    if(srcsize<MAX_OUTBURST) srcsize=MAX_OUTBURST;
     sh_audio->audio_out_minsize=srcsize; // audio output min. size
     if(verbose) printf("Audio ACM output buffer min. size: %ld\n",srcsize);
 
-    acmStreamSize(sh_audio->srcstream, 2*srcsize, &srcsize, ACM_STREAMSIZEF_DESTINATION);
+    acmStreamSize(sh_audio->srcstream, srcsize, &srcsize, ACM_STREAMSIZEF_DESTINATION);
     sh_audio->audio_in_minsize=srcsize; // audio input min. size
     if(verbose) printf("Audio ACM input buffer min. size: %ld\n",srcsize);
     
@@ -106,11 +107,12 @@
         }
         hr=acmStreamConvert(sh_audio->srcstream,&ash,0);
         if(hr){
-          printf("ACM_Decoder: acmStreamConvert error %d\n",(int)hr);
+          if(verbose>=2) printf("ACM_Decoder: acmStreamConvert error %d\n",(int)hr);
           
 //					return -1;
         }
-        if(verbose>=3) printf("acm converted %d -> %d\n",ash.cbSrcLengthUsed,ash.cbDstLengthUsed);
+        //if(verbose>=3)
+        printf("acm converted %d -> %d\n",ash.cbSrcLengthUsed,ash.cbDstLengthUsed);
         if(ash.cbSrcLengthUsed>=sh_audio->a_in_buffer_len){
           sh_audio->a_in_buffer_len=0;
         } else {
@@ -138,8 +140,8 @@
   sh_video->o_bih.biSize = sizeof(BITMAPINFOHEADER);
 
   win32_codec_name = sh_video->codec->dll;
-  sh_video->hic = ICOpen( 0x63646976, sh_video->bih->biCompression, ICMODE_FASTDECOMPRESS);
-//  sh_video->hic = ICOpen( 0x63646976, sh_video->bih.biCompression, ICMODE_DECOMPRESS);
+//  sh_video->hic = ICOpen( 0x63646976, sh_video->bih->biCompression, ICMODE_FASTDECOMPRESS);
+  sh_video->hic = ICOpen( 0x63646976, sh_video->bih->biCompression, ICMODE_DECOMPRESS);
   if(!sh_video->hic){
     printf("ICOpen failed! unknown codec / wrong parameters?\n");
     return 0;
@@ -260,19 +262,6 @@
     return 0;
   }
 
-#if 0
-
-//sh_video->hic
-//ICSendMessage(HIC hic,unsigned int msg,long lParam1,long lParam2)
-{ int i;
-  for(i=73;i<256;i++){
-    printf("Calling ICM_USER+%d function...",i);fflush(stdout);
-    ret = ICSendMessage(sh_video->hic,ICM_USER+i,NULL,NULL);
-    printf(" ret=%d\n",ret);
-  }
-}
-#endif
-
   sh_video->our_out_buffer = shmem_alloc(sh_video->o_bih.biSizeImage);
   if(!sh_video->our_out_buffer){
     printf("not enough memory for decoded picture buffer (%ld bytes)\n", sh_video->o_bih.biSizeImage);
--- a/mplayer.c	Wed May 09 23:41:01 2001 +0000
+++ b/mplayer.c	Thu May 10 03:39:54 2001 +0000
@@ -27,7 +27,7 @@
 #include "version.h"
 #include "config.h"
 
-#ifndef OUTBURST
+#ifndef MAX_OUTBURST
 #error "============================================="
 #error "Please re-run ./configure and then try again!"
 #error "============================================="
@@ -254,7 +254,6 @@
   return len;
 }
 
-
 //#include "dec_audio.c"
 
 //**************************************************************************//
@@ -304,6 +303,31 @@
 }
 }
 #endif
+
+//**************************************************************************//
+
+int audio_delay_method=2;
+int audio_buffer_size=-1;
+
+int get_audio_delay(int audio_fd){
+  if(audio_delay_method==2){
+      // 
+      int r=0;
+      if(ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &r)!=-1)
+         return r;
+      audio_delay_method=1; // fallback if not supported
+  }
+  if(audio_delay_method==1){
+      // SNDCTL_DSP_GETOSPACE
+      audio_buf_info zz;
+      if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)!=-1)
+         return audio_buffer_size-zz.bytes;
+      audio_delay_method=0; // fallback if not supported
+  }
+  return audio_buffer_size;
+}
+
+
 //**************************************************************************//
 
 // AVI file header reader/parser/writer:
@@ -401,7 +425,7 @@
 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 maxlen);
+extern int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen);
 
 char* filename=NULL; //"MI2-Trailer.avi";
 int i;
@@ -424,7 +448,6 @@
 #else
 int alsa=0;
 #endif
-int audio_buffer_size=-1;
 int audio_id=-1;
 int video_id=-1;
 int dvdsub_id=-1;
@@ -1031,7 +1054,8 @@
     printf("Couldn't initialize audio codec! -> nosound\n");
     has_audio=0;
   } else {
-    printf("AUDIO: samplerate=%d  channels=%d  bps=%d\n",sh_audio->samplerate,sh_audio->channels,sh_audio->samplesize);
+    printf("AUDIO: samplerate=%d  channels=%d  bps=%d  ratio: %d->%d\n",sh_audio->samplerate,sh_audio->channels,sh_audio->samplesize,
+        sh_audio->i_bps,sh_audio->o_bps);
   }
 }
 
@@ -1282,7 +1306,10 @@
 //================== MAIN: ==========================
 {
 int audio_fd=-1;
-float buffer_delay=0;
+int outburst=OUTBURST;
+float audio_buffer_delay=0;
+
+//float buffer_delay=0;
 float frame_correction=0; // A-V timestamp kulonbseg atlagolas
 int frame_corr_num=0;   //
 float a_frame=0;    // Audio
@@ -1362,24 +1389,38 @@
 #ifdef USE_XMMP_AUDIO
   if(audio_buffer_size==-1){
     // Measuring buffer size:
-    buffer_delay=pSound->QueryDelay(pSound, 0);
+    audio_buffer_delay=pSound->QueryDelay(pSound, 0);
   } else {
     // -abs commandline option
-    buffer_delay=audio_buffer_size/(float)(sh_audio->o_bps);
+    audio_buffer_delay=audio_buffer_size/(float)(sh_audio->o_bps);
   }
 #else
   int r;
+  audio_buf_info zz;
+
   r=(sh_audio->samplesize==2)?AFMT_S16_LE:AFMT_U8;ioctl (audio_fd, SNDCTL_DSP_SETFMT, &r);
   r=sh_audio->channels-1; ioctl (audio_fd, SNDCTL_DSP_STEREO, &r);
-  r=sh_audio->samplerate; if(ioctl (audio_fd, SNDCTL_DSP_SPEED, &r)==-1)
-      printf("audio_setup: your card doesn't support %d Hz samplerate\n",r);
+  r=sh_audio->samplerate; if(ioctl (audio_fd, SNDCTL_DSP_SPEED, &r)==-1){
+      printf("audio_setup: your card doesn't support %d Hz samplerate => nosound\n",r);
+      has_audio=0;
+  } else
+      printf("audio_setup: using %d Hz samplerate (requested: %d)\n",r,sh_audio->samplerate);
 
-#if 0
-//  r = (64 << 16) + 1024;
-  r = (65536 << 16) + 512;
-    if(ioctl (audio_fd, SNDCTL_DSP_SETFRAGMENT, &r)==-1)
-      printf("audio_setup: your card doesn't support setting fragments\n",r);
-#endif
+  if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)==-1){
+      printf("audio_setup: driver doesn't support SNDCTL_DSP_GETOSPACE :-(\n");
+      r=0;
+      if(ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &r)==-1){
+          printf("audio_setup: %d bytes/frag (config.h)\n",outburst);
+      } else {
+          outburst=r;
+          printf("audio_setup: %d bytes/frag (GETBLKSIZE)\n",outburst);
+      }
+  } else {
+      printf("audio_setup: frags: %3d/%d  (%d bytes/frag)  free: %6d\n",
+          zz.fragments, zz.fragstotal, zz.fragsize, zz.bytes);
+      if(audio_buffer_size==-1) audio_buffer_size=zz.bytes;
+      outburst=zz.fragsize;
+  }
 
   if(audio_buffer_size==-1){
     // Measuring buffer size:
@@ -1391,8 +1432,8 @@
       FD_ZERO(&rfds); FD_SET(audio_fd,&rfds);
       tv.tv_sec=0; tv.tv_usec = 0;
       if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) break;
-      write(audio_fd,&sh_audio->a_buffer[sh_audio->a_buffer_len],OUTBURST);
-      audio_buffer_size+=OUTBURST;
+      write(audio_fd,&sh_audio->a_buffer[sh_audio->a_buffer_len],outburst);
+      audio_buffer_size+=outburst;
     }
     if(audio_buffer_size==0){
         printf("\n   ***  Your audio driver DOES NOT support select()  ***\n");
@@ -1401,10 +1442,12 @@
     }
 #endif
   }
-  buffer_delay=audio_buffer_size/(float)(sh_audio->o_bps);
+  audio_buffer_delay=audio_buffer_size/(float)(sh_audio->o_bps);
 #endif
-  a_frame=-(buffer_delay);
-  printf("Audio buffer size: %d bytes, delay: %5.3fs\n",audio_buffer_size,buffer_delay);
+  printf("Audio buffer size: %d bytes, delay: %5.3fs\n",audio_buffer_size,audio_buffer_delay);
+
+//  a_frame=-(audio_buffer_delay);
+  a_frame=0;
 //  RESET_AUDIO(audio_fd);
 }
 
@@ -1428,13 +1471,13 @@
 //==================== START PLAYING =======================
 
 if(file_format==DEMUXER_TYPE_AVI){
-  a_pts=d_audio->pts-(buffer_delay+audio_delay);
+  a_pts=d_audio->pts;
   audio_delay-=(float)(sh_audio->audio.dwInitialFrames-sh_video->video.dwInitialFrames)*sh_video->frametime;
 //  audio_delay-=(float)(sh_audio->audio.dwInitialFrames-sh_video->video.dwInitialFrames)/default_fps;
   if(verbose){
     printf("AVI Initial frame delay: %5.3f\n",(float)(sh_audio->audio.dwInitialFrames-sh_video->video.dwInitialFrames)*sh_video->frametime);
     printf("v: audio_delay=%5.3f  buffer_delay=%5.3f  a_pts=%5.3f  a_frame=%5.3f\n",
-             audio_delay,buffer_delay,a_pts,a_frame);
+             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
@@ -1452,39 +1495,69 @@
 while(!eof){
 
 /*========================== 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=outburst;
+  audio_buf_info zz;
+  int use_select=1;
+  
+  if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)!=-1){
+      // calculate exact buffer space:
+      playsize=zz.fragments*zz.fragsize;
+      if(!playsize) break; // buffer is full, do not block here!!!
+      use_select=0;
+  }
+  
+  if(playsize>MAX_OUTBURST) playsize=MAX_OUTBURST; // we shouldn't exceed it!
+  //if(playsize>outburst) playsize=outburst;
 
   // Update buffer if needed
-  unsigned int t=GetTimer();
+  t=GetTimer();
   current_module="decode_audio";   // Enter AUDIO decoder module
-  //sh_audio->codec->driver=has_audio; // FIXME!
-  while(sh_audio->a_buffer_len<OUTBURST && !d_audio->eof){
-    int ret=decode_audio(sh_audio,&sh_audio->a_buffer[sh_audio->a_buffer_len],sh_audio->a_buffer_size-sh_audio->a_buffer_len);
+  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/=outburst; playsize*=outburst; // rounding to fragment boundary
+  
+//  printf("play %d bytes of %d [max: %d]\n",playsize,sh_audio->a_buffer_len,sh_audio->a_buffer_size);
 
   // Play sound from the buffer:
-  if(sh_audio->a_buffer_len>=OUTBURST){ // if not EOF
+  if(playsize>0){ // if not EOF
 #ifdef USE_XMMP_AUDIO
-    pSound->Write( pSound, sh_audio->a_buffer, OUTBURST );
+    pSound->Write( pSound, sh_audio->a_buffer, playsize );
 #else
 #ifdef SIMULATE_ALSA
-    fake_ALSA_write(audio_fd,sh_audio->a_buffer,OUTBURST); // for testing purposes
+    fake_ALSA_write(audio_fd,sh_audio->a_buffer,playsize); // for testing purposes
 #else
-    write(audio_fd,sh_audio->a_buffer,OUTBURST);
+    playsize=write(audio_fd,sh_audio->a_buffer,playsize);
 #endif
 #endif
-    sh_audio->a_buffer_len-=OUTBURST;
-    memcpy(sh_audio->a_buffer,&sh_audio->a_buffer[OUTBURST],sh_audio->a_buffer_len);
+    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);
+    }
 #ifndef USE_XMMP_AUDIO
 #ifndef SIMULATE_ALSA
     // check buffer
 #ifdef HAVE_AUDIO_SELECT
-    {  fd_set rfds;
+    if(use_select){  // do not use this code if SNDCTL_DSP_GETOSPACE works
+       fd_set rfds;
        struct timeval tv;
        FD_ZERO(&rfds);
        FD_SET(audio_fd, &rfds);
@@ -1492,7 +1565,7 @@
        tv.tv_usec = 0;
        if(select(audio_fd+1, NULL, &rfds, NULL, &tv)){
          a_frame+=OUTBURST/(float)(sh_audio->o_bps);
-         a_pts+=OUTBURST/(float)(sh_audio->o_bps);
+//         a_pts+=OUTBURST/(float)(sh_audio->o_bps);
 //         printf("Filling audio buffer...\n");
          continue;
 //       } else {
@@ -1508,13 +1581,9 @@
 } // if(has_audio)
 
 /*========================== UPDATE TIMERS ============================*/
-
-  a_frame+=OUTBURST/(float)(sh_audio->o_bps);
-  a_pts+=OUTBURST/(float)(sh_audio->o_bps);
-
+#if 0
   if(alsa){
     // Use system timer for sync, not audio card/driver
-    time_frame+=OUTBURST/(float)(sh_audio->o_bps);
     time_frame-=GetRelativeTime();
     if(time_frame<-0.1 || time_frame>0.1){
       time_frame=0;
@@ -1529,19 +1598,19 @@
         }
     }
   }
-
+#endif
 
 /*========================== PLAY VIDEO ============================*/
 
 if(1)
-  while(v_frame<a_frame || force_redraw){
+  while(1){
   
     float frame_time=1;
     float pts1=d_video->pts;
 
     current_module="decode_video";
     
-    if(!force_redraw && v_frame+0.1<a_frame) drop_frame=1; else drop_frame=0;
+//    if(!force_redraw && v_frame+0.1<a_frame) drop_frame=1; else drop_frame=0;
     drop_frame_cnt+=drop_frame;
 
   //--------------------  Decode a frame: -----------------------
@@ -1714,6 +1783,29 @@
     }
     v_frame+=frame_time;
     v_pts+=frame_time;
+    time_frame+=frame_time;  // for nosound
+
+    // It's time to sleep...
+    time_frame-=GetRelativeTime(); // reset timer
+
+    if(has_audio){
+          int delay=get_audio_delay(audio_fd);
+          if(verbose)printf("delay=%d\n",delay);
+          time_frame=v_frame;
+          time_frame-=a_frame-(float)delay/(float)sh_audio->o_bps;
+    } else {
+          if(time_frame<-0.1 || time_frame>0.1) time_frame=0;
+    }
+    
+      if(verbose)printf("sleep: %5.3f  a:%6.3f  v:%6.3f  \n",stime,a_frame,v_frame);
+      
+      while(time_frame>0.005){
+          if(time_frame<=0.020)
+             usleep(0); // sleep 10ms
+          else
+             usleep(1000000*(time_frame-0.002));
+          time_frame-=GetRelativeTime();
+      }
 
     if(!drop_frame){
         current_module="flip_page";
@@ -1726,6 +1818,7 @@
     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);
@@ -1734,34 +1827,45 @@
 #if 1
 /*================ A-V TIMESTAMP CORRECTION: =========================*/
   if(has_audio){
+    // unplayed bytes in our and soundcard/dma buffer:
+    int delay_bytes=get_audio_delay(audio_fd)+sh_audio->a_buffer_len;
+    float delay=(float)delay_bytes/(float)sh_audio->o_bps;
+
     if(pts_from_bps && (file_format==DEMUXER_TYPE_AVI)){
 //      a_pts=(float)ds_tell(d_audio)/sh_audio->wf.nAvgBytesPerSec-(buffer_delay+audio_delay);
-      a_pts=(float)ds_tell(d_audio)/sh_audio->wf->nAvgBytesPerSec-(buffer_delay);
+      a_pts=(float)ds_tell(d_audio)/sh_audio->wf->nAvgBytesPerSec;
       delay_corrected=1; // hack
     } else
     if(d_audio->pts){
 //      printf("\n=== APTS  a_pts=%5.3f  v_pts=%5.3f ===  \n",d_audio->pts,d_video->pts);
 #if 1
       if(!delay_corrected){
-        float x=d_audio->pts-d_video->pts-(buffer_delay+audio_delay);
-        float y=-(buffer_delay+audio_delay);
+        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);
         audio_delay+=x;
         //a_pts-=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,buffer_delay,d_audio->pts,d_video->pts);
+               audio_delay,delay,d_audio->pts,d_video->pts);
       }
 #endif
-      a_pts=d_audio->pts-(buffer_delay+audio_delay);
-      d_audio->pts=0;
+//      a_pts=(ds_tell_pts(d_audio)+sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+//      printf("a_pts+=%6.3f    \n",a_pts);
+//      a_pts=d_audio->pts-a_pts;
+
+      a_pts=d_audio->pts;
+      a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+
+      //a_pts=d_audio->pts; d_audio->pts=0;
     }
     if(d_video->pts) v_pts=d_video->pts;
     if(frame_corr_num==5){
       float x=(frame_correction/5.0f);
       if(delay_corrected){
-        printf("A:%6.1f  V:%6.1f  A-V:%7.3f",a_pts,v_pts,x);
+//        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.5f;
         if(x<-max_pts_correction) x=-max_pts_correction; else
         if(x> max_pts_correction) x= max_pts_correction;
@@ -1779,7 +1883,7 @@
       }
       frame_corr_num=0; frame_correction=0;
     }
-    if(frame_corr_num>=0) frame_correction+=a_pts-v_pts;
+    if(frame_corr_num>=0) frame_correction+=(a_pts-delay-audio_delay)-v_pts;
   } else {
     // No audio:
     if(d_video->pts) v_pts=d_video->pts;
@@ -1825,6 +1929,8 @@
 #endif
   }
 
+
+    if(!force_redraw) break;
   } //  while(v_frame<a_frame || force_redraw)
 
 
@@ -1857,11 +1963,11 @@
       rel_seek_secs-=600;break;
     // delay correction:
     case '+':
-      buffer_delay+=0.1;  // increase audio buffer delay
+      audio_delay+=0.1;  // increase audio buffer delay
       a_frame-=0.1;
       break;
     case '-':
-      buffer_delay-=0.1;  // decrease audio buffer delay
+      audio_delay-=0.1;  // decrease audio buffer delay
       a_frame+=0.1;
       break;
     // quit
@@ -1986,7 +2092,7 @@
 #else
       avi_video_pts=v_pts;
 #endif
-      a_pts=avi_video_pts-(buffer_delay);
+      a_pts=avi_video_pts;
       //a_pts=v_pts; //-(buffer_delay+audio_delay);
 
       if(has_audio){
@@ -2189,7 +2295,7 @@
       max_pts_correction=0.1;
       frame_corr_num=-5; frame_correction=0;
       force_redraw=5;
-      a_frame=-buffer_delay-skip_audio_secs;
+      a_frame=-skip_audio_secs;
 //      a_frame=-audio_delay-buffer_delay-skip_audio_secs;
       v_frame=0; // !!!!!!
       audio_time_usage=0; video_time_usage=0; vout_time_usage=0;
--- a/stheader.h	Wed May 09 23:41:01 2001 +0000
+++ b/stheader.h	Thu May 10 03:39:54 2001 +0000
@@ -15,7 +15,8 @@
   int samplerate;
   int samplesize;
   int channels;
-  int o_bps; // == samplerate*samplesize*channels
+  int o_bps; // == samplerate*samplesize*channels   (uncompr. bytes/sec)
+  int i_bps; // == bitrate  (compressed bytes/sec)
   // in buffers:
   char* a_in_buffer;
   int a_in_buffer_len;