Click here to Skip to main content
13,259,779 members (54,541 online)
Click here to Skip to main content
Add your own
alternative version


131 bookmarked
Posted 22 Apr 2004

C# Windows Media Format SDK Translation

, 9 May 2004
Rate this:
Please Sign up or sign in to vote.
In this article, I describe a translation of most of the WMF SDK interfaces, data structures, constants, and functions into C#.


In my previous article (Windows Media Audio Compressor), I've showed you how to create a Windows Media compressor. I used managed C++ to interact with the Windows Media Format (WMF) SDK, which exposes only unmanaged COM interfaces. While this could be an acceptable solution, it is a little complicated to implement, specially if you need more than simple interaction with the WMF objects, data and functions. In this article, I describe a translation of most of the WMF SDK interfaces, data structures, constants and functions into C#. Note: Digital Rights Management (DRM) support is not included in this translation.

While there are some classes that can be used without deep knowledge of the WMF SDK, the code accompanying this article assumes that you are already familiar with the WMF SDK. Also, a good knowledge of COM Interop and Interop Marshaling may be needed to use some of the translated interfaces and structures.

Some words about the translation

Somebody has asked me about ideas of how to translate the IWMSyncReader interface to use it for concatenating two WMA files. I told him that one idea could be to create an IDL file that publishes the required interfaces and compile it as a Type Library, and then use TLBIMP or just add it as a reference using the VS.NET IDE. This method could be appropriate for using many COM related objects and interfaces, but in the case of the WMF, there are many structures that are not automation compatible, as well as use of C-style arrays instead of SAFEARRAY, etc.

When you try to import such a Type Library, you will have many types and functions that not represent, in some cases, the concepts of the managed definition. Some types and functions can be useless or require too much marshaling effort to use it. In such situations, the .NET Framework documentation recommends that after using TLBIMP, you should use ILDASM to obtain a file in the intermediate language, which you can modify and recompile to obtain the desired results. However, in the case of the WMF SDK, we are talking about more than 50 interfaces.

I think that the best solution to use the WMF SDK is to declare in managed code all the definitions needed, and that was what I did. There is another solution, tough: wait for Microsoft to release their managed version of the SDK.

In this translation, I tried to have as much as possible a managed vision for all definitions and function prototypes in a managed vision, avoiding the use of pointers. However, sometimes this was just not possible. For example, the IDL definition of the method IWMHeaderInfo3.GetAttributeIndices is the following:

interface IWMHeaderInfo3 : IWMHeaderInfo2
 HRESULT GetAttributeIndices( [in] WORD wStreamNum,
                              [in] LPCWSTR pwszName,
                              [in] WORD *pwLangIndex,
                              [out, size_is( *pwCount )] WORD *pwIndices,
                              [in, out] WORD *pwCount );

I translated it as follows:

interface IWMHeaderInfo3 : IWMHeaderInfo2
 void GetAttributeIndices( [In] ushort wStreamNum,
                           [In, MarshalAs(UnmanagedType.LPWStr)] string pwszName,
                           IntPtr pwLangIndex,
                           [Out, MarshalAs(UnmanagedType.LPArray)]ushort[] pwIndices,
                           [In, Out] ref ushort pwCount );


Here, it may be preferable to translate the parameter pwLangIndex as ref ushort pwLangIndex. I used IntPtr because this parameter (the pointer value) can be NULL, and if we use the ref keyword, there is no way to pass null references.

Whenever you want to call this method and need to pass a null value, simply pass IntPtr.Zero, if you need a reference to a value then you must use a combination of GCHandle.Alloc and GCHandle.AddressOfPinnedObject. If you use these translated interfaces, you will need to do manual marshaling in many cases, so the wiser option is to write helper classes that wrap this "low level" work. That's why I wrote some helper classes to wrap INSSBuffer, IWMProfile, IWMHeaderInfo and IWMStreamConfig interfaces. In the implementation, you can find examples of how to do manual marshaling when needed.

Another important thing about translation is that in the WMF SDK, errors are handled through HRESULT. In the translated version, a COMException is thrown any time there is an error. Sometimes, we need to know the value of the returned HRESULT. In that case, you must handle the COMException and check for its ErrorCode property. The following code, which is extracted from the Read method of the WmaStream class, demonstrates how to do it:

  m_Reader.GetNextSample(m_OuputStream, out sample, out SampleTime, 
                         out Duration, out Flags, out m_OutputNumber, 
                         out m_OuputStream); 
catch (COMException e) 
  if (e.ErrorCode == WM.NS_E_NO_MORE_SAMPLES) 
    // No more samples, the stream end have been reached, there is not an error
    // Code to handle the end of the stream.
    throw (e); //Re-throw, an error that must be catch in an upper level.

Caution: There may be some errors in this translation, I didn't test all the interfaces and functions. If you plan to use this library for any serious work, you must check carefully every translated piece of code against the WMF SDK headers and documentation.

Using the code

I didn't include any demo project in the downloads, instead I'll comment here some simple examples of using the code. As part of the translation, I included a class named WmaStream that allows reading the audio stream of any ASF file and get the uncompressed PCM data out of it. As a complement, there is a class named WmaWriter that allows you to create Windows Media Audio Files from PCM audio data, this class is very similar to the WmaWriter class described in my article Windows Media Audio Compressor, but this time it is implemented in C#. You can compare both versions to get an idea of how easier is the implementation when a managed version of WMF SDK is available.

WmaStream class:

This class is derived from System.IO.Stream so it can be used as any other read-only stream. The following code shows a simple way to copy the audio content of any file that can be read by the WMF objects (*.mp3, *.wma, *.mpe, *.asf, *.wmv, etc.) to a WAV file:

using System; 
using System.IO;
using Yeti.MMedia; 
using Yeti.WMFSdk; 
using WaveLib;
using (WmaStream str = new WmaStream("Somefile.wma")) 
  byte[] buffer = new byte[str.SampleSize*2];
  AudioWriter writer = new WaveWriter(new FileStream("Somefile.wav",
    int read; 
    while ( (read = str.Read(buffer, 0, buffer.Length)) > 0) 
      writer.Write(buffer, 0, read); 
} //str.Close() is automatically called by Dispose.

WaveWriter is a BinaryWriter that creates a WAV file (or stream) from PCM data received through its Write method. The property WmaStream.Format returns a WaveFormat class describing the PCM format of the data read through its Read method. This format must be the same as the WAV file format, that's why it is passed as parameter in the WaveWriter constructor.

As another example, you can download the source code of the article A low-level Audio Player in C# by Ianier Munoz and do the following changes:

Add a reference to this library to the cswavplay project. In the file MainForm.cs, look for:

static void Main()

and change it by:

//MTA threading is needed is WMF object are planed to be used in 
//multithreaded APPs
static void Main()

In the same file, look for the method OpenFile() and change it as follows:

private void OpenFile() 
  //Add this line to open the files that can be processed by the 
  //WMF sync reader object
  OpenDlg.Filter = "Windows Media Files (*.mpe,*.wma, *.asf, *.wmv, *.mp3)
  |*.mpe; *.wma;*.asf;*.wmv;*.mp3|All files (*.*)|*.*"; 
  if (OpenDlg.ShowDialog() == DialogResult.OK) 
      //WaveLib.WaveStream S = new WaveLib.WaveStream(OpenDlg.FileName);
      //Change the previous line by this one:
      Yeti.WMFSdk.WmaStream S = new Yeti.WMFSdk.WmaStream(OpenDlg.FileName);
//The rest of the code remains the same

With those few changes, you will have a player capable of playing any ASF file and also MP3 files.

One of the lacks of the WmaStream at this moment is that it doesn't allow reading the compressed data from the ASF file. This could be useful when copying streams without recompression, merging files, etc. Anyway, extending the WmaStream to include this feature is easy.

WmaWriter class:

More details about this class can be found in my article Windows Media Audio Compressor. It has almost the same interface, the difference is that now it is implemented with the real WMF interfaces and that I added the possibility to define metadata that will be included in the final ASF stream.

The following code demonstrates how to extract the audio information from a Windows Media Video (WMV) file and write it to a Windows Media Audio file using the WmaStream and WmaWriter classes:

using System; 
using System.IO;
using Yeti.MMedia; 
using Yeti.WMFSdk; 
using WaveLib;
using (WmaStream str = new WmaStream("Somefile.wmv")) 
  byte[] buffer = new byte[str.SampleSize*2]; 
  //Extract the WMF profile from the original file
  WMProfile profile = new WMProfile(str.Profile);
  while (profile.StreamCount > 1)//Remove any non-audio stream from the profile
    WMStreamConfig config = new WMStreamConfig(profile.GetStream(0)); 
    if (config.StreamType == MediaTypes.WMMEDIATYPE_Audio) 
  System.Collections.ArrayList List = new System.Collections.ArrayList(); 
  //Check if the original file had a title
  string AttrValue = str[WM.g_wszWMTitle];
  if (AttrValue != null) 
  { //The title will be added to the destination file
    WM_Attr Attr = new WM_Attr(WM.g_wszWMTitle,
  //Check by the author metadata
  AttrValue = str[WM.g_wszWMAuthor];
  if (AttrValue != null) 
  { //The actor will be added to the destination file
    WM_Attr Attr = new WM_Attr(WM.g_wszWMAuthor,
  AudioWriter writer = new WmaWriter(new FileStream("SomeFile.wma",
    int read;
    while ( (read = str.Read(buffer, 0, buffer.Length)) > 0)
      writer.Write(buffer, 0, read);

In the previous code, I used the helper classes WMProfile and WMStreamConfig. Without them, I would have to write much more code. The WM_Attr structure is a helper structure to define metadata information in an easier way. An array of WM_Attr is passed to the WmaWriter constructor to define the metadata information that will be present in the resulting file.

The code str[WM.g_wszWMTitle] wraps the IWMHeaderInfo.GetAttributeByName functionality and returns a string representing the desired metadata attribute whose name is passed as the index value (in this case, the constant WM.g_wszWMTitle). The previous code was shown as a demonstration only, the preferred way to do the same thing is using the functionality of the WMF reader and writer objects, which allow you to read and write, respectively, compressed data samples.

There can be many examples of using the WMF. Here, I just showed some simple cases. You can find more information by looking at the implementation of the helper classes and to the comments included in the code. I didn't comment any of the WMF interfaces, structures, enumerations and functions; you can find that information in the WMF SDK documentation.


Here is an easy solution to use the WMF SDK in managed world (I've already done the dirty work). However, there are two main points you should take into account: forward compatibility and performance.

Regarding compatibility, I don't know what are the Microsoft plans about a managed version of the WMF SDK, but I guess that when they provide one, it will have many differences with the current WMF SDK.

The other problem is performance: this is not a managed version of WMF SDK, but a translation, so any time you use a method of any WMF interface, there is a COM interop operation involved. The performance penalty could be serious for real-time applications or when handling streams with video content. It is up to you to decide whether this solution suits your needs.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Idael Cardoso
Web Developer
France France
No Biography provided

You may also be interested in...

Comments and Discussions

Questionhow it will be work for other formats like .avi ,.mp4 etc Pin
ch.haya17-Jul-14 10:07
memberch.haya17-Jul-14 10:07 
GeneralLicense does not allow usage in LGPL project Pin
Yuval Naveh25-Nov-10 15:53
memberYuval Naveh25-Nov-10 15:53 
GeneralFile size inconsistency Pin
Joe Underhill21-Apr-09 5:41
memberJoe Underhill21-Apr-09 5:41 
QuestionMP3 Playback Sample Pin
Gee.21-Jan-09 11:54
memberGee.21-Jan-09 11:54 

This code looks very interesting - I have been digging through a fair bit of directsound stuff myself lately! I was wondering if you had an example that ties the WMF stream to audio playback?



GeneralExcellent Pin
dotman130-Nov-08 0:04
memberdotman130-Nov-08 0:04 
QuestionYeti.WMFSdk.WmaStream Length Pin
claudiorneves17-Oct-08 8:37
memberclaudiorneves17-Oct-08 8:37 
GeneralFound a small bug Pin
JRivord21-Sep-08 19:54
memberJRivord21-Sep-08 19:54 
Generalconvert not all the wma file but just a little sequence Pin
bouha12-Aug-08 23:20
memberbouha12-Aug-08 23:20 
QuestionHow to let hte sdk to open stream or url on internet Pin
huafengming10-Aug-08 21:00
memberhuafengming10-Aug-08 21:00 
JokeThank you a lot! Pin
RebeL-FM-22-May-08 0:45
memberRebeL-FM-22-May-08 0:45 
GeneralRe: Thank you a lot! Pin
Todd Chen14-May-09 3:54
memberTodd Chen14-May-09 3:54 
GeneralRe: Thank you a lot! Pin
PaulHuynh15-Nov-09 15:55
memberPaulHuynh15-Nov-09 15:55 
QuestionLicensing Pin
Edw19-May-08 6:22
memberEdw19-May-08 6:22 
GeneralIndexing a newly copied sample Pin
Martin Brandt16-May-08 5:07
memberMartin Brandt16-May-08 5:07 
QuestionAny example to convert wav to wma file? Pin
Gx Lam26-Mar-08 0:39
memberGx Lam26-Mar-08 0:39 
GeneralAny usage example Pin
yousefk25-Feb-08 8:08
memberyousefk25-Feb-08 8:08 
QuestionParsing ASX and ASF files. Pin
Ram Anam22-Feb-08 17:52
memberRam Anam22-Feb-08 17:52 
GeneralWMV to MP3 Pin
Lipman Roi18-Feb-08 11:00
memberLipman Roi18-Feb-08 11:00 
Questionextract as .wav from video formats other than .wmv? Pin
yuf23-Jan-08 22:34
memberyuf23-Jan-08 22:34 
QuestionWMVIDEOINFOHEADER definition ? Pin
Martin Brandt29-Dec-07 6:59
memberMartin Brandt29-Dec-07 6:59 
GeneralAttempted to read or write protected memory. This is often an indication that other memory is corrupt. Pin
circass20-Dec-07 5:01
membercircass20-Dec-07 5:01 
NewsRe: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Pin
Bobo21-Dec-07 4:18
memberBobo21-Dec-07 4:18 
GeneralRe: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. [modified] Pin
circass21-Dec-07 14:02
membercircass21-Dec-07 14:02 
GeneralRe: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Pin
circass25-Dec-07 17:12
membercircass25-Dec-07 17:12 
GeneralHi, i need help abput taking audio from wmv files Pin
circass28-Nov-07 15:53
membercircass28-Nov-07 15:53 
GeneralRe: Hi, i need help abput taking audio from wmv files Pin
Idael Cardoso3-Dec-07 12:03
memberIdael Cardoso3-Dec-07 12:03 
QuestionRe: Hi, i need help abput taking audio from wmv files Pin
Member 33391107-Dec-07 6:16
memberMember 33391107-Dec-07 6:16 
GeneralRe: Hi, i need help abput taking audio from wmv files Pin
circass7-Dec-07 15:09
membercircass7-Dec-07 15:09 
AnswerRe: Hi, i need help abput taking audio from wmv files Pin
Bobo17-Dec-07 3:41
memberBobo17-Dec-07 3:41 
GeneralRe: Hi, i need help abput taking audio from wmv files Pin
circass17-Dec-07 16:38
membercircass17-Dec-07 16:38 
QuestionHow about WMV file Codec Information ++ ? Pin
Wasia13-Sep-07 16:13
memberWasia13-Sep-07 16:13 
GeneralQuestion on WmaWriterProfileManager Pin
George_micom23-Aug-07 19:21
memberGeorge_micom23-Aug-07 19:21 
GeneralRe: Question on WmaWriterProfileManager Pin
divyesh143226-Apr-10 1:35
memberdivyesh143226-Apr-10 1:35 
Generalsdk Pin
Dzaurdy19-Jul-07 9:54
memberDzaurdy19-Jul-07 9:54 
GeneralRe: sdk Pin
Bobo14-Dec-07 4:10
memberBobo14-Dec-07 4:10 
QuestionPreprocessing? Pin
Kastellanos Nikos21-Jun-07 5:58
memberKastellanos Nikos21-Jun-07 5:58 
Generalhelpful article Pin
R Balboa16-Jun-07 23:35
memberR Balboa16-Jun-07 23:35 
QuestionTranslate WMVNetWrite to C# version? Pin
fillmorechen8-Jun-07 3:17
memberfillmorechen8-Jun-07 3:17 
QuestionC# Lessons Pin
bjvail25-Apr-07 16:27
memberbjvail25-Apr-07 16:27 
AnswerRe: C# Lessons Pin
Christian Graus25-Apr-07 17:03
staffChristian Graus25-Apr-07 17:03 
QuestionIWMCredentialCallback interface? Pin
Boek, Karel13-Apr-07 14:19
memberBoek, Karel13-Apr-07 14:19 
GeneralUrgent Question Pin
DavidR.21-Mar-07 10:00
memberDavidR.21-Mar-07 10:00 
GeneralRendering Audio in OnSample() Pin
NogginBoink18-Mar-07 16:45
memberNogginBoink18-Mar-07 16:45 
GeneralRe: Rendering Audio in OnSample() Pin
NogginBoink18-Mar-07 16:59
memberNogginBoink18-Mar-07 16:59 
Generalcast exceptions when outside debugger Pin
OscarTV12-Feb-07 3:15
memberOscarTV12-Feb-07 3:15 
GeneralRe: cast exceptions when outside debugger Pin
OscarTV12-Feb-07 5:44
memberOscarTV12-Feb-07 5:44 
Generalerror in WMFFunctions.cs Pin
Mathias Soeken12-Feb-07 0:20
memberMathias Soeken12-Feb-07 0:20 
GeneralConvert WAV to WMA Pin
mastershadows21-Nov-06 22:55
membermastershadows21-Nov-06 22:55 
QuestionIs there a way to convert WMV to WAV? Pin
anilmalak3-Nov-06 3:28
memberanilmalak3-Nov-06 3:28 
GeneralWmaReader Pin
MarcelPeek18-Oct-06 0:50
memberMarcelPeek18-Oct-06 0:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171114.1 | Last Updated 10 May 2004
Article Copyright 2004 by Idael Cardoso
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid