[MPlayer-users] help needed, mplayer repeats audio frames at the end of video

David Bolen db3l.net at gmail.com
Thu Dec 11 23:34:29 CET 2014


Reimar Döffinger <Reimar.Doeffinger at gmx.de> writes:

> On 11.12.2014, at 12:35, Reimar Döffinger <Reimar.Doeffinger at gmx.de> wrote:
>> On 11 December 2014 11:34:08 CET, Shahid Mahmood Satti <ss at opticom.de> wrote:
>>> 
>>> AO: [dsound] 44100Hz 2ch s16le (2 bytes per sample)
>> 
>> Not sure which will be available in your build, but could you try other -ao ?
>> E.g. win32, sdl and openal are available on Windows in principle.
>> Even though dsound (the one your are using) is generally recommended.
>
> I looked at the code and it is indeed a bug.
> It happens only with dsound due to the API being a bit special.
> It will probably take a bit to fix, so you might want to use one of the others I mentioned as a work-around.

I ran into this myself a long time back - I believe in addition to audio
shorter than video it can happen with extremely short audio files, like <1s
sound effects.  I had switched to and been using ao_win32 for a long time.
But I had to start using ao_dsound last year for application reasons, and
developed a patch that resolved the issue for me, though it's a little
crude.

It essentially back-fills the audio buffer with silence, so that any
overruns at the end are silent rather than garbage audio from what happens
to be in the buffer.  It also wakes up a little more frequently to help
minimize the overrun (with no real measurable increase in CPU usage in my
testing).  I've had it in production use for the past 18 months or so
without an issue.

The patch is against a pretty ancient version (r29004) since that's still
my base, but at least as of last year when working on the patch it didn't
look like anything had changed in ao_dsound that would be incompatible.

-- David

*** mplayer.29004/libao2/ao_dsound.c	2009-03-06 14:43:12.249628000 -0500
--- mplayer.new/libao2/ao_dsound.c	2013-02-19 19:23:15.668625000 -0500
***************
*** 27,32 ****
--- 27,33 ----
  
  #include <stdio.h>
  #include <stdlib.h>
+ #include <string.h>
  #include <windows.h>
  #define DIRECTSOUND_VERSION 0x0600
  #include <dsound.h>
***************
*** 378,383 ****
--- 379,426 ----
    return 0;
  }
  
+ /**
+ \brief fill sound buffer with silence
+ \param len length of the buffer to fill
+ \return number of filled bytes
+ */
+ static int write_silence(int len)
+ {
+   HRESULT res;
+   LPVOID lpvPtr1; 
+   DWORD dwBytes1; 
+   LPVOID lpvPtr2; 
+   DWORD dwBytes2; 
+ 	
+   // Lock the buffer
+   res = IDirectSoundBuffer_Lock(hdsbuf, write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
+   // If the buffer was lost, restore and retry lock. 
+   if (DSERR_BUFFERLOST == res) 
+   { 
+       IDirectSoundBuffer_Restore(hdsbuf);
+       res = IDirectSoundBuffer_Lock(hdsbuf, write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
+   }
+   
+   if (SUCCEEDED(res)) 
+   {
+       // Fill buffer with silence
+       memset(lpvPtr1, 0, dwBytes1);
+       if (NULL != lpvPtr2 ) memset(lpvPtr2, 0, dwBytes2);
+       write_offset += dwBytes1+dwBytes2;
+       if (write_offset >= buffer_size) write_offset = dwBytes2;
+   }
+ 	
+   // Release the data back to DirectSound. 
+   res = IDirectSoundBuffer_Unlock(hdsbuf, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
+   if (SUCCEEDED(res)) 
+   { 
+       return dwBytes1+dwBytes2; 
+   } 
+ 
+   // Lock, Unlock, or Restore failed. 
+   return 0;
+ }
+ 
  /***************************************************************************************/
  
  /**
***************
*** 560,571 ****
  static void uninit(int immed)
  {
  	if(immed)reset();
! 	else{
! 		DWORD status;
! 		IDirectSoundBuffer_Play(hdsbuf, 0, 0, 0);
  		while(!IDirectSoundBuffer_GetStatus(hdsbuf,&status) && (status&DSBSTATUS_PLAYING))
! 			usec_sleep(20000);
! 	}
  	DestroyBuffer();
  	UninitDirectSound();
  }
--- 603,649 ----
  static void uninit(int immed)
  {
  	if(immed)reset();
!         else {
! 		// [db3l] 2013-01-26 - 2013-02-19
!                 //
!                 // Allow remaining pending data (through write_offset) to play.  The buffer
!                 // is back-filled with silence while waiting to avoid any stray audio from
!                 // overrunning the final position (since we have to poll to detect).
!                 //
!                 // Take possible wrapping of remaining data into account while waiting.
!                 // Also, if the intended stopping location is close to a buffer edge, it
!                 // could be missed entirely, so wrap count serves as a forced exit after
!                 // too many wraps.  For example, one test showed:
!                 //       ds_write     mp_write      buffer end
!                 //       5292         176128        176400
!                 // and when executing, adjacent position polls were 174636, then 0, so
!                 // missed the target entirely (a narrow window from 176128-176400).
! 
!                 DWORD status, ds_play_offset, ds_last_offset;
!                 int mp_write_offset = write_offset;    // Save as it changes when filling
!                 int wrap_remain;                       // Buffer wrap count
! 
!                 IDirectSoundBuffer_GetCurrentPosition(hdsbuf, &ds_play_offset, NULL);
!                 wrap_remain = mp_write_offset < ds_play_offset;
!                 
!                 IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING);
!                 while (wrap_remain > 0 ||
!                        (wrap_remain >= 0 && ds_play_offset < mp_write_offset)) {
!                     write_silence(get_space());
!                     usec_sleep(5000);
! 
!                     ds_last_offset = ds_play_offset;
!                     IDirectSoundBuffer_GetCurrentPosition(hdsbuf, &ds_play_offset, NULL);
!                     if (ds_play_offset < ds_last_offset) {
!                         wrap_remain--;
!                     }
!                 }
! 
! 		// Then stop and wait for completion
!                 IDirectSoundBuffer_Stop(hdsbuf);
  		while(!IDirectSoundBuffer_GetStatus(hdsbuf,&status) && (status&DSBSTATUS_PLAYING))
!                     usec_sleep(5000);
!         }
  	DestroyBuffer();
  	UninitDirectSound();
  }



More information about the MPlayer-users mailing list