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;
namespace MyNamespace
{
public class MetaDataReader
{
public MetaDataReader()
{
}
public string GetFieldByName(string fileName, string attrName)
{
try
{
IWMMetadataEditor MetadataEditor;
IWMHeaderInfo3 HeaderInfo3;
ushort streamNum = 0;
WMT_ATTR_DATATYPE wAttribType;
byte[] pbAttribValue = null;
ushort wAttribValueLen = 0;
WMFSDKFunctions.WMCreateEditor(out MetadataEditor);
MetadataEditor.Open(fileName);
HeaderInfo3 = (IWMHeaderInfo3)MetadataEditor;
HeaderInfo3.GetAttributeByName(ref streamNum, attrName,
out wAttribType, pbAttribValue, ref wAttribValueLen);
pbAttribValue = new byte[wAttribValueLen];
HeaderInfo3.GetAttributeByName(ref streamNum,
attrName, out wAttribType,
pbAttribValue,
ref wAttribValueLen);
MetadataEditor.Close();
return ConvertAttrToString(pbAttribValue,
wAttribValueLen);
}
catch (Exception e)
{
return "ERROR: " + e.Message;
}
}
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));
}
}
}
}
return Value;
}
}
}
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.