Tag Support API
The Tag Support API allows developers to write their own tag support for a format that's not supported yet by WMP Tag Plus. This support needs to be implemented in a DLL, which, when it's properly registered, will be loaded and called by WMP Tag Plus. This will in turn allow Windows Media Player to read and write the tags of a new format. The API explained on this page is the interface between WMP Tag Pus and such a tag support DLL.
Of course, you could also read this API contract from the other side, and apply it to write an application or plug-in that calls existing tag support DLLs. In this case, please note that you are not allowed to separately distribute the tag support DLLs included in the WMP Tag Plus package. Contact the author by e-mail for more information.
This API is loosely based on the WMP Tag Support Extender API, but there are a lot of fundamental differences because WMP Tag Support Extender and WMP Tag Plus use totally different techniques to integrate into Windows Media Player.
Various parts of the Tag Support API header file, WMPTagPlusAPI.h
, are given and explained here. The full version of this file is included in the WMP Tag Plus SDK, which can be downloaded below. By means of example, this SDK also includes the full source of the MPEG-4 tag support used by WMP Tag Plus.
Before you start working on your own tag support, it is recommended that you notify the author of WMP Tag Plus of this. This is mainly to prevent that two different people are working on tag support for the same format at the same time. You can find the author's e-mail address on the About-tab of WMP Tag Plus' properties, or on the BM-productions website.
Tags
Each supported tag has a corresponding data type. The possible data types are defined in the TAG_DATATYPE
enum in WMPTagPlusAPI.h
:
typedef enum _TAG_DATATYPE { MT_DATATYPE_STRING, MT_DATATYPE_INT, MT_DATATYPE_BINARY, MT_DATATYPE_REMOVE, } TAG_DATATYPE;
Currently, there isn't any tag that has the MT_DATATYPE_BINARY
type. This type is reserved for future use.
MT_DATATYPE_REMOVE
is a special data type that will only be set when writing tags. It indicates that the tag should be completely removed from the media file.
The following tags are defined in WMPTagPlusAPI.h
:
#define WMPTAG_AUTHOR 0 // MT_DATATYPE_STRING #define WMPTAG_AVERAGELEVEL 1 // MT_DATATYPE_INT #define WMPTAG_COPYRIGHT 2 // MT_DATATYPE_STRING #define WMPTAG_AVERAGEBITRATE 3 // MT_DATATYPE_INT (read-only) #define WMPTAG_DURATION 4 // MT_DATATYPE_INT (read-only) #define WMPTAG_FILESIZE 5 // MT_DATATYPE_INT (read-only) #define WMPTAG_HASAUDIO 6 // MT_DATATYPE_INT (read-only) #define WMPTAG_HASVIDEO 7 // MT_DATATYPE_INT (read-only) #define WMPTAG_IS_PROTECTED 8 // MT_DATATYPE_INT (read-only) #define WMPTAG_PEAKVALUE 9 // MT_DATATYPE_INT #define WMPTAG_TITLE 10 // MT_DATATYPE_STRING #define WMPTAG_ALBUMARTIST 11 // MT_DATATYPE_STRING #define WMPTAG_ALBUMTITLE 12 // MT_DATATYPE_STRING #define WMPTAG_CATEGORY 13 // MT_DATATYPE_STRING #define WMPTAG_COMPOSER 14 // MT_DATATYPE_STRING #define WMPTAG_CONDUCTOR 15 // MT_DATATYPE_STRING #define WMPTAG_CONTENTDISTRIBUTOR 16 // MT_DATATYPE_STRING #define WMPTAG_CONTENTGROUPDESC 17 // MT_DATATYPE_STRING #define WMPTAG_DIRECTOR 18 // MT_DATATYPE_STRING #define WMPTAG_ENCODINGTIME 19 // MT_DATATYPE_INT #define WMPTAG_GENRE 20 // MT_DATATYPE_STRING #define WMPTAG_GENREID 21 // MT_DATATYPE_STRING #define WMPTAG_INITIALKEY 22 // MT_DATATYPE_STRING #define WMPTAG_LANGUAGE 23 // MT_DATATYPE_STRING #define WMPTAG_MOOD 24 // MT_DATATYPE_STRING #define WMPTAG_PARENTALRATING 25 // MT_DATATYPE_STRING #define WMPTAG_PARTOFSET 26 // MT_DATATYPE_STRING #define WMPTAG_PERIOD 27 // MT_DATATYPE_STRING #define WMPTAG_PROVIDER 28 // MT_DATATYPE_STRING #define WMPTAG_PROVIDERRATING 29 // MT_DATATYPE_STRING #define WMPTAG_PROVIDERSTYLE 30 // MT_DATATYPE_STRING #define WMPTAG_PUBLISHER 31 // MT_DATATYPE_STRING #define WMPTAG_SHAREDUSERRATING 32 // MT_DATATYPE_INT #define WMPTAG_SUBTITLE 33 // MT_DATATYPE_STRING #define WMPTAG_TRACKNUMBER 34 // MT_DATATYPE_STRING #define WMPTAG_WRITER 35 // MT_DATATYPE_STRING #define WMPTAG_YEAR 36 // MT_DATATYPE_STRING #define WMPTAG_LYRICS 37 // MT_DATATYPE_STRING #define WMPTAG_DESCRIPTION 38 // MT_DATATYPE_STRING #define WMPTAG_ISRC 39 // MT_DATATYPE_STRING #define WMPTAG_ENCODEDBY 40 // MT_DATATYPE_STRING #define WMPTAG_MODIFIEDBY 41 // MT_DATATYPE_STRING #define WMPTAG_PRODUCER 42 // MT_DATATYPE_STRING #define WMPTAG_BPM 43 // MT_DATATYPE_STRING
The corresponding data type is denoted next to each tag in comments. After having read tags from file, the tags that you pass to WMP Tag Plus with an incorrect data type will be ignored. While writing, you can assume that the tags passed to your tag support by WMP Tag Plus will have the correct data type.
Read-only tags are also indicated in the comments. These can only be passed to WMP Tag Plus while reading, and will never be used while writing.
Each of the tags above corresponds to a predefined attribute in the Windows Media Format SDK. This relation is shown in the static WMPTagNames
array:
static const char* WMPTagNames [] = { "Author", "AverageLevel", "Copyright", "CurrentBitrate", "Duration", "FileSize", "HasAudio", "HasVideo", "Is_Protected", "PeakValue", "Title", "WM/AlbumArtist", "WM/AlbumTitle", "WM/Category", "WM/Composer", "WM/Conductor", "WM/ContentDistributor", "WM/ContentGroupDescription", "WM/Director", "WM/EncodingTime", "WM/Genre", "WM/GenreID", "WM/InitialKey", "WM/Language", "WM/Mood", "WM/ParentalRating", "WM/PartOfSet", "WM/Period", "WM/Provider", "WM/ProviderRating", "WM/ProviderStyle", "WM/Publisher", "WM/SharedUserRating", "WM/SubTitle", "WM/TrackNumber", "WM/Writer", "WM/Year", "WM/Lyrics", "Description", "WM/ISRC", "WM/EncodedBy", "WM/ModifiedBy", "WM/Producer", "WM/BeatsPerMinute" };
If you are not sure about the specific format or meaning of a tag in the Tag Support API, you can refer to the Windows Media Format SDK Attribute List. The information given there will apply to the WMPTAG_
tag as well (with one exception: WMPTAG_GENREID
).
While the official WM/GenreID
documentation states that the tag can contain an ID3 genre ID in parentheses, followed by a refinement, WMPTAG_GENREID
should just contain a ID3 genre ID (without parentheses). WMP Tag Plus processes/generates WMPTAG_GENREID
as follows:
- Reading: after you have read and passed the tag to WMP Tag Plus, the parentheses are automatically added (and the value is passed to Windows Media Player).
- Writing:
- When Windows Media Player wants to write
WM/GenreID
, WMP Tag Plus will parse the value into aWMPTAG_GENRE
andWMPTAG_GENREID
tag, and pass these to your tag support. - When Windows Media Player wants to write
WM/Genre
, WMP Tag Plus will try to match the genre with an ID3 genre ID, and add aWMPTAG_GENREID
tag, on top of aWMPTAG_GENRE
tag. Genre ID 12 (Other) will be used if no such match is found.
- When Windows Media Player wants to write
WMPTAG_FILESIZE
is already handled by WMP Tag Plus itself and will be set to the file size of the media file. As a result, you generally don't need to handle this tag in your tag support.
Tag Structures
Each tag that is passed to/from your tag support, together with its value, will be stored in a WMPTP_TAG
structure:
/** memory container for a tag and its value */ typedef struct _WMPTP_TAG { UINT tagId; /** identifies the tag, see WMPTAG_* */ UINT tagIndex; /** index of the tag, for tags with multiple values */ TAG_DATATYPE valueDataType; /** data type of the tag's value */ union { LPWSTR stringValue; /** string value of the tag, if ValueDataType == MT_DATATYPE_STRING */ DWORD64 intValue; /** integer value of the tag, if ValueDataType == MT_DATATYPE_INT */ struct { DWORD dataLength; /** length of binary data */ BYTE* data; /** pointer to binary data */ } binaryValue; /** binary data value of the tag, if ValueDataType == MT_DATATYPE_BINARY */ } value; /** the tag's value */ } WMPTP_TAG; typedef WMPTP_TAG *PWMPTP_TAG;
The tagIndex
member is reserved for future use and should be set to 0. Future WMP Tag Plus versions might use it to support tags containing multiple values.
The tags are grouped together in a WMPTP_TAGLIST
structure:
/** memory container for a list of tags (WMPTP_TAG) */ typedef struct _WMPTP_TAGLIST { UINT numTags; /** number of tags */ PWMPTP_TAG items; /** pointer to the first element of an array of tags */ } WMPTP_TAGLIST; typedef WMPTP_TAGLIST *PWMPTP_TAGLIST;
When reading tags, WMP Tag Plus will allocate an empty WMPTP_TAGLIST
structure for your tag support to fill in. However, the WMPTP_TAGLIST.items
, WMPTP_TAG.value.stringValue
and WMPTP_TAG.value.binaryValue.data
members need to be allocated by your tag support. These should be allocated on the process heap, using the HeapAlloc and HeapReAlloc Windows API functions. When WMP Tag Plus has finished processing the tags that were passed to it by your tag support, it will free these members with HeapFree.
To prevent you from having to worry about this allocation, you can use the following helper functions while reading tags. These are defined in WMPTagPlusAPI.h
and implemented in WMPTagPlusAPI.cpp
:
void InitTagList(PWMPTP_TAGLIST tags); PWMPTP_TAG AddTag(PWMPTP_TAGLIST tags); void AddWideStringTag(PWMPTP_TAGLIST tags, UINT wmpTag, const WCHAR* value); void AddStringTag(PWMPTP_TAGLIST tags, UINT wmpTag, const char* value); void AddIntTag(PWMPTP_TAGLIST tags, UINT wmpTag, DWORD64 value);
Read and Write Functions
Now that the tags themselves and tag structures have been explained, it's time to head to the heart of your tag support: the read and write functions.
First of all, you should give your tag support a name. This name should be the name of the format that you're adding support for, without any spaces or other special characters. A good example is MPEG4
. Make sure that this name doesn't conflict with any existing tag support formats, especially with the ones included with WMP Tag Plus. From now on, this tag support name (or format) will be referred to as <TagFormat>
.
You are now ready to implement and export the actual read and write functions in your tag support DLL, as follows:
BOOL WMPTP_API WMPTagPlusRead<TagFormat>Tags(LPCWSTR filename, PWMPTP_TAGLIST tags) BOOL WMPTP_API WMPTagPlusWrite<TagFormat>Tags(LPCWSTR filename, PWMPTP_TAGLIST tags)
If the supplied filename can't be opened, or doesn't point to a valid media file of your tag support format, return FALSE
. Otherwise, if the tags have been read/written correctly, return TRUE
. Returning FALSE
is important in case the media file has a different format than the format that your tag support expects. If the extension of the file is registered with other tag support implementation than yours, returning FALSE
will cause WMP Tag Plus to try these other implementations as well, until the read/write function of an implementation has returned TRUE
. This is to properly support file extensions that can represent more than one format or tag format.
A common implementation of WMPTagPlusRead<TagFormat>Tags
opens the specified file and initializes the tags
parameter. Next, each tag that is present in the file and supported by the API, is added to tags
. Finally, the file is closed.
A common implementation of WMPTagPlusWrite<TagFormat>Tags
opens the specified file (for writing), loops through all the tags in the tags
parameter, saves each tag to the file (or possibly removes it). Finally, the changes are flushed to the file and it is closed.
The read function is required, but the write function isn't. If the write function isn't exported by your tag support DLL, WMP Tag Plus will still use the DLL for read-only tag support. However, leaving out write support is not recommended.
Capabilities
After implementing the read and write functions, it's recommended that you add a simple capabilities function too. This function allows WMP Tag Plus to query your tag support about some of its specific read and write capabilities.
The capabilities function should have the following prototype:
UINT WMPTP_API WMPTagPlusGet<TagFormat>Capabilities(void)
The return value of this function should be a combination of the following values, depending on whether your tag support implementation supports reading/writing of the WMPTAG_DESCRIPTION
and WMPTAG_LYRICS
tags:
#define WMPTP_CAPABILITIES_READ_DESCRIPTION 0x00000001 #define WMPTP_CAPABILITIES_WRITE_DESCRIPTION 0x00000002 #define WMPTP_CAPABILITIES_READ_LYRICS 0x00000004 #define WMPTP_CAPABILITIES_WRITE_LYRICS 0x00000008
This function's implementation can be one simple return-statement, nothing more is usually required.
WMP Tag Plus or other plug-ins can use the returned value to provide a better user experience. For example, consider a tag editor that has a separate page for editing the lyrics of a song. The tag editor might decide to hide this page if the capabilities function of the used tag support indicates that lyrics editing isn't possible.
Initialization and Cleanup
If you need to do any one-time initialization in your tag support DLL, such as loading dependencies or allocating and initializing global data structures, you can do so in the initialization function (optional):
BOOL WMPTP_API WMPTagPlusInitialize(void)
This function is guaranteed to be called first by WMP Tag Plus, before any other functions. You can return FALSE
, this will cause WMP Tag Plus not to call any more functions of the DLL. Returning FALSE
usually means that there was an error while initializing, for example, when a required dependency failed to load. Return TRUE
if initialization was successful.
Likewise, you can use the uninitialization function for any cleanup that needs to be done before your DLL is unloaded (optional):
void WMPTP_API WMPTagPlusUninitialize(void)
Note that the uninitialization function will not be called if the initialization function has returned FALSE
.
Both the initialization and uninitialization functions are global and not bound to a single tag support format. The initialization and uninitialization functions of a single DLL implementing tag support for multiple formats will still be called only once.
Registration
For WMP Tag Plus to be able to find and load your tag support DLL, the DLL needs to be registered. This can be done by adding a few specific keys and values to the registry. Usually, the registration will happen during installation of your tag support. There is no user interface that allows users to register or unregister tag support DLLs themselves. They can, however, disable DLLs and edit the list of file extensions that are handled by a DLL.
To register your tag support DLL, create the following subkey:
HKEY_LOCAL_MACHINE\Software\BM-productions\WMP Tag Plus\Formats\<TagFormat>
Then, create the following entries (values) in this new subkey:
Name | Type | Value |
---|---|---|
(Default) |
REG_SZ |
The full path to the DLL file that implements your tag support. |
Enabled |
REG_DWORD |
1
|
Next, create the following subkey:
HKEY_LOCAL_MACHINE\Software\BM-productions\WMP Tag Plus\Formats\<TagFormat>\Extensions
For each file extension that will be handled by your tag support DLL, add a new REG_SZ
entry to this Extensions
subkey. The name of this entry should be the actual extension, without the preceding period character. The value of the entry itself is ignored and can be left empty.
Testing
During and right after the development of a tag support, you can use the TagSupportTest
sample application to test your implementation. This sample is included in the WMP Tag Plus SDK (see below).
When your tag support implementation has become stable enough, you should also test it with WMP Tag Plus itself, inside Windows Media Player. First, add a single media file of the new format to the media library, and check if all tags have been read correctly. Then, edit each tag that can be written by your tag support, and verify that all the changes are written to file.
You should also copy a whole collection of files of the new format (such as a full album) to your music folder in one go. Again, verify that all tags have been read correctly. Finally, test your tag support implementation on a library with at least 1.000 files of the new format.
SDK
The WMP Tag Plus SDK contains the following:
- The Tag Support API header file,
WMPTagPlusAPI.h
, together with the accompanyingWMPTagPlusAPI.cpp
file, in which the helper functions are implemented.
- The Delphi version of the Tag Support API header:
WMPTagPlusAPI.pas
.
- The (unmodified) VC++ source code of the MPEG-4 tag support that is used by WMP Tag Plus. This tag support implementation utilizes the MP4v2 library, which is also included. The code can be used as an example for other tag support implementations.
- The VC++ source code of the
TagSupportTest
sample application. This is a console application that loads and calls a specific tag support DLL for outputting all the tags in a media file. This application can help you with testing your own tag support implementation. Be careful when supplying thewrite
orremove
switches, as these will respectively alter or remove all the tags of a file.
The MPEG-4 tag support (not including MP4v2) is licensed under the BSD License. All other source code in the WMP Tag Plus SDK is public domain.
Download the WMP Tag Plus SDK (version 1.2)