Old 3rd December 2012, 02:47   #1
thinktink
Forum King
 
thinktink's Avatar
 
Join Date: May 2009
Location: On the streets of Kings County, CA.
Posts: 3,013
Send a message via Skype™ to thinktink
Winamp Encoders

I learned a lot from trial-and-error and debug inspection about how Winamp interacts with the encoder plugins (enc_*.dll) while working on an Opus encoder plugin. The same problems I had interacting with WASABI objects I also had with AudioCoder objects, in that they also are MSVC classes. I thought it would be simple enough to define a new encoder object handler like I did for WASABI classes, which was close, but not all the way.

[SMALL_RANT]
When Winamp is done with an encoder object it deletes it. Now for the layman this might not seem nefarious on it's own but to a third-party library developer it's actually not good (some would even say "bad form".) Deleting a class you did not create is dangerous, even when deleting a class from a DLL compiled with the same compiler, regardless if the destructor method is virtual. And since encoder plugins can (theoretically) be developed by any third-party developer, then submitted and reviewed there's no guarantee that it will be compiled with the same compiler.
[/SMALL_RANT]

Long story short, I had to add a special handling mechanism into my handling of my Winamp AudioCoder class, specifically, adding a method to the fake v-table pointer for handling calls to the AudioCoder's destructor.

Notes for new encoder developers (these are just some notes from off the top of my head that I had to discover the hard way):
  • When you have exported a "PrepareToFinish" or "PrepareToFinishW" function (which is apparently optional), this is a signal to your plugin that there is no more audio data left and to flush all remaining file data out on the next call to "Encode". "Encode" will continue to be called until you return 0 so don't worry if you have more data than the out buffer can hold at the time of the call. The file that is being written to still has a handle open on it so I suggest waiting until "FinishAudio3"/"FinishAudio3W" is called to finalize the file (if needed.)
  • When "FinishAudio3" or "FinishAudio3W" is called by Winamp, all file handles (at least by Winamp) have been closed and it's (theoretically) safe to modify it for finalization by whatever your library is encoding. This can include (but is not limited to) adding tags/headers/footers, parameter tweaks, or whatever the new file might need for actual use/playback.
  • The functions "CreateAudio3", "ConfigAudio3", "SetConfigItem", and "GetConfigItem" all have a parameter labeled "configfile". Use of that data is NOT optional. Normally it points to the ML Transcoder configuration file although it can point to some other file where another developer can specify a different location for other purposes. If your encoder has parameters that are user configurable from your configuration window (the one that is made when Winamp calls "ConfigAudio3"), you NEED to store those settings in the file pointed to by "configfile". The main reason for this is in the transition between when your config window is displayed and when "CreateAudio3" is called, your plugin IS COMPLETELY UNLOADED, which means all the configuration parameters the user just set went bye-bye. The only way to get them back is through that config file. Since the file pointed to by "configfile" is usually the same as the other encoder plugins (and the Transcoder ML plugin), you will need to play nice and define a unique INI section for your plugin (and keep the configuration parameters only in your section).
  • For Winamp, the PCM type is defined as 0x204D4350 or "PCM ". Example: "const unsigned int pcmtype='PCM ';//0x204D4350"
  • Before "CreateAudio3" is called, "GetConfigItem" is called with the "item" parameter set to "extension". When this happens, it would be good to return the actual file extension used for your encoder without the delimiting extension dot, but double check to make sure that the length of the "data" parameter (as indicated by the "len" parameter) is large enough to accommodate your actual file extension. At the moment I believe it's 5 so if your file extension is longer than "len", output what you can (taking into consideration the NULL terminator), then rename the file when "FinishAudio3"/"FinishAudio3W" is called.
  • The dimensions of your configuration window: width<=384; height<=271. This window will be a child window to the window handle given by the "hwndParent" parameter in the call to "ConfigAudio3". This is not the same as Winamp's main window.

I am attaching my encoder handler source unit for Borland compilers. Enjoy.
Attached Files
File Type: zip CallEncoder.zip (1.8 KB, 526 views)
thinktink is offline   Reply With Quote
Old 27th March 2013, 20:39   #2
Benski
Ben Allison
Former Winamp Developer
 
Benski's Avatar
 
Join Date: Jan 2005
Location: Brooklyn, NY
Posts: 1,057
Definitely good info.

Don't get me started on the encoder API. It's a leftover from NSV development that got re-used. It's been haphazardly developed and in general, the "push data in, get data out" model leaves a lot to be desired. It was built for real-time encoding of streamable codecs like Layer 3 or ADTS AAC. The MP4/AAC encoder plugin just sends back dummy data, secretly writes to a temp file, and then swaps it over at the end (during FinishAudio). It's horribly inefficient (since winamp.exe is also writing to disk), but I don't think disk I/O is the bottleneck.

The delete issue is a known issue. No guarantee that they were allocated from the same memory heap as winamp.exe I should just add a DeleteAudio and call it a day. Of course it'd only be compatible with newer versions of Winamp.

I've been contemplating a new interface to replace it, but have been so busy with the Android app and the Cloud project for that.
Benski is offline   Reply With Quote
Old 3rd April 2013, 17:39   #3
thinktink
Forum King
 
thinktink's Avatar
 
Join Date: May 2009
Location: On the streets of Kings County, CA.
Posts: 3,013
Send a message via Skype™ to thinktink
Just now saw your reply.

Quote:
Originally Posted by Benski View Post
Don't get me started on the encoder API. It's a leftover from NSV development that got re-used. It's been haphazardly developed and in general, the "push data in, get data out" model leaves a lot to be desired. It was built for real-time encoding of streamable codecs like Layer 3 or ADTS AAC.
It's really not THAT bad since I have been able to develop a compliant and working encoder plugin (for Opus encoding.)

Quote:
Originally Posted by Benski View Post
The MP4/AAC encoder plugin just sends back dummy data, secretly writes to a temp file, and then swaps it over at the end (during FinishAudio). It's horribly inefficient (since winamp.exe is also writing to disk), but I don't think disk I/O is the bottleneck.
Heh, I never woulda' figured.

Quote:
Originally Posted by Benski View Post
The delete issue is a known issue. No guarantee that they were allocated from the same memory heap as winamp.exe I should just add a DeleteAudio and call it a day. Of course it'd only be compatible with newer versions of Winamp.
I like that actually and you can even still do the old delete behavior for encoders that don't export it.

Quote:
Originally Posted by Benski View Post
I've been contemplating a new interface to replace it, but have been so busy with the Android app and the Cloud project for that.
If it were me, I'd just interface it the same way the other plugins do it, a single exported function that returns a plugin struct that contains interface functions. But as I said before the current model is not THAT bad as I have been able to manage it, could just use a bit of tweaking.
thinktink is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > Winamp Development

Tags
audiocoder, encoder

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump