Click here to Skip to main content
Click here to Skip to main content

Accessing WMF metadata with C#

By , 21 Jun 2006
 

Introduction

So, you want to write a C# application that can use specific Windows Media Format (WMF) metadata fields? Perhaps you want to list the title and ratings of all of the movie files you have. Fortunately, Microsoft has an SDK for Windows Media Format. However, the WMF SDK is not managed code. But, it very nicely provides a managed wrapper for metadata access. In fact, the SDK contains a complete sample program for editing WMF metadata. So, why not simply use that? Because, in my case, it was overkill for my client's needs. All I needed in this case was the ability to query a WMF file (in particular, a WMV file) to obtain author and copyright information. So, I wrote my own class, which was streamlined to work strictly with string metadata. (It can easily be modified to accommodate other data types, or to access the metadata by index instead of by name.)

Since I had need of something this simple, I thought others might, as well. In addition, this example can serve as a simple introduction to the use of WMF metadata in an application.

Background

First of all, what kind of metadata are we talking about? The WMF metadata fields are one of four data types:

  • QWORD (Quadruple word)
  • DWORD (Double word)
  • BOOL
  • STRING

For instance, here is a list of metadata attributes available in one of my test WMV files:

 Index    Name                   Stream Language Type  
 -----    ------                 ------ -------- ----  
   0      Duration                    0    0    QWORD  
   1      Bitrate                     0    0    DWORD  
   2      Seekable                    0    0     BOOL  
   3      Stridable                   0    0     BOOL  
   4      Broadcast                   0    0     BOOL  
   5      Is_Protected                0    0     BOOL  
   6      Is_Trusted                  0    0     BOOL  
   7      Signature_Name              0    0   STRING  
   8      HasAudio                    0    0     BOOL  
   9      HasImage                    0    0     BOOL  
  10      HasScript                   0    0     BOOL  
  11      HasVideo                    0    0     BOOL  
  12      CurrentBitrate              0    0    DWORD  
  13      OptimalBitrate              0    0    DWORD  
  14      HasAttachedImages           0    0     BOOL  
  15      Can_Skip_Backward           0    0     BOOL  
  16      Can_Skip_Forward            0    0     BOOL  
  17      FileSize                    0    0    QWORD  
  18      HasArbitraryDataStream      0    0     BOOL  
  19      HasFileTransferStream       0    0     BOOL  
  20      WM/ContainerFormat          0    0    DWORD  
  21      Title                       0    0   STRING  
  22      Author                      0    0   STRING  
  23      Copyright                   0    0   STRING  
  24      Description                 0    0   STRING  
  25      Rating                      0    0   STRING  
  26      BannerImageURL              0    0   STRING  
  27      CopyrightURL                0    0   STRING  
  28      WMFSDKVersion               0    0   STRING  
  29      WMFSDKNeeded                0    0   STRING  
  30      IsVBR                       0    0     BOOL  
  31      WM/AlbumTitle               0    0   STRING  
  32      WM/Track                    0    0   STRING  
  33      WM/PromotionURL             0    0   STRING  
  34      WM/AlbumCoverURL            0    0   STRING  
  35      WM/Genre                    0    0   STRING  
  36      WM/Year                     0    0   STRING  
  37      WM/GenreID                  0    0   STRING  
  38      WM/Composer                 0    0   STRING  
  39      WM/Lyrics                   0    0   STRING  
  40      WM/ToolName                 0    0   STRING  
  41      WM/ToolVersion              0    0   STRING  
  42      WM/AlbumArtist              0    0   STRING  
  43      WM/AuthorURL                0    0   STRING  
  44      WM/AudioFileURL             0    0   STRING  
  45      WM/Language                 0    0   STRING  
  46      WM/ParentalRating           0    0   STRING  
  47      WM/BeatsPerMinute           0    0   STRING  
  48      WM/InitialKey               0    0   STRING  
  49      WM/Mood                     0    0   STRING  
  50      WM/DVDID                    0    0   STRING  
  51      WM/UniqueFileIdentifier     0    0   STRING  
  52      WM/ModifiedBy               0    0   STRING  
  53      WM/RadioStationName         0    0   STRING  
  54      WM/RadioStationOwner        0    0   STRING  
  55      WM/PlaylistDelay            0    0   STRING  
  56      WM/Codec                    0    0   STRING  
  57      WM/DRM                      0    0   STRING  
  58      WM/ISRC                     0    0   STRING  
  59      WM/Provider                 0    0   STRING  
  60      WM/ProviderRating           0    0   STRING  
  61      WM/ProviderStyle            0    0   STRING  
  62      WM/ContentDistributor       0    0   STRING  
  63      WM/SubscriptionContentID    0    0   STRING  
  64      WM/ASFPacketCount           0    0    QWORD  
  65      WM/ASFSecurityObjectsSize   0    0    QWORD

As you can see, there can be a lot of attributes available! However, it's important to note that not all files contain the same attribute list. Be sure that the file you're interrogating has the field you are asking for. If it doesn't, the query will return an error: Exception from HRESULT: 0xC00D07F0 or Exception from HRESULT: 0xC00D001D.

Using the code

Since the managed wrapper is Microsoft's code, and part of the WMF SDK, I'm not including it as a download with this article. But you can download the SDK from MSDN. Once you install it, find the "Managed" directory, (for the default installation, it will be: C:\WMSDK\WMFSDK95\samples\managed\). Under that directory, you'll find the wrapper project. The simplest way to use it is to import that project into your Visual Studio solution, then add a reference to that project in your main application project. Now, import my MetaDataReader class file into your main project, and use the GetFieldByName method to retrieve the value of your desired metadata field.

Here's the MetaDataReader class:

using System;
using System.Collections.Generic;
using System.Text;
using WMFSDKWrapper;
//managed wrapper to WMF SDK -
//        provides access to metadata

namespace MyNamespace
{

    /// This class contains the functionality
    /// for handling interaction with the media file
    /// metadata, via the WMF SDK managed wrapper class.
    public class MetaDataReader
    {

        /// Default constructor
        public MetaDataReader()
        {
        }

        /// Method to obtain a metadata attribute by passing in its name. 
        /// Assumes the metadata type is STRING.
        /// Uses the SDK function GetAttributeByName.
        ///
        /// param name="filename" - the filename
        ///            (including path) of media file to interrogate
        /// param name="attrName" - the name of the field we're looking for
        /// returns - the value of the named attribute,
        ///           empty string if not found, or error message
        public string GetFieldByName(string fileName, string attrName)
        {
            try
            {
                //object used to access WMF file 
                IWMMetadataEditor MetadataEditor;
                //object to use access metadata 
                IWMHeaderInfo3 HeaderInfo3;
                //media stream to interrogate
                ushort streamNum = 0;
                //data type of attribute
                WMT_ATTR_DATATYPE wAttribType;
                //value of attribute (as returned by method call)
                byte[] pbAttribValue = null;
                //length of attribute (byte array)
                ushort wAttribValueLen = 0;

                WMFSDKFunctions.WMCreateEditor(out MetadataEditor);

                MetadataEditor.Open(fileName);

                HeaderInfo3 = (IWMHeaderInfo3)MetadataEditor;

                //make call to get attribute length
                HeaderInfo3.GetAttributeByName(ref streamNum, attrName, 
                  out wAttribType, pbAttribValue, ref wAttribValueLen);
                //set byte array length
                pbAttribValue = new byte[wAttribValueLen];
                //make call again, which will get value 
                //into correct-length byte array
                HeaderInfo3.GetAttributeByName(ref streamNum, 
                                               attrName, out wAttribType, 
                                               pbAttribValue, 
                                               ref wAttribValueLen);

                MetadataEditor.Close();

                return ConvertAttrToString(pbAttribValue, 
                                           wAttribValueLen);
            }
            catch (Exception e)
            {
                return "ERROR: " + e.Message;
            }
        }//end method

        /// Method to convert byte array value into string. 
        /// (From the Microsoft WMF SDK sample.)
        ///
        /// param name="pbValue" - byte array value of attribute
        /// param name="dwValueLen" - Length of byte array
        private string ConvertAttrToString(byte[] pbValue, ushort dwValueLen)
        {
            string Value = "";

            if (0 == dwValueLen)
            {
                Value = "";
            }
            else
            {
                if ((0xFE == Convert.ToInt16(pbValue[0])) &&
                     (0xFF == Convert.ToInt16(pbValue[1])))
                {
                    Value = "UTF-16LE BOM+";

                    if (4 <= dwValueLen)
                    {
                        for (int i = 0; i < pbValue.Length - 2; i += 2)
                        {
                            Value += 
                              Convert.ToString(BitConverter.ToChar(pbValue, i));
                        }
                    }
                }
                else if ((0xFF == Convert.ToInt16(pbValue[0])) &&
                          (0xFE == Convert.ToInt16(pbValue[1])))
                {
                    Value = "UTF-16BE BOM+";
                    if (4 <= dwValueLen)
                    {
                        for (int i = 0; i < pbValue.Length - 2; i += 2)
                        {
                            Value += 
                              Convert.ToString(BitConverter.ToChar(pbValue, i));
                        }
                    }
                }
                else
                {
                    Value = "";
                    if (2 <= dwValueLen)
                    {
                        for (int i = 0; i < pbValue.Length - 2; i += 2)
                        {
                            Value += 
                              Convert.ToString(BitConverter.ToChar(pbValue, i));
                        }
                    }
                }
            }//end else not a 0-length string

            return Value;
            
        }//end method

    }//end class
}

Here's a code snippet of a sample call:

MetaDataReader objMetaData = new MetaDataReader();
string Author = objMetaData.GetAttrByName("C:\Videos\MyVideo.wmv", "Author");

That's it! I hope this simple example will provide the basics you need for writing some cool apps that access the WMF metadata.

History

  • 06.20.06 - Initial version.

License

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

Kris Rudin
Web Developer
United States United States
Member
Kris Rudin is a senior developer with Ascentium corporation, with 10 years of experience including both web and Windows client software development.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionAccess the metadata of different types of filememberEricckWu30 Jan '12 - 19:17 
Thank you for the great code firstly. And do you have any suggestion for me to access the metadata of different types of file?
For example, if I want to access Bitrate of a *.mp4 or *.avi file, the SDK seems not allow me to do this. The return of GetFieldByName will be incorrect. So I am very grateful if you can provide some ideas, thank you so much!
AnswerRe: Access the metadata of different types of filememberKris Rudin31 Jan '12 - 6:37 
First off, I'm glad you found the article helpful. But this article is VERY old, and there are no doubt newer libraries and SDK's out there. Many of these may have the functionality you need. I would do an internet search for the functionality you want, to find something newer and more robust. Good luck!
GeneralRe: Access the metadata of different types of filememberEricckWu31 Jan '12 - 15:01 
Thank you so much for your help! I will also do other research for this issue. Once I have new findings, I will share it on this thread. Look forword to hearing good news from you.
Sincerely.
QuestionMacintoshmemberdejan19dejan1920 Sep '11 - 1:01 
And does someone know how to get video resolution (frame width and height) that will work on Macintosh?
AnswerRe: Macintosh [modified]memberdejan19dejan1920 Sep '11 - 21:39 
Can I use some kind of a ffmpeg mono wrapper to convert videos?

modified on Wednesday, September 21, 2011 6:09 AM

GeneralKeeping Handle after call of GetFieldByNamemembergl_media27 Dec '10 - 7:37 
Hi,
 
great! You can also use it for mp3s.
 
I found that GetFieldByName does not close the handle on the file in some times. I put the MetaDataEditor.Close() in a "finally" block and it seems that the problem disappeared?
 
Someone here to explain what is happening?
QuestionShall You Upload this code in VB?memberPeter Farago8 Jan '10 - 0:09 
Dear Kris,
 
I am a student from Hungary and I read your code about titled "Accessing WMF metadata with C#". I think this is a very very good application that you was writing, but I have a problem: I don't programming with C# and I only have Visual Basic 2005 or 2008. Shall you programming this application with VB, because I need this program as a plug-in for my exam.
 
Yours faithfully,
Peter Farago
Student, From Hungary
 
08 January, 2010.
AnswerRe: Shall You Upload this code in VB?memberKris Rudin8 Jan '10 - 6:03 
Peter,
The functionality in VB will be the same as in C#. Just translate what's happening in C# into VB. (A student should be able to see code in one language, and be able to translate it to another - especially code that is very straight-forward, as this one is.) I bet that if you looked closely at the code, you'd be able to see what it's doing, and then write it in VB. Just take it step by step.
Smile | :)
GeneralNot able to read WM/Codec attribute from a .wmv file..memberbalagopalabcd21 Oct '08 - 17:54 
Iam able to read properties like title, author etc but iam not able to read WM/Codec attribute.It returns null in size parameter of GetAttributebyName().
can any one help me Smile | :)
 
Thanks in advance..
QuestionVista - oh boy more Vista issues, just what I needmembergoondoo2719 Jun '08 - 5:06 
This code works great on XP. I play a .wma file using an embedded WMP11 player and change the meta data at will. Now on Vista it's a whole new ball game. I can only set the meta data when the .wma file is not playing (or even referenced by the WMP11 player). Any idea on how to "fix" this for Vista?
 
Thanks for the great code.
AnswerRe: Vista - oh boy more Vista issues, just what I needmemberKris Rudin19 Jun '08 - 6:12 
*sigh* Sorry - I don't have any idea. I haven't had to target anything for Vista yet, so I don't know what the tricks are. If you figure it out, do reply, so that others can benefit from your experience. Good luck!
GeneralUnable to retrieve the rating attributememberHimanshu Pokhariya23 Mar '08 - 22:50 
I am executing the following line:
 
string rating = MetaDataReader.GetFieldByName("C:\\Users\\himanp\\M3Shared\\z.wma", "Rating");
 
After execution, the value of the above string is "ERROR: Exception from HRESULT: 0xC00D07F0"
 
Your article mentions - "Be sure that the file you're interrogating has the field you are asking for. If it doesn't, the query will return an error: Exception from HRESULT: 0xC00D07F0 or Exception from HRESULT: 0xC00D001D."
 
I have checked that and the rating field is definitely present in my file z.wma.
 
Any suggestions?
GeneralRe: Unable to retrieve the rating attributememberHimanshu Pokhariya23 Mar '08 - 23:03 
I tried with a different audio file. This the string returned by the method was:
"ERROR: Exception from HRESULT: 0xC00D07F0"
 
(While in my code, the error code mentioned is "0xC00D001D")
GeneralRe: Unable to retrieve the rating attributememberKris Rudin24 Mar '08 - 6:35 
What version of WMV is your file? This SDK is for an older version than what is out currently. Don't know what else it could be.
QuestionHow to modify The Bitrate, Rating and Frame Width meta data of a media filememberMember 459767720 Mar '08 - 4:54 
For Bitrate we tryed with below code.
result = MetadataEdit.SetAttrib("The Trooper.wmv", wStreamNum, "Bitrate", wAttribType, "2011");
 
Got error like "Value does not fall within the expected range."
 
Please help me in this.
AnswerRe: How to modify The Bitrate, Rating and Frame Width meta data of a media filememberKris Rudin20 Mar '08 - 6:18 
Verify that wAttribType has the correct value (should be 0 for a DWord).
Verify that wStreamNum has the correct value - different attributes are available for different streams, so make sure the stream you are using has the bitrate attribute. Those are the 1st things I'd verify. Good luck.
GeneralRe: How to modify The Bitrate, Rating and Frame Width meta data of a media filememberMember 459767720 Mar '08 - 19:02 
I tried with correct input value, still not able to get or set the value of following attributes
Bitrate, Rating, Frame width, Frame height
 
Can you help me in this?
GeneralRe: How to modify The Bitrate, Rating and Frame Width meta data of a media filememberKris Rudin21 Mar '08 - 5:47 
What type of media file is this? What version of the SDK? I don't know what else to check, because I didn't do anything with setting values, only reading them. Good luck.
Generalsetting or editing Metadata.memberMember 35409183 Mar '08 - 1:18 
Hi,
 
How can we make use of SDK functions to Set and Edit Metadata like 'Title' and 'Author'.if any body has got any idea on this issue please feel free to share it.
 
Regards,
Ani
GeneralReading FrameRatememberjeeshnair13 Jan '08 - 17:01 
Hi,
 
Although simple attributes seems to be read. Attributes like Framerate,Aspectratio does not get read?
What is the way to read them?
 
Regards
Jeesh Nair
GeneralSlow Performancemembergoondoo279 Apr '07 - 12:17 
First off, thanks for a great article! I've written a simple display window that reads *.wma file attributes and displays them to a window. It works fine, but the performance is pretty slow when the number of files gets close to 1000. The bottle neck seems to be in the GetFieldByName() routine. Have you done anything with increasing the performance of this otherwise great code?
 
Thanks,
John

GeneralRe: Slow PerformancememberKris Rudin10 Apr '07 - 14:08 
John,
 
Glad you found the article useful. Unfortunately, I haven't done any more work with the code (I got moved to another project). The GetFieldByName() method uses calls to the SDK methods, which could be the cause of the slow-down. I'd be interested in hearing from you if you do find a way to increase the performance. Then I can update the sample, and give you the credit for the improvement. Smile | :)
 
Kris
GeneralTotal wrong title [modified]memberMike Novy28 Feb '07 - 1:01 
You named your project completely wrong: WMF (vector based gfx: windows meta FILE) and WMV (VIDEO) are completly different things.
 

-- modified at 7:16 Wednesday 28th February, 2007
GeneralRe: Total wrong titlememberKris Rudin28 Feb '07 - 4:36 
Gee, I guess I called it WMF because that's what Microsoft called it. It's the "WMF wrapper" class by them, in their code and on their website.
GeneralRe: Total wrong titlememberRyan Beesley15 Sep '07 - 14:12 
Microsoft has the sometimes annoying habit of recycling product names, code names, and acronyms. WMF in this case stands for Windows Media Format and while it does in fact cover WMV (Video), this article and the associated SDK also equally applies to WMA (Audio).

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 21 Jun 2006
Article Copyright 2006 by Kris Rudin
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid