Don't disallow loading a subtitle in Win32 GUI when playback is stopped.
[mplayer.git] / mencoder.c
index eaa13d2..9fc3ebe 100644 (file)
@@ -50,6 +50,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <sys/time.h>
 #if defined(__MINGW32__) || defined(__CYGWIN__)
 #include <windows.h>
@@ -58,7 +59,6 @@
 #include "input/input.h"
 #include "libaf/af_format.h"
 #include "libao2/audio_out.h"
-#include "libass/ass_mp.h"
 #include "libavcodec/avcodec.h"
 #include "libmpcodecs/ae.h"
 #include "libmpcodecs/dec_audio.h"
 #include "libmpdemux/muxer.h"
 #include "libmpdemux/stheader.h"
 #include "libvo/fastmemcpy.h"
-#include "libvo/font_load.h"
-#include "libvo/sub.h"
+#include "sub/font_load.h"
+#include "sub/sub.h"
 #include "libvo/video_out.h"
-#include "osdep/priority.h"
 #include "osdep/timer.h"
 #include "stream/stream.h"
 #include "stream/stream_bd.h"
@@ -84,6 +83,7 @@
 #include "stream/stream_dvd.h"
 #endif
 #include "stream/stream_dvdnav.h"
+#include "sub/ass_mp.h"
 #include "codec-cfg.h"
 #include "edl.h"
 #include "help_mp.h"
 #include "parser-cfg.h"
 #include "parser-mecmd.h"
 #include "path.h"
-#include "spudec.h"
-#include "vobsub.h"
+#include "sub/spudec.h"
+#include "sub/vobsub.h"
+#include "sub/eosd.h"
+#include "mencoder.h"
 
 
 int vo_doublebuffering=0;
 int vo_directrendering=0;
 int vo_config_count=1;
-int forced_subs_only=0;
 
 //--------------------------
 
 // cache2:
 int stream_cache_size=-1;
 #ifdef CONFIG_STREAM_CACHE
-extern int cache_fill_status;
-
 float stream_cache_min_percent=20.0;
 float stream_cache_seek_min_percent=50.0;
-#else
-#define cache_fill_status 0
 #endif
 
 int audio_id=-1;
@@ -123,15 +120,11 @@ int dvdsub_id=-1;
 int vobsub_id=-1;
 char* audio_lang=NULL;
 char* dvdsub_lang=NULL;
-static char* spudec_ifo=NULL;
 
 static char** audio_codec_list=NULL;  // override audio codec
 static char** video_codec_list=NULL;  // override video codec
 static char** audio_fm_list=NULL;     // override audio codec family
 static char** video_fm_list=NULL;     // override video codec family
-extern char *demuxer_name; // override demuxer
-extern char *audio_demuxer_name; // override audio demuxer
-extern char *sub_demuxer_name; // override sub demuxer
 
 static int out_audio_codec=-1;
 static int out_video_codec=-1;
@@ -147,7 +140,6 @@ double cur_vout_time_usage=0;
 int benchmark=0;
 
 // A-V sync:
-int delay_corrected=1;
 static float default_max_pts_correction=-1;//0.01f;
 static float max_pts_correction=0;//default_max_pts_correction;
 static float c_total=0;
@@ -164,7 +156,7 @@ static int skip_limit=-1;
 float playback_speed=1.0;
 
 static int force_srate=0;
-static int audio_output_format=0;
+static int audio_output_format=AF_FORMAT_UNKNOWN;
 
 char *vobsub_out=NULL;
 unsigned int vobsub_out_index=0;
@@ -183,12 +175,13 @@ static int play_n_frames_mf=-1;
 // sub:
 char *font_name=NULL;
 char *sub_font_name=NULL;
-extern int font_fontconfig;
 float font_factor=0.75;
 char **sub_name=NULL;
+char **sub_paths = NULL;
 float sub_delay=0;
 float sub_fps=0;
 int   sub_auto = 0;
+char *vobsub_name = NULL;
 int   subcc_enabled=0;
 int   suboverlap_enabled = 1;
 
@@ -228,16 +221,6 @@ void set_osd_subtitle(subtitle *subs) {
     vo_osd_changed(OSDTYPE_SUBTITLE);
 }
 
-//-------------------------- config stuff:
-
-m_config_t* mconfig;
-
-static int cfg_inc_verbose(m_option_t *conf){ ++verbose; return 0;}
-
-static int cfg_include(m_option_t *conf, char *filename){
-       return m_config_parse_config_file(mconfig, filename);
-}
-
 static double seek_to_sec;
 static off_t seek_to_byte=0;
 
@@ -250,13 +233,14 @@ typedef struct {
     int in_size;
     float frame_time;
     int already_read;
+    int flush;
 } s_frame_data;
 
 static edl_record_ptr edl_records = NULL; ///< EDL entries memory area
 static edl_record_ptr next_edl_record = NULL; ///< only for traversing edl_records
 static short edl_muted; ///< Stores whether EDL is currently in muted mode.
 static short edl_seeking; ///< When non-zero, stream is seekable.
-static short edl_seek_type; ///< When non-zero, frames are discarded instead of seeking.
+static int edl_seek_type; ///< When non-zero, frames are discarded instead of seeking.
 
 /* This header requires all the global variable declarations. */
 #include "cfg-mencoder.h"
@@ -277,14 +261,14 @@ static void parse_cfgfiles( m_config_t* conf )
 {
   char *conffile;
   if (!disable_system_conf &&
-      m_config_parse_config_file(conf, MPLAYER_CONFDIR "/mencoder.conf") < 0)
+      m_config_parse_config_file(conf, MPLAYER_CONFDIR "/mencoder.conf", 1) < 0)
     mencoder_exit(1,MSGTR_ConfigFileError);
 
   if (!disable_user_conf) {
     if ((conffile = get_path("mencoder.conf")) == NULL) {
       mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_GetpathProblem);
     } else {
-      if (m_config_parse_config_file(conf, conffile) < 0)
+      if (m_config_parse_config_file(conf, conffile, 1) < 0)
         mencoder_exit(1,MSGTR_ConfigFileError);
       free(conffile);
     }
@@ -298,14 +282,20 @@ static int dec_audio(sh_audio_t *sh_audio,unsigned char* buffer,int total){
     int size=0;
     int at_eof=0;
     while(size<total && !at_eof){
+       int res;
        int len=total-size;
                if(len>MAX_OUTBURST) len=MAX_OUTBURST;
-               if (decode_audio(sh_audio, len) < 0) at_eof=1;
+               res = mp_decode_audio(sh_audio, len);
+               if (res == -2)
+                   mp_msg(MSGT_MENCODER, MSGL_FATAL, "Audio format change detected!\n"
+                          "MEncoder currently cannot handle format changes - patches welcome!\n");
+               if (res < 0)
+                    at_eof = 1;
                if(len>sh_audio->a_out_buffer_len) len=sh_audio->a_out_buffer_len;
                fast_memcpy(buffer+size,sh_audio->a_out_buffer,len);
                sh_audio->a_out_buffer_len-=len; size+=len;
                if(sh_audio->a_out_buffer_len>0)
-                   fast_memcpy(sh_audio->a_out_buffer,&sh_audio->a_out_buffer[len],sh_audio->a_out_buffer_len);
+                   memmove(sh_audio->a_out_buffer,&sh_audio->a_out_buffer[len],sh_audio->a_out_buffer_len);
     }
     return size;
 }
@@ -316,7 +306,7 @@ static volatile int at_eof=0;
 static volatile int interrupted=0;
 
 static void exit_sighandler(int x){
-    at_eof=1;
+    at_eof=3;
     interrupted=2; /* 1 means error */
 }
 
@@ -360,15 +350,30 @@ static void add_subtitles(char *filename, float fps, int silent)
     subdata = subd;
 }
 
+/* Provide a timer value suitable for use in A/V sync calculations.
+ * mux->timer records the current position of the muxer stream.
+ * mux->encoder_delay is how many frames are currently buffered by the
+ * encoder. To mencoder core, encoder-buffered frames have been "dealt with"--
+ * they'll get to the muxer eventually. So, for the purposes of A/V sync,
+ * we need to add the total time length of buffered frames to the muxer stream
+ * position. */
+static double adjusted_muxer_time(muxer_stream_t *mux)
+{
+    if (! mux) return MP_NOPTS_VALUE;
+    return mux->timer + (double) mux->encoder_delay * mux->h.dwScale/mux->h.dwRate;
+}
+
 /* This function returns the absolute time for which MEncoder will switch files
  * or move in the file so audio can be cut correctly. -1 if there is no limit. */
 static float stop_time(demuxer_t* demuxer, muxer_stream_t* mux_v)
 {
        float timeleft = -1;
-       if (play_n_frames >= 0) timeleft = mux_v->timer + play_n_frames * (double)(mux_v->h.dwScale) / mux_v->h.dwRate;
-       if (end_at.type == END_AT_TIME && (timeleft > end_at.pos || timeleft == -1)) timeleft = end_at.pos;
+       if (play_n_frames >= 0)
+               timeleft = adjusted_muxer_time(mux_v) + play_n_frames * (double)(mux_v->h.dwScale) / mux_v->h.dwRate;
+       if (end_at.type == END_AT_TIME && (timeleft > end_at.pos || timeleft == -1))
+               timeleft = end_at.pos;
        if (next_edl_record && demuxer && demuxer->video) { // everything is OK to be checked
-               float tmp = mux_v->timer + next_edl_record->start_sec - demuxer->video->pts;
+               float tmp = adjusted_muxer_time(mux_v) + next_edl_record->start_sec - demuxer->video->pts;
                if (timeleft == -1 || timeleft > tmp) {
                        // There's less time in EDL than what we already know
                        if (next_edl_record->action == EDL_SKIP && edl_seeking) {
@@ -382,23 +387,13 @@ static float stop_time(demuxer_t* demuxer, muxer_stream_t* mux_v)
        return timeleft;
 }
 
-/// Returns a_pts
-static float calc_a_pts(demux_stream_t *d_audio)
-{
-    sh_audio_t * sh_audio = d_audio ? d_audio->sh : NULL;
-    float a_pts = 0.;
-    if (sh_audio)
-        a_pts = d_audio->pts + (ds_tell_pts(d_audio) - sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
-    return a_pts;
-}
-
 /** \brief Seeks audio forward to pts by dumping audio packets
  *  \return The current audio pts. */
 static float forward_audio(float pts, demux_stream_t *d_audio, muxer_stream_t* mux_a)
 {
     sh_audio_t * sh_audio = d_audio ? d_audio->sh : NULL;
     int samplesize, avg;
-    float a_pts = calc_a_pts(d_audio);
+    float a_pts = calc_a_pts(sh_audio, d_audio);
 
     if (!sh_audio) return a_pts;
 
@@ -410,7 +405,7 @@ static float forward_audio(float pts, demux_stream_t *d_audio, muxer_stream_t* m
     // carefully checking if a_pts is truely correct by reading tiniest amount of data possible.
     if (pts > a_pts && a_pts == 0.0 && samplesize) {
         if (demux_read_data(sh_audio->ds,mux_a->buffer,samplesize) <= 0) return a_pts; // EOF
-        a_pts = calc_a_pts(d_audio);
+        a_pts = calc_a_pts(sh_audio, d_audio);
     }
 
     while (pts > a_pts) {
@@ -425,7 +420,7 @@ static float forward_audio(float pts, demux_stream_t *d_audio, muxer_stream_t* m
             len = ds_get_packet(sh_audio->ds, &crap);
         }
         if (len <= 0) break; // EOF of audio.
-        a_pts = calc_a_pts(d_audio);
+        a_pts = calc_a_pts(sh_audio, d_audio);
     }
     return a_pts;
 }
@@ -445,6 +440,11 @@ static int slowseek(float end_pts, demux_stream_t *d_video,
 
         if (!frame_data->already_read) { // when called after fixdelay, a frame is already read
             frame_data->in_size = video_read_frame(sh_video, &frame_data->frame_time, &frame_data->start, force_fps);
+            frame_data->flush = frame_data->in_size < 0 && d_video->eof;
+            if (frame_data->flush) {
+                frame_data->in_size = 0;
+                frame_data->start = NULL;
+            }
             if(frame_data->in_size<0) return 2;
             sh_video->timer += frame_data->frame_time;
         }
@@ -463,9 +463,11 @@ static int slowseek(float end_pts, demux_stream_t *d_video,
 
         if (vfilter) {
             int softskip = (vfilter->control(vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) == CONTROL_TRUE);
-            void *decoded_frame = decode_video(sh_video, frame_data->start, frame_data->in_size, !softskip, MP_NOPTS_VALUE);
+            void *decoded_frame = decode_video(sh_video, frame_data->start, frame_data->in_size, !softskip, MP_NOPTS_VALUE, MP_NOPTS_VALUE, NULL);
            if (decoded_frame)
-               filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE);
+               filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
+           else if (frame_data->flush)
+               return 2;
         }
 
         if (print_info) mp_msg(MSGT_MENCODER, MSGL_STATUS,
@@ -558,11 +560,15 @@ uint32_t duplicatedframes=0;
 uint32_t badframes=0;
 
 muxer_stream_t* mux_a=NULL;
+// For correct deallocation
+unsigned char *mux_v_buffer = NULL;
 muxer_stream_t* mux_v=NULL;
 off_t muxer_f_size=0;
 
 double v_pts_corr=0;
 double v_timer_corr=0;
+double sub_offset=0;
+int did_seek=0;
 
 m_entry_t* filelist = NULL;
 char* filename=NULL;
@@ -580,7 +586,7 @@ audio_encoder_t *aencoder = NULL;
 
 user_correct_pts = 0;
 
-  mp_msg_init();
+  common_preinit(&argc, &argv);
 
   // Create the config context and register the options
   mconfig = m_config_new();
@@ -592,27 +598,11 @@ user_correct_pts = 0;
 
   print_version("MEncoder");
 
-#if (defined(__MINGW32__) || defined(__CYGWIN__)) && defined(CONFIG_WIN32DLL)
-  set_path_env();
-#endif
-
-  InitTimer();
-
-// check codec.conf
-if(!codecs_file || !parse_codec_cfg(codecs_file)){
-  if(!parse_codec_cfg(get_path("codecs.conf"))){
-    if(!parse_codec_cfg(MPLAYER_CONFDIR "/codecs.conf")){
-      if(!parse_codec_cfg(NULL)){
-       mencoder_exit(1,NULL);
-      }
-      mp_msg(MSGT_MENCODER,MSGL_V,MSGTR_BuiltinCodecsConf);
-    }
-  }
-}
-
  parse_cfgfiles(mconfig);
  filelist = m_config_parse_me_command_line(mconfig, argc, argv);
  if(!filelist) mencoder_exit(1, MSGTR_ErrorParsingCommandLine);
+ if (!common_init())
+   mencoder_exit(1,NULL);
 
 {
        char *extension;
@@ -652,38 +642,6 @@ if (frameno_filename) {
   }
 }
 
-#ifdef CONFIG_PRIORITY
-  set_priority();
-#endif
-
-  if (codec_path)
-    set_codec_path(codec_path);
-
-// check font
-#ifdef CONFIG_FREETYPE
-  init_freetype();
-#endif
-#ifdef CONFIG_FONTCONFIG
-  if(font_fontconfig <= 0)
-  {
-#endif
-#ifdef CONFIG_BITMAP_FONT
-  if(font_name){
-       vo_font=read_font_desc(font_name,font_factor,verbose>1);
-       if(!vo_font) mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CantLoadFont,font_name);
-  } else {
-      // try default:
-       vo_font=read_font_desc(get_path("font/font.desc"),font_factor,verbose>1);
-       if(!vo_font)
-         vo_font=read_font_desc(MPLAYER_DATADIR "/font/font.desc",font_factor,verbose>1);
-  }
-#endif
-#ifdef CONFIG_FONTCONFIG
-  }
-#endif
-
-  vo_init_osd();
-
   /* HACK, for some weird reason, push() has to be called twice,
      otherwise options are not saved correctly */
   m_config_push(mconfig);
@@ -692,14 +650,20 @@ play_next_file:
   m_entry_set_options(mconfig,&filelist[curfile]);
   filename = filelist[curfile].name;
 
-#ifdef CONFIG_ASS
-  ass_library = ass_init();
-#endif
-
   if(!filename){
        mp_msg(MSGT_CPLAYER, MSGL_FATAL, MSGTR_MissingFilename);
        mencoder_exit(1,NULL);
   }
+
+  if (vobsub_name)
+    vo_vobsub = vobsub_open(vobsub_name, spudec_ifo, 1, &vo_spudec);
+#ifdef CONFIG_ASS
+  // must be before demuxer open, since the settings are
+  // used in generating the ASSTrack
+  if (ass_enabled && ass_library)
+    ass_mp_reset_config(ass_library);
+#endif
+
   stream=open_stream(filename,0,&file_format);
 
   if(!stream){
@@ -714,6 +678,13 @@ if(stream->type==STREAMTYPE_BD){
   if(dvdsub_lang && dvdsub_id==-1) dvdsub_id=bd_sid_from_lang(stream,dvdsub_lang);
 }
 
+#ifdef CONFIG_LIBBLURAY
+if(stream->type==STREAMTYPE_BLURAY){
+  if(audio_lang && audio_id==-1) audio_id=bluray_id_from_lang(stream,stream_ctrl_audio,audio_lang);
+  if(dvdsub_lang && dvdsub_id==-1) dvdsub_id=bluray_id_from_lang(stream,stream_ctrl_sub,dvdsub_lang);
+}
+#endif
+
 #ifdef CONFIG_DVDREAD
 if(stream->type==STREAMTYPE_DVD){
   if(audio_lang && audio_id==-1) audio_id=dvd_aid_from_lang(stream,audio_lang);
@@ -730,7 +701,7 @@ if(stream->type==STREAMTYPE_DVDNAV){
 
   stream->start_pos+=seek_to_byte;
 
-  if(stream_cache_size>0) stream_enable_cache(stream,stream_cache_size*1024,0,0);
+  if(stream_cache_size>0) stream_enable_cache(stream,stream_cache_size*1024ull,0,0);
 
   if(demuxer2) audio_id=-2; /* do NOT read audio packets... */
 
@@ -745,10 +716,10 @@ if(stream->type==STREAMTYPE_DVDNAV){
     demux_program_t prog = { .progid = ts_prog };
     if (demux_control(demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM, &prog) != DEMUXER_CTRL_NOTIMPL) {
       audio_id = prog.aid; // switching is handled by select_audio below
-      video_id = prog.vid;
-      demuxer_switch_video(demuxer, video_id);
+      video_id = prog.vid; // switching is handled by select_video below
     }
   }
+  select_video(demuxer, video_id);
   select_audio(demuxer, audio_id, audio_lang);
 
   if (dvdsub_id == -1 && dvdsub_lang)
@@ -860,20 +831,8 @@ if (vobsub_out) {
     }
 #endif
 }
-else {
-if (spudec_ifo) {
-  unsigned int palette[16], width, height;
-  if (vobsub_parse_ifo(NULL,spudec_ifo, palette, &width, &height, 1, -1, NULL) >= 0)
-    vo_spudec=spudec_new_scaled(palette, sh_video->disp_w, sh_video->disp_h, NULL, 0);
-}
-#ifdef CONFIG_DVDREAD
-if (vo_spudec==NULL) {
-vo_spudec=spudec_new_scaled(stream->type==STREAMTYPE_DVD?((dvd_priv_t *)(stream->priv))->cur_pgc->palette:NULL,
-                           sh_video->disp_w, sh_video->disp_h, NULL, 0);
-}
-#endif
-if (vo_spudec)
-  spudec_set_forced_subs_only(vo_spudec, forced_subs_only);
+else if (!vo_spudec) {
+init_vo_spudec(stream, sh_video, d_dvdsub ? d_dvdsub->sh : NULL);
 }
 
 ostream = open_output_stream(out_filename, 0);
@@ -898,13 +857,13 @@ muxer->audio_delay_fix = audio_delay_fix;
 
 mux_v=muxer_new_stream(muxer,MUXER_TYPE_VIDEO);
 
-mux_v->buffer_size=0x200000; // 2MB
-mux_v->buffer=malloc(mux_v->buffer_size);
+mux_v->buffer_size=0x800000; // 8MB
+mux_v->buffer=mux_v_buffer=malloc(mux_v->buffer_size);
 
 mux_v->source=sh_video;
 
 mux_v->h.dwSampleSize=0; // VBR
-#ifdef CONFIG_LIBAVCODEC
+#ifdef CONFIG_FFMPEG
 {
     double fps = force_ofps?force_ofps:sh_video->fps*playback_speed;
     AVRational q= av_d2q(fps, fps*1001+2);
@@ -932,8 +891,8 @@ case VCODEC_COPY:
                }
     else
     {
-       mux_v->bih=calloc(1,sizeof(BITMAPINFOHEADER));
-       mux_v->bih->biSize=sizeof(BITMAPINFOHEADER);
+       mux_v->bih=calloc(1,sizeof(*mux_v->bih));
+       mux_v->bih->biSize=sizeof(*mux_v->bih);
        mux_v->bih->biWidth=sh_video->disp_w;
        mux_v->bih->biHeight=sh_video->disp_h;
        mux_v->bih->biCompression=sh_video->format;
@@ -972,8 +931,8 @@ case VCODEC_COPY:
     break;
 case VCODEC_FRAMENO:
        if (!curfile) {
-    mux_v->bih=calloc(1,sizeof(BITMAPINFOHEADER));
-    mux_v->bih->biSize=sizeof(BITMAPINFOHEADER);
+    mux_v->bih=calloc(1,sizeof(*mux_v->bih));
+    mux_v->bih->biSize=sizeof(*mux_v->bih);
     mux_v->bih->biWidth=sh_video->disp_w;
     mux_v->bih->biHeight=sh_video->disp_h;
     mux_v->bih->biPlanes=1;
@@ -1051,33 +1010,18 @@ default: {
   }
 #endif
 
-    sh_video->vfilter=append_filters(sh_video->vfilter);
+  sh_video->vfilter=append_filters(sh_video->vfilter);
+  eosd_init(sh_video->vfilter);
 
 #ifdef CONFIG_ASS
   if (ass_enabled)
-    ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_INIT_EOSD, ass_library);
+    eosd_ass_init(ass_library);
 #endif
 
 // after reading video params we should load subtitles because
 // we know fps so now we can adjust subtitles time to ~6 seconds AST
 // check .sub
-  if(sub_name && sub_name[0]){
-    for (i = 0; sub_name[i] != NULL; ++i)
-        add_subtitles (sub_name[i], sh_video->fps, 0);
-  } else
-  if(sub_auto && filename) { // auto load sub file ...
-    char **tmp = NULL;
-    int i = 0;
-    char *psub = get_path( "sub/" );
-    tmp = sub_filenames((psub ? psub : ""), filename);
-    free(psub);
-    while (tmp[i])
-    {
-      add_subtitles (tmp[i], sh_video->fps, 0);
-      free(tmp[i++]);
-    }
-    free(tmp);
-  }
+    load_subtitles(filename, sh_video->fps, add_subtitles);
 
     mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
     init_best_video_codec(sh_video,video_codec_list,video_fm_list);
@@ -1138,6 +1082,7 @@ if(!init_audio_filters(sh_audio,
 
 aparams.channels = ao_data.channels;
 aparams.sample_rate = ao_data.samplerate;
+aparams.sample_format = ao_data.format;
 aparams.audio_preload = 1000 * audio_preload;
 if(mux_a->codec != ACODEC_COPY) {
     aencoder = new_audio_encoder(mux_a, &aparams);
@@ -1149,6 +1094,9 @@ if(mux_a->codec != ACODEC_COPY) {
       mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_NoMatchingFilter);
       mencoder_exit(1,NULL);
     }
+    ao_data.format = aencoder->input_format;
+    ao_data.channels = aparams.channels;
+    ao_data.samplerate = aparams.sample_rate;
 }
 switch(mux_a->codec){
 case ACODEC_COPY:
@@ -1158,11 +1106,11 @@ case ACODEC_COPY:
        mencoder_exit(1,NULL);
     }
     if (sh_audio->wf){
-       mux_a->wf=malloc(sizeof(WAVEFORMATEX) + sh_audio->wf->cbSize);
-       memcpy(mux_a->wf, sh_audio->wf, sizeof(WAVEFORMATEX) + sh_audio->wf->cbSize);
+       mux_a->wf=malloc(sizeof(*mux_a->wf) + sh_audio->wf->cbSize);
+       memcpy(mux_a->wf, sh_audio->wf, sizeof(*mux_a->wf) + sh_audio->wf->cbSize);
        if(!sh_audio->i_bps) sh_audio->i_bps=mux_a->wf->nAvgBytesPerSec;
     } else {
-       mux_a->wf = malloc(sizeof(WAVEFORMATEX));
+       mux_a->wf = malloc(sizeof(*mux_a->wf));
        mux_a->wf->nBlockAlign = 1; //mux_a->h.dwSampleSize;
        mux_a->wf->wFormatTag = sh_audio->format;
        mux_a->wf->nChannels = sh_audio->channels;
@@ -1282,7 +1230,7 @@ if(file_format == DEMUXER_TYPE_TV)
        }
 
 play_n_frames=play_n_frames_mf;
-if (curfile && end_at.type == END_AT_TIME) end_at.pos += mux_v->timer;
+if (curfile && end_at.type == END_AT_TIME) end_at.pos += adjusted_muxer_time(mux_v);
 
 if (edl_records) free_edl(edl_records);
 next_edl_record = edl_records = NULL;
@@ -1294,15 +1242,25 @@ if (edl_filename) {
 
 if (sh_audio && audio_delay != 0.) fixdelay(d_video, d_audio, mux_a, &frame_data, mux_v->codec==VCODEC_COPY);
 
-while(!at_eof){
+// Just assume a seek. Also works if time stamps do not start with 0
+did_seek = 1;
+
+while(at_eof != 3){
 
     int blit_frame=0;
     float a_pts=0;
     float v_pts=0;
     int skip_flag=0; // 1=skip  -1=duplicate
+    double a_muxer_time;
+    double v_muxer_time;
+    int force_audio = at_eof & 1;
+
+    a_muxer_time = adjusted_muxer_time(mux_a);
+    v_muxer_time = adjusted_muxer_time(mux_v);
+    at_eof = sh_audio ? 0 : 2;
 
     if((end_at.type == END_AT_SIZE && end_at.pos <= stream_tell(muxer->stream))  ||
-       (end_at.type == END_AT_TIME && end_at.pos < mux_v->timer))
+       (end_at.type == END_AT_TIME && end_at.pos < v_muxer_time))
         break;
 
     if(play_n_frames>=0){
@@ -1325,9 +1283,10 @@ goto_redo_edl:
 
             result = edl_seek(next_edl_record, demuxer, d_audio, mux_a, &frame_data, mux_v->codec==VCODEC_COPY);
 
-            if (result == 2) { at_eof=1; break; } // EOF
+            if (result == 2) { at_eof=3; break; } // EOF
             else if (result == 0) edl_seeking = 0; // no seeking
             else { // sucess
+                did_seek = 1;
                 edl_muted = 0;
                 if (last_pos >= sh_video->pts) {
                     // backwards seek detected!! Forget about this EDL skip altogether.
@@ -1356,16 +1315,17 @@ goto_redo_edl:
 
 if(sh_audio){
     // get audio:
-    while(mux_a->timer-audio_preload<mux_v->timer){
+    while(force_audio || a_muxer_time-audio_preload<v_muxer_time){
         float tottime;
-       int len=0;
+       int bytes_to_mux=0;
+       force_audio = 0;
 
        ptimer_start = GetTimerMS();
        // CBR - copy 0.5 sec of audio
        // or until the end of video:
        tottime = stop_time(demuxer, mux_v);
        if (tottime != -1) {
-               tottime -= mux_a->timer;
+               tottime -= a_muxer_time;
                if (tottime > 1./audio_density) tottime = 1./audio_density;
        }
        else tottime = 1./audio_density;
@@ -1377,6 +1337,7 @@ if(sh_audio){
        {
                if(mux_a->h.dwSampleSize) /* CBR */
                {
+                       int len;
                        if(aencoder->set_decoded_len)
                        {
                                len = mux_a->h.dwSampleSize*(int)(mux_a->h.dwRate*tottime);
@@ -1387,63 +1348,66 @@ if(sh_audio){
 
                        len = dec_audio(sh_audio, aencoder->decode_buffer, len);
                        mux_a->buffer_len += aencoder->encode(aencoder, mux_a->buffer + mux_a->buffer_len,
-                               aencoder->decode_buffer, len, mux_a->buffer_size-mux_a->buffer_len);
-                       if(mux_a->buffer_len < mux_a->wf->nBlockAlign)
-                               len = 0;
-                       else
-                               len = mux_a->wf->nBlockAlign*(mux_a->buffer_len/mux_a->wf->nBlockAlign);
+                               len <= 0 && sh_audio->ds->eof ? NULL : aencoder->decode_buffer, len, mux_a->buffer_size-mux_a->buffer_len);
+                       if(mux_a->buffer_len >= mux_a->wf->nBlockAlign)
+                               bytes_to_mux = mux_a->wf->nBlockAlign*(mux_a->buffer_len/mux_a->wf->nBlockAlign);
                }
                else    /* VBR */
                {
                        int sz = 0;
                        while(1)
                        {
-                               len = 0;
+                               int len;
                                if(! sz)
                                        sz = aencoder->get_frame_size(aencoder);
                                if(sz > 0 && mux_a->buffer_len >= sz)
                                {
-                                       len = sz;
+                                       bytes_to_mux = sz;
                                        break;
                                }
                                len = dec_audio(sh_audio,aencoder->decode_buffer, aencoder->decode_buffer_size);
                                if(len <= 0)
                                {
-                                       len = 0;
-                                       break;
-                               }
-                               len = aencoder->encode(aencoder, mux_a->buffer + mux_a->buffer_len, aencoder->decode_buffer, len, mux_a->buffer_size-mux_a->buffer_len);
+                                       // try flushing encoder
+                                       if (sh_audio->ds->eof)
+                                               len = aencoder->encode(aencoder, mux_a->buffer + mux_a->buffer_len, NULL, 0, mux_a->buffer_size-mux_a->buffer_len);
+                                       if (len <= 0)
+                                               break;
+                               } else
+                                       len = aencoder->encode(aencoder, mux_a->buffer + mux_a->buffer_len, aencoder->decode_buffer, len, mux_a->buffer_size-mux_a->buffer_len);
                                mux_a->buffer_len += len;
                        }
            }
-           if (mux_v->timer == 0) mux_a->h.dwInitialFrames++;
+           if (v_muxer_time == 0) mux_a->h.dwInitialFrames++;
        }
-       else {
+       else if (mux_a->codec == ACODEC_COPY) {
        if(mux_a->h.dwSampleSize){
-           switch(mux_a->codec){
-           case ACODEC_COPY: // copy
+           int len;
                len=mux_a->wf->nAvgBytesPerSec*tottime;
                len/=mux_a->h.dwSampleSize;if(len<1) len=1;
                len*=mux_a->h.dwSampleSize;
-               len=demux_read_data(sh_audio->ds,mux_a->buffer,len);
-               break;
-           }
+               bytes_to_mux=demux_read_data(sh_audio->ds,mux_a->buffer,len);
        } else {
            // VBR - encode/copy an audio frame
-           switch(mux_a->codec){
-           case ACODEC_COPY: // copy
-               len=ds_get_packet(sh_audio->ds,(unsigned char**) &mux_a->buffer);
-               break;
-               }
+               bytes_to_mux=ds_get_packet(sh_audio->ds,(unsigned char**) &mux_a->buffer);
            }
        }
-       if(len<=0) break; // EOF?
-       muxer_write_chunk(mux_a,len,AVIIF_KEYFRAME, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
-       if(!mux_a->h.dwSampleSize && mux_a->timer>0)
-           mux_a->wf->nAvgBytesPerSec=0.5f+(double)mux_a->size/mux_a->timer; // avg bps (VBR)
-       if(mux_a->buffer_len>=len){
-           mux_a->buffer_len-=len;
-           fast_memcpy(mux_a->buffer,mux_a->buffer+len,mux_a->buffer_len);
+       if(bytes_to_mux<=0) {
+           // EOF?
+           if (!sh_audio->a_out_buffer_len && sh_audio->ds->eof) {
+               if (mux_a->buffer_len)
+                  mp_msg(MSGT_MENCODER, MSGL_WARN, "Audio data left in buffer at end of file. Probably bug in audio encoder, please report.");
+               at_eof |= 2;
+           }
+           break;
+       }
+       muxer_write_chunk(mux_a,bytes_to_mux,AVIIF_KEYFRAME, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
+       a_muxer_time = adjusted_muxer_time(mux_a); // update after muxing
+       if(!mux_a->h.dwSampleSize && a_muxer_time>0)
+           mux_a->wf->nAvgBytesPerSec=0.5f+(double)mux_a->size/a_muxer_time; // avg bps (VBR)
+       if(mux_a->buffer_len>=bytes_to_mux){
+           mux_a->buffer_len-=bytes_to_mux;
+           memmove(mux_a->buffer,mux_a->buffer+bytes_to_mux,mux_a->buffer_len);
        }
 
 
@@ -1457,10 +1421,17 @@ if(sh_audio){
 
     if (!frame_data.already_read) {
         frame_data.in_size=video_read_frame(sh_video,&frame_data.frame_time,&frame_data.start,force_fps);
+        frame_data.flush = frame_data.in_size < 0 && d_video->eof && (at_eof & 2) &&
+                           mux_v->codec != VCODEC_COPY &&
+                           mux_v->codec != VCODEC_FRAMENO;
+        if (frame_data.flush) {
+            frame_data.in_size = 0;
+            frame_data.start = NULL;
+        }
         sh_video->timer+=frame_data.frame_time;
     }
     frame_data.frame_time /= playback_speed;
-    if(frame_data.in_size<0){ at_eof=1; break; }
+    if(frame_data.in_size<0){ frame_data.already_read = 0; at_eof|=1; continue; }
     ++decoded_frameno;
 
     v_timer_corr-=frame_data.frame_time-(float)mux_v->h.dwScale/mux_v->h.dwRate;
@@ -1470,17 +1441,17 @@ if(demuxer2){   // 3-pass encoding, read control file (frameno.avi)
        while(next_frameno<decoded_frameno){
            int* start;
            int len=ds_get_packet(demuxer2->video,(unsigned char**) &start);
-           if(len<0){ at_eof=1;break;}
+           if(len<0){ at_eof|=1;break;}
            if(len==0) --skip_flag; else  // duplicate
            if(len==4) next_frameno=start[0];
        }
-    if(at_eof) break;
+    if(at_eof) continue;
        skip_flag=next_frameno-decoded_frameno;
     // find next frame:
        while(next_frameno<=decoded_frameno){
            int* start;
            int len=ds_get_packet(demuxer2->video,(unsigned char**) &start);
-           if(len<0){ at_eof=1;break;}
+           if(len<0){ at_eof|=1;break;}
            if(len==0) --skip_flag; else  // duplicate
            if(len==4) next_frameno=start[0];
        }
@@ -1533,8 +1504,21 @@ default:
                      (!sh_video->vfilter ||
                       ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) != CONTROL_TRUE);
     void *decoded_frame = decode_video(sh_video,frame_data.start,frame_data.in_size,
-                                       drop_frame, MP_NOPTS_VALUE);
-    blit_frame = decoded_frame && filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE);}
+                                       drop_frame, MP_NOPTS_VALUE, MP_NOPTS_VALUE, NULL);
+    if (frame_data.flush && !decoded_frame)
+        at_eof = 3;
+    if (did_seek && sh_video->pts != MP_NOPTS_VALUE) {
+        did_seek = 0;
+        sub_offset = sh_video->pts;
+    }
+    // NOTE: this is not really correct, but it allows -ass to work mostly
+    // v_muxer_time was tried before, but it is completely off when -ss is used
+    // (see bug #1960).
+    // sh_video->pts causes flickering with subtitles and complaints from MPEG-4
+    // encoder due to not being monotonic.
+    // If you change this please note the reason here!
+    blit_frame = decoded_frame && filter_video(sh_video, decoded_frame, v_muxer_time + sub_offset, MP_NOPTS_VALUE);}
+    v_muxer_time = adjusted_muxer_time(mux_v); // update after muxing
 
     if (sh_video->vf_initialized < 0) mencoder_exit(1, NULL);
 
@@ -1593,24 +1577,18 @@ if(sh_audio && !demuxer2){
           ((ds_tell(d_audio)-sh_audio->a_in_buffer_len)/sh_audio->audio.dwSampleSize) :
           (d_audio->block_no); // <- used for VBR audio
         a_pts=samples*(float)sh_audio->audio.dwScale/(float)sh_audio->audio.dwRate;
-      delay_corrected=1;
     } else
 #endif
     {
       // PTS = (last timestamp) + (bytes after last timestamp)/(bytes per sec)
-      a_pts=d_audio->pts;
-      if(!delay_corrected) if(a_pts) delay_corrected=1;
-      a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+      a_pts=calc_a_pts(sh_audio, d_audio);
     }
     v_pts=sh_video ? sh_video->pts : d_video->pts;
     // av = compensated (with out buffering delay) A-V diff
     AV_delay=(a_pts-v_pts);
     AV_delay-=audio_delay;
     AV_delay /= playback_speed;
-    AV_delay-=mux_a->timer-(mux_v->timer-(v_timer_corr+v_pts_corr));
-    // adjust for encoder delays
-    AV_delay -= (float) mux_a->encoder_delay * mux_a->h.dwScale/mux_a->h.dwRate;
-    AV_delay += (float) mux_v->encoder_delay * mux_v->h.dwScale/mux_v->h.dwRate;
+    AV_delay-=a_muxer_time-(v_muxer_time-(v_timer_corr+v_pts_corr));
        // compensate input video timer by av:
         x=AV_delay*0.1f;
         if(x<-max_pts_correction) x=-max_pts_correction; else
@@ -1637,26 +1615,26 @@ if(sh_audio && !demuxer2){
 #endif
       if(!quiet) {
        if( mp_msg_test(MSGT_STATUSLINE,MSGL_V) ) {
-               mp_msg(MSGT_STATUSLINE,MSGL_STATUS,"Pos:%6.1fs %6df (%2d%%) %3dfps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d] A/Vms %d/%d D/B/S %d/%d/%d \r",
-               mux_v->timer, decoded_frameno, (int)(p*100),
+               mp_msg(MSGT_STATUSLINE,MSGL_STATUS,"VPos:%6.1fs APos:%6.1fs %6df (%2d%%) %3dfps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d] A/Vms %d/%d D/B/S %d/%d/%d \r",
+               v_muxer_time, a_muxer_time, decoded_frameno, (int)(p*100),
                (t>1) ? (int)(decoded_frameno/t+0.5) : 0,
                (p>0.001) ? (int)((t/p-t)/60) : 0,
                (p>0.001) ? (int)(stream_tell(muxer->stream)/p/1024/1024) : 0,
                v_pts_corr,
-               (mux_v->timer>1) ? (int)(mux_v->size/mux_v->timer/125) : 0,
-               (mux_a && mux_a->timer>1) ? (int)(mux_a->size/mux_a->timer/125) : 0,
+               (v_muxer_time>1) ? (int)(mux_v->size/v_muxer_time/125) : 0,
+               (mux_a && a_muxer_time>1) ? (int)(mux_a->size/a_muxer_time/125) : 0,
                        audiorate/audiosamples, videorate/videosamples,
                        duplicatedframes, badframes, skippedframes
                );
        } else
        mp_msg(MSGT_STATUSLINE,MSGL_STATUS,"Pos:%6.1fs %6df (%2d%%) %5.2ffps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d]\r",
-           mux_v->timer, decoded_frameno, (int)(p*100),
+           v_muxer_time, decoded_frameno, (int)(p*100),
            (t>1) ? (float)(decoded_frameno/t) : 0,
            (p>0.001) ? (int)((t/p-t)/60) : 0,
            (p>0.001) ? (int)(stream_tell(muxer->stream)/p/1024/1024) : 0,
            v_pts_corr,
-           (mux_v->timer>1) ? (int)(mux_v->size/mux_v->timer/125) : 0,
-           (mux_a && mux_a->timer>1) ? (int)(mux_a->size/mux_a->timer/125) : 0
+           (v_muxer_time>1) ? (int)(mux_v->size/v_muxer_time/125) : 0,
+           (mux_a && a_muxer_time>1) ? (int)(mux_a->size/a_muxer_time/125) : 0
        );
       }
     }
@@ -1669,7 +1647,7 @@ if(sh_audio && !demuxer2){
      int len;
      while((len=ds_get_packet_sub(d_dvdsub,&packet, NULL, NULL))>0){
         mp_msg(MSGT_MENCODER,MSGL_V,"\rDVD sub: len=%d  v_pts=%5.3f  s_pts=%5.3f  \n",len,sh_video->pts,d_dvdsub->pts);
-            vobsub_out_output(vobsub_writer,packet,len,mux_v->timer + d_dvdsub->pts - sh_video->pts);
+            vobsub_out_output(vobsub_writer,packet,len,v_muxer_time + d_dvdsub->pts - sh_video->pts);
      }
  }
  else
@@ -1722,6 +1700,9 @@ if(aencoder)
     if(aencoder->fixup)
         aencoder->fixup(aencoder);
 
+/* flush muxer just in case, this is a no-op unless
+ * we created a stream but never wrote frames to it... */
+muxer_flush(muxer);
 if (muxer->cont_write_index) muxer_write_index(muxer);
 muxer_f_size=stream_tell(muxer->stream);
 stream_seek(muxer->stream,0);
@@ -1754,6 +1735,12 @@ if(sh_audio){ uninit_audio(sh_audio);sh_audio=NULL; }
 if(sh_video){ uninit_video(sh_video);sh_video=NULL; }
 if(demuxer) free_demuxer(demuxer);
 if(stream) free_stream(stream); // kill cache thread
+// Do not free mux_v->buffer, it may have been overwritten
+// with something we should not free.
+if(mux_v) free(mux_v_buffer);
+if(mux_a) free(mux_a->buffer);
+common_uninit();
+mp_msg_uninit();
 
 return interrupted;
 }