Current version

v1.10.4 (stable)

Navigation

Main page
Archived news
Downloads
Documentation
   Capture
   Compiling
   Processing
   Crashes
Features
Filters
Plugin SDK
Knowledge base
Donate
Contact info
Forum
 
Other projects
   Altirra

Search

Archives

01 Dec - 31 Dec 2013
01 Oct - 31 Oct 2013
01 Aug - 31 Aug 2013
01 May - 31 May 2013
01 Mar - 31 Mar 2013
01 Feb - 29 Feb 2013
01 Dec - 31 Dec 2012
01 Nov - 30 Nov 2012
01 Oct - 31 Oct 2012
01 Sep - 30 Sep 2012
01 Aug - 31 Aug 2012
01 June - 30 June 2012
01 May - 31 May 2012
01 Apr - 30 Apr 2012
01 Dec - 31 Dec 2011
01 Nov - 30 Nov 2011
01 Oct - 31 Oct 2011
01 Sep - 30 Sep 2011
01 Aug - 31 Aug 2011
01 Jul - 31 Jul 2011
01 June - 30 June 2011
01 May - 31 May 2011
01 Apr - 30 Apr 2011
01 Mar - 31 Mar 2011
01 Feb - 29 Feb 2011
01 Jan - 31 Jan 2011
01 Dec - 31 Dec 2010
01 Nov - 30 Nov 2010
01 Oct - 31 Oct 2010
01 Sep - 30 Sep 2010
01 Aug - 31 Aug 2010
01 Jul - 31 Jul 2010
01 June - 30 June 2010
01 May - 31 May 2010
01 Apr - 30 Apr 2010
01 Mar - 31 Mar 2010
01 Feb - 29 Feb 2010
01 Jan - 31 Jan 2010
01 Dec - 31 Dec 2009
01 Nov - 30 Nov 2009
01 Oct - 31 Oct 2009
01 Sep - 30 Sep 2009
01 Aug - 31 Aug 2009
01 Jul - 31 Jul 2009
01 June - 30 June 2009
01 May - 31 May 2009
01 Apr - 30 Apr 2009
01 Mar - 31 Mar 2009
01 Feb - 29 Feb 2009
01 Jan - 31 Jan 2009
01 Dec - 31 Dec 2008
01 Nov - 30 Nov 2008
01 Oct - 31 Oct 2008
01 Sep - 30 Sep 2008
01 Aug - 31 Aug 2008
01 Jul - 31 Jul 2008
01 June - 30 June 2008
01 May - 31 May 2008
01 Apr - 30 Apr 2008
01 Mar - 31 Mar 2008
01 Feb - 29 Feb 2008
01 Jan - 31 Jan 2008
01 Dec - 31 Dec 2007
01 Nov - 30 Nov 2007
01 Oct - 31 Oct 2007
01 Sep - 30 Sep 2007
01 Aug - 31 Aug 2007
01 Jul - 31 Jul 2007
01 June - 30 June 2007
01 May - 31 May 2007
01 Apr - 30 Apr 2007
01 Mar - 31 Mar 2007
01 Feb - 29 Feb 2007
01 Jan - 31 Jan 2007
01 Dec - 31 Dec 2006
01 Nov - 30 Nov 2006
01 Oct - 31 Oct 2006
01 Sep - 30 Sep 2006
01 Aug - 31 Aug 2006
01 Jul - 31 Jul 2006
01 June - 30 June 2006
01 May - 31 May 2006
01 Apr - 30 Apr 2006
01 Mar - 31 Mar 2006
01 Feb - 29 Feb 2006
01 Jan - 31 Jan 2006
01 Dec - 31 Dec 2005
01 Nov - 30 Nov 2005
01 Oct - 31 Oct 2005
01 Sep - 30 Sep 2005
01 Aug - 31 Aug 2005
01 Jul - 31 Jul 2005
01 June - 30 June 2005
01 May - 31 May 2005
01 Apr - 30 Apr 2005
01 Mar - 31 Mar 2005
01 Feb - 29 Feb 2005
01 Jan - 31 Jan 2005
01 Dec - 31 Dec 2004
01 Nov - 30 Nov 2004
01 Oct - 31 Oct 2004
01 Sep - 30 Sep 2004
01 Aug - 31 Aug 2004

Stuff

Powered by Pivot  
XML: RSS feed 
XML: Atom feed 

§ The infamous frame 9995 MP3 bug

For years, I've been receiving reports about a mysterious problem with VirtualDub hanging during a save operation. The program's UI was still responsive, so the application hadn't totally died, but the processing pipeline jammed up such that the render couldn't make any progress or be aborted (a "livelock"). I had initially assumed that this was a deadlock caused by thread synchronization issues, which wouldn't lock the UI because VirtualDub's UI runs in a separate thread, and this was reinforced by the livelock log messages in recent versions indicating that the audio thread was stuck in a system call. However, I could never find the culprit or reproduce the problem. This was very frustrating for me, because it was a long-standing issue that made my program unusable for some people, and which I couldn't fix.

Until now.

I recently found out which software triggers the problem and why — it's the Creative Labs MP3 codec (ctmp3.acm), and it's because of peculiar notifications being sent by that codec. It comes with the software that ships with certain SoundBlaster Live! sound cards; in particular, installing the PlayCenter application will also install the codec. Either renaming the driver file temporarily, uninstalling it, or lowering its priority in the Sounds and Audio Devices control panel so that another MP3 codec has priority will work around the problem. I think I have a viable workaround that I can put into VirtualDub itself, but why this codec causes a lockup is an interesting question in itself.

A quick note

The Creative MP3 codec shows up as just "MP3" in the audio codec list, and it of course, uses a tag of 0x0055 (WAVE_FORMAT_MPEGLAYER3) for its compressed format. One of the sources of confusion is that when the lockup problem occurs, you can get it whether you choose that codec or any other MP3 codec in VirtualDub's audio compression dialog. The reason for this is a deficiency in VirtualDub's settings handling. When an audio format is selected for compression, VirtualDub only records the compressed format that you have selected. The problem is that if you have multiple audio codecs installed that can compress to that format from the audio source, it is indeterminate which codec is used, regardless of which one you picked. The result is that picking either the MP3 setting, the MPEG Layer-3 entry provided by the ubiquitous Fraunhofer codec, or even a Lame ACM entry, can cause the Creative codec to be used instead.

I plan to solve this at some point by adding the codec name or ID in the internal settings as a hint, but haven't gotten around to modifying all the code paths yet. In the meantime, only having one codec installed per compressed format is the best way to avoid ambiguity.

The reason for the livelock

The test that finally succeeded in reproducing the problem was to do MP3 compression from 44kHz, 16-bit PCM to 160kbps with a long audio stream, nearly an hour long. Once it locked up — and after I had done the customary finally-a-repro-case dance of joy — attaching the debugger revealed something really strange. The thread that was processing the audio had locked up in the call to acmStreamConvert() inside the CTMP3.ACM codec, which had, in turn, made a system call at the time of the break. What was totally unexpected, though, was that the system call wasn't WaitForSingleObject(), but Sleep()! Well, after a little disassembly, here's the surrounding code that I found in the codec:

do {
    Sleep(10);
} while(!PostThreadMessage(GetCurrentThreadId(), MM_STREAM_DONE, hacmStream, 0));

Uh, right.

A little background: PostThreadMessage() is used to asynchronously send a message to a thread's message queue, but without associating that thread with any window. The only way such a message can be handled is by a message hook or by direct handling in the thread's message loop, because DispatchMessage() just dumps messages on the floor. You can use thread messages as a way to communicate between threads, as long as the receiving thread doesn't create a modal dialog box without a thread hook. One of the problems you can run into is that if the thread hasn't gotten to a function like PeekMessage() or GetMessage() yet, PostThreadMessage() will fail. One of the solutions that the Platform SDK recommends is precisely the above, to call Sleep() and then retry PostThreadMessage() until it succeeds. Yuuuuck!!

However, there are two problems with the above.

One is that I can't see why the audio codec would post MM_STREAM_DONE as a thread message. According to the ACM documentation, MM_STREAM_DONE is only used in two contexts: posted as a message to a window that was specified with the stream with CALLBACK_WINDOW, and used as an event ID when calling the callback function specified with CALLBACK_FUNCTION. VirtualDub doesn't set either of these flags, and moreover, I couldn't find any other audio codec on my system that even imports PostThreadMessage(). The other problem is more serious, though, which is that....

...It makes no sense to do a loop like this with the current thread as the target. The current thread obviously can't be running a message loop, since it's busy running this post loop instead, and if there is a problem with the message queue that causes PostThreadMessage() to fail, it will never be resolved. And in fact, because VirtualDub calls the audio codec on a non-UI thread that doesn't run a message pump, the message queue fills with MM_STREAM_DONE messages and eventually fills up, causing PostThreadMessage() to fail with ERROR_INSUFFICIENT_QUOTA. And then the thread loops forever calling Sleep().

How big is the message queue in Windows XP? You guessed it, the default is 10,000 messages. Take into account a 1:1 audio interleave with a little skew for the audio preload, and that's where the frame 9995 part comes from.

I can't definitively say that this is a bug, because the Platform SDK documentation in the Windows Multimedia area is rusty and I've definitely found a lot of it lacking, misleading, or even completely in error compared to the docs for the original 16-bit Windows systems that the modern Win32 multimedia modules are based on. The good news is that it is unlikely to affect most other programs, since many of them are single-threaded and will thus run a PeekMessage() loop in order to keep the UI responsive, or at least check for an abort request. The bad news is that it still isn't entirely safe, even in a thread that runs a message pump. Posting a thread message like this looks unnecessary; I see nothing in the docs that says you need to run a message queue to use ACM, and looping infinitely on an error without checking the error code is bad practice. I partly blame the MSDN technical writer who put such a lame solution in the documentation for PostThreadMessage().

What's sobering about the statement "not my bug" is that "not my problem" doesn't necessarily follow.

The way I am experimenting with solving this for 1.6.13 is to add a PeekMessage() loop to my audio codec class that only drains MM_STREAM_DONE thread messages, which in theory should work around the problem for non-UI threads while still not fouling normal window message dispatch if I call it on a UI thread. It seems to work so far, which makes me happy.

Comments

Comments posted:


Congrats... Btw: you said "my" instead of "by" in second paragraph, Line 2.

Pharaoh Atem - 11 02 06 - 15:09


Whoops, thanks for catching that.

Phaeron - 11 02 06 - 15:22


Does this have something to do with the following registry entry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERPostMessageLimit

and can this be used as a workaround?
(Google gives a lots of hits on this).

GL

Grof Luigi - 14 02 06 - 19:49


Possibly, but I'd be skeptical of how high you could feasibly adjust it — not sure, but the message queue might be in kernel mode. On a long clip it might be necessary to raise the limit into the hundreds of thousands.

Phaeron - 15 02 06 - 00:22


02/14
I would just like to point out that on such a system, there is "MP3" and there is "MPEG Layer-3". (Perhaps developers/programmers get as confused as the rest of us?) It is interesting to note that the two are different as one is essentially a technology layered for MP1/2 while the other is PCM.

So I will just say, the non-true Fraunhoffer _is_ likely an Illegally acquired codec, more likely than not at the point when MS was, atypically, forcing integration of MP3 technology (PCM) ahead of proper (as well as *Legal*) integration (Win98). (Whether Fraunhoffer decided to let it pass or a backroom deal was made or I am just making this up in my head is beyond me... Having been around when MP3 was more or less officially released, I can say MS's 'integration' seemed surpringly rapid.)

VirtualDub is the only program I know of to report the, for lack of clarity, "error". Interestingly too, the error is reported for a high number of avi's distributed over p2p.

Though I applaud your solution, as I refuse any integration of audio in my own video work for just this kind of reason, I can only welcome it as another step towards clarity, and maybe a future when I am more comfortable and trusting of the integration of audio into video (for lack of resources).

BTW, this issue, obviously, has never come up with audio software!

Can you help clarify some of my confusion to someone like me?,
£

£ (link) - 17 02 06 - 21:08


MP3 and MPEG layer-III are the same thing, referring to an encoding described by part of ISO 11172 that is a compressed encoding for audio. One's just an abbreviation for the other. PCM stands for pulse coded modulation and refers to uncompressed samples, which cannot be placed in an MPEG stream. Perhaps you are thinking of DVD, which does provide for PCM audio.

The entry that shows up in VirtualDub as MPEG layer-3 is the Fraunhofer-IIS codec. This codec is licensed by Microsoft and is installed with various products, most notably Windows Media Player. The MP3 entry comes from the Creative MP3 codec, which presumably is also licensed. Both are overt about the technology in use and neither is, AFAIK, illegal. In fact, I remember seeing one of the Windows Media Player team members saying that Microsoft had shelled out big bucks to include Fraunhofer-IIS in WMP10, because although they believe WMA is better, users demanded MP3 encoding support.

How their use might affect legality of your work, well, that I can't answer, not being a lawyer. VirtualDub flags codecs mainly for technical reasons, not for legal reasons; quite often when a codec is "extracted" for unlimited use, portions of the code are subtly broken in ways that affect program stability. The most notorious was the AngelPotion Definitive video codec, which was a hacked version of MS MPEG-4 V3 that potentially broke all other video codecs in the system when you installed it. The presence or absence of a warning dialog from VirtualDub, however, is not at all a good indicator and should not be relied upon for determining whether your workflow is legally safe.

Phaeron - 17 02 06 - 23:40


Dually thankfulness, Phaeron (:

'How their use might affect legality of your work, well, that I can’t answer, not being a lawyer.' - you obviously don't know me (I think I set a landspeed record of one copyright violation per 2.5 seconds or so over the length of a short album I did).

BTW, seen AutoGK? It basically worked for me (uses NanDub, I think) though I am still testing the VBR for the audio (MP3). Anyways, hope we can stay in touch as the MP4 encoding trickles down.

£

£ (link) - 18 02 06 - 18:12


funny synchronicity.. http://blogs.msdn.com/oldnewthing/archiv..

Ron - 22 02 06 - 00:39


Huh, guess what the Filter Graph Manager documentation states about that message pump:
http://msdn.microsoft.com/en-us/library/..).aspx

QUOTE:
Generally, applications should use CLSID_FilterGraph. Both CLSIDs create the same object, but they use different threading models:

* CLSID_FilterGraph creates the Filter Graph Manager on a worker thread, which is shared by all CLSID_FilterGraph instances within the same process. The thread dispatches messages sent by filters, and controls the lifetime of any windows created by filters.
* CLSID_FilterGraphNoThread creates the Filter Graph Manager on the application's thread. If you use this CLSID, the thread that calls CoCreateInstance must have a message loop that dispatches messages; otherwise, deadlocks can occur. Also, before the application thread exits, it must release the Filter Graph Manager and all graph objects (such as filters, pins, reference clocks, and so forth).

George Valkov (link) - 16 05 08 - 08:37


That's nice. What does the DirectShow Filter Graph Manager have to do with a codec registered with the WINMM Audio Compression Manager?

Phaeron - 16 05 08 - 22:56


Hi, I am using VirtualDub 1.5.4 and encountered the livelock situation at 23000 frame. I checked and I have no CTMP3.acm file installed on my computer. I changed to the latest version 1.9.11 still encountered the same issue. Can anyone help me and give me some advice?

R.T. - 24 08 11 - 10:20

Comment form


Please keep comments on-topic for this entry. If you have unrelated comments about VirtualDub, the forum is a better place to post them.
Name:  
Remember personal info?

Email (Optional):
Your email address is only revealed to the blog owner and is not shown to the public.
URL (Optional):
Comment: /

An authentication dialog may appear when you click Post Comment. Simply type in "post" as the user and "now" as the password. I have had to do this to stop automated comment spam.



Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.