5,445,109 members and growing! (13,909 online)
Email Password   helpLost your password?
Multimedia » Audio and Video » Audio     Intermediate

Accessing WMF metadata with C#

By Kris Rudin

An article on how to use C# and the Windows Media Format SDK to read metadata in Windows Media Format files.
C++, C#.NET 2.0, WinXP, Windows, .NETVisual Studio, VS2005, Dev

Posted: 21 Jun 2006
Updated: 21 Jun 2006
Views: 28,501
Bookmarked: 22 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
8 votes for this Article.
Popularity: 3.88 Rating: 4.29 out of 5
1 vote, 12.5%
1
0 votes, 0.0%
2
2 votes, 25.0%
3
0 votes, 0.0%
4
5 votes, 62.5%
5

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


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

Other popular Audio and Video articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 27 (Total in Forum: 27) (Refresh)FirstPrevNext
Subject  Author Date 
QuestionVista - oh boy more Vista issues, just what I needmembergoondoo276:06 19 Jun '08  
AnswerRe: Vista - oh boy more Vista issues, just what I needmemberKris Rudin7:12 19 Jun '08  
GeneralUnable to retrieve the rating attributememberHimanshu Pokhariya23:50 23 Mar '08  
GeneralRe: Unable to retrieve the rating attributememberHimanshu Pokhariya0:03 24 Mar '08  
GeneralRe: Unable to retrieve the rating attributememberKris Rudin7:35 24 Mar '08  
GeneralHow to modify The Bitrate, Rating and Frame Width meta data of a media filememberMember 45976775:54 20 Mar '08  
GeneralRe: How to modify The Bitrate, Rating and Frame Width meta data of a media filememberKris Rudin7:18 20 Mar '08  
GeneralRe: How to modify The Bitrate, Rating and Frame Width meta data of a media filememberMember 459767720:02 20 Mar '08  
GeneralRe: How to modify The Bitrate, Rating and Frame Width meta data of a media filememberKris Rudin6:47 21 Mar '08  
Generalsetting or editing Metadata.memberMember 35409182:18 3 Mar '08  
GeneralReading FrameRatememberjeeshnair18:01 13 Jan '08  
GeneralSlow Performancemembergoondoo2713:17 9 Apr '07  
GeneralRe: Slow PerformancememberKris Rudin15:08 10 Apr '07  
GeneralTotal wrong title [modified]memberMike Novy2:01 28 Feb '07  
GeneralRe: Total wrong titlememberKris Rudin5:36 28 Feb '07  
GeneralRe: Total wrong titlememberRyan Beesley15:12 15 Sep '07  
Generalhow to add attribute with size>64kmemberHemant kulkarni4:35 7 Nov '06  
GeneralRe: how to add attribute with size>64kmemberKris Rudin7:24 7 Nov '06  
QuestionOdd charactersmemberMr Saoi6:49 26 Oct '06  
AnswerRe: Odd charactersmemberKris Rudin6:56 26 Oct '06  
GeneralRe: Odd charactersmember_C#_beginner12:39 15 Aug '07  
GeneralRe: Odd charactersmemberKris Rudin12:59 15 Aug '07  
AnswerRe: Odd characters