mplayer: fix buffer handling during channel change.
authorcigaes <cigaes@b3059339-0415-0410-9bf9-f77b7e298cf2>
Tue, 12 May 2015 17:53:41 +0000 (17:53 +0000)
committercigaes <cigaes@b3059339-0415-0410-9bf9-f77b7e298cf2>
Tue, 12 May 2015 17:53:41 +0000 (17:53 +0000)
Without this change, when changing from, for example, stereo
to 5.1, there may be a little stereo data left in the output
buffer when the audio output is reinitialized with the new
format. If that little stereo data is not a multiple of 6 samples
it causes a shift in the mapping of the 5.1 channels.

With this patch, decoded audio data in new format is not filtered
as long as there are still samples in old format that have not
yet been sent to the AO driver.

Based on a suggestion by Reimar Döffinger.

git-svn-id: svn://git.mplayerhq.hu/mplayer/trunk@37399 b3059339-0415-0410-9bf9-f77b7e298cf2

libmpdemux/stheader.h
mplayer.c

index 9cbcd4c..d7601b6 100644 (file)
@@ -68,6 +68,9 @@ typedef struct sh_audio {
   char* a_buffer;
   int a_buffer_len;
   int a_buffer_size;
+  int a_buffer_format_change; // audio data in the input buffer is subject
+                              // to a format change but data in the old
+                              // format is still present in the out buffer
   // output buffers:
   char* a_out_buffer;
   int a_out_buffer_len;
index 0068b84..9da8888 100644 (file)
--- a/mplayer.c
+++ b/mplayer.c
@@ -2135,7 +2135,6 @@ static int fill_audio_out_buffers(void)
     int playflags = 0;
     int audio_eof = 0;
     int bytes_to_write;
-    int format_change = 0;
     int timeout = 0;
     sh_audio_t *const sh_audio = mpctx->sh_audio;
 
@@ -2174,11 +2173,11 @@ static int fill_audio_out_buffers(void)
         // Fill buffer if needed:
         current_module = "decode_audio";
         t = GetTimer();
-        if (!format_change) {
+        if (!sh_audio->a_buffer_format_change) {
             res = mp_decode_audio(sh_audio, playsize);
-            format_change = res == -2;
+            sh_audio->a_buffer_format_change = res == -2;
         }
-        if (!format_change && res < 0) // EOF or error
+        if (!sh_audio->a_buffer_format_change && res < 0) // EOF or error
             if (mpctx->d_audio->eof) {
                 audio_eof = 1;
                 if (sh_audio->a_out_buffer_len == 0)
@@ -2189,7 +2188,7 @@ static int fill_audio_out_buffers(void)
         audio_time_usage += tt;
         if (playsize > sh_audio->a_out_buffer_len) {
             playsize = sh_audio->a_out_buffer_len;
-            if (audio_eof || format_change)
+            if (audio_eof || sh_audio->a_buffer_format_change)
                 playflags |= AOPLAY_FINAL_CHUNK;
         }
         if (!playsize)
@@ -2209,19 +2208,21 @@ static int fill_audio_out_buffers(void)
             memmove(sh_audio->a_out_buffer, &sh_audio->a_out_buffer[playsize],
                     sh_audio->a_out_buffer_len);
             mpctx->delay += playback_speed * playsize / (double)ao_data.bps;
-        } else if ((format_change || audio_eof) && mpctx->audio_out->get_delay() < .04) {
+        } else if ((sh_audio->a_buffer_format_change || audio_eof) &&
+                   mpctx->audio_out->get_delay() < .04) {
             // Sanity check to avoid hanging in case current ao doesn't output
             // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
             mp_msg(MSGT_CPLAYER, MSGL_WARN, MSGTR_AudioOutputTruncated);
             sh_audio->a_out_buffer_len = 0;
         }
     }
-    if (format_change) {
+    if (sh_audio->a_buffer_format_change && !sh_audio->a_out_buffer_len) {
         uninit_player(INITIALIZED_AO);
         af_uninit(sh_audio->afilter);
         free(sh_audio->afilter);
         sh_audio->afilter = NULL;
         reinit_audio_chain();
+        sh_audio->a_buffer_format_change = 0;
     }
     return 1;
 }