设置文件的元数据
在使用 IWMDMStorageControl3::Insert3 () 或在现有存储 (上调用 IWMDMStorage3::SetMetadata) 时,可以在文件写入设备之前设置元数据。 通过调用 IWMDMStorage::SetAttributes 或 IWMDMStorage2::SetAttributes2) ,只能在现有存储 (上设置属性。
通过创建并填充传递到 IWMDMStorageControl3::Insert3 的 IWMDMMetaData 接口来完成元数据设置。 但是,此方法可以清除文件上的所有现有元数据,但文件系统本身中存储的硬编码元数据(如文件名或大小)不一样。 因此,必须将要保留的所有现有元数据复制到提交的 IWMDMMetaData 接口中。 由于 Windows Media 设备管理器 不能用于从本地文件检索元数据,因此必须使用 Windows Media Format SDK (或其他一些工具) 检索此类元数据。
若要使用 Windows Media Format SDK 检索 ASF 文件属性,请执行以下步骤:
- 通过调用 WMCreateEditor 并请求 IWMMetadataEditor 接口创建元数据编辑器对象。
- 通过调用 IWMMetadataEditor::Open 打开文件以读取元数据。
- 如果文件是有效的 ASF 文件并且可以打开,请在编辑器中查询 IWMHeaderInfo 接口。
- 通过调用 IWMHeaderInfo::GetAttributeByName 并传入所需的 Windows Media Format SDK 属性常量来检索文件属性。 下表提供了具有等效 Windows Media 设备管理器 SDK 常量的格式 SDK 常量列表。
Windows Media Format SDK 常量 | Windows Media 设备管理器 SDK 常量 |
---|---|
g_wszWMTitle | g_wszWMDMTitle |
g_wszWMAuthor | g_wszWMDMAuthor |
g_wszWMAlbumTitle | g_wszWMDMAlbumTitle |
g_wszWMGenre | g_wszWMDMGenre |
g_wszWMYear | g_wszWMDMYear |
g_wszWMTrackNumber或g_wszWMTrack | g_wszWMDMTrack |
g_wszWMComposer | g_wszWMDMComposer |
g_wszWMDuration | g_wszWMDMDuration |
g_wszWMCopyright | g_wszWMDMProviderCopyright |
g_wszWMDescription | g_wszWMDMDescription |
g_wszWMBitrate | g_wszWMDMBitrate |
g_wszWMRating | g_wszWMDMUserRating |
g_wszWMAlbumArtist | g_wszWMDMAlbumArtist |
g_wszWMParentalRating | g_wszWMDMParentalRating |
g_wszWMRadioStationName | g_wszWMDMMediaStationName |
g_wszWMSubTitle | g_wszWMDMSubTitle |
g_wszWMVideoWidth | g_wszWMDMWidth |
g_wszWMVideoHeight | g_wszWMDMHeight |
g_wszWMMood | g_wszWMDMTrackMood |
g_wszWMCodec | g_wszAudioWAVECodec或g_wszVideoFourCCCodec |
以下 C++ 示例代码演示如何使用 Windows Media Format SDK 从 ASF 文件检索大量元数据属性,并将其转换为等效的 Windows Media 设备管理器值。
// Structure and array to hold equivalent Windows Media Format SDK
// and Windows Media Device Manager SDK metadata property names.
struct EquivalentProperty
{
LPCWSTR FormatSDKConst;
LPCWSTR WMDMSDKConst;
};
EquivalentProperty EquivalentProperties []=
{
{g_wszWMTitle, g_wszWMDMTitle},
{g_wszWMAuthor, g_wszWMDMAuthor},
{g_wszWMAlbumTitle, g_wszWMDMAlbumTitle},
{g_wszWMGenre, g_wszWMDMGenre},
{g_wszWMYear, g_wszWMDMYear},
{g_wszWMTrackNumber, g_wszWMDMTrack},
{g_wszWMTrack, g_wszWMDMTrack},
{g_wszWMComposer, g_wszWMDMComposer},
{g_wszWMBitrate, g_wszWMDMBitrate},
{g_wszWMDuration, g_wszWMDMDuration},
{g_wszWMCopyright, g_wszWMDMProviderCopyright},
{g_wszWMDescription, g_wszWMDMDescription},
{g_wszWMRating, g_wszWMDMUserRating},
{g_wszWMAlbumArtist, g_wszWMDMAlbumArtist},
{g_wszWMParentalRating, g_wszWMDMParentalRating},
{g_wszWMRadioStationName, g_wszWMDMMediaStationName},
{g_wszWMSubTitle, g_wszWMDMSubTitle},
{g_wszWMVideoWidth, g_wszWMDMWidth},
{g_wszWMVideoHeight, g_wszWMDMHeight},
{g_wszWMMood, g_wszWMDMTrackMood},
{g_wszWMCodec, g_wszAudioWAVECodec},
{g_wszWMCodec, g_wszVideoFourCCCodec}
};
// Function that tries to get metadata by using the Format SDK.
// If it cannot open the file, it returns E_FAIL.
HRESULT GetFileMetadataFromFormatSDK(IWMDMMetaData* pMetadata, LPCWSTR file)
{
if ((pMetaData == NULL) || (file == NULL)) return E_INVALIDPARAM;
HRESULT hr = S_OK;
CComPtr<IWMMetadataEditor> pEditor;
// Do loop to allow easy error trapping. Even if there are no errors,
// the loop executes only once.
do {
hr = WMCreateEditor(&pEditor);
if (FAILED(hr))
break;
// Open the file.
hr = pEditor->Open(file);
if (FAILED(hr))
break;
CComPtr<IWMHeaderInfo>pHeaderInfo;
hr = pEditor->QueryInterface(__uuidof(IWMHeaderInfo), (void**)&pHeaderInfo);
if (FAILED(hr))
break;
// Copy values from Format SDK to equivalent WMDM SDK metadata values.
// Loop through all known values
WORD stream = 0;
WMT_ATTR_DATATYPE wmfType;
WORD len = 0;
BYTE* value = NULL;
WMDM_TAG_DATATYPE wmdmType;
for (int i = 0; i < sizeof(EquivalentProperties) / sizeof(EquivalentProperties[0]); i++)
{
// Request each value from our equivalency list by name.
// The function is called twice: once to get the buffer size,
// and once to get the value in the allocated buffer.
if (FAILED(pHeaderInfo->GetAttributeByName(
&stream, EquivalentProperties[i].FormatSDKConst, &wmfType, NULL, &len)))
{
continue;
}
value = new BYTE[len];
if (value == NULL) continue;
if (FAILED(pHeaderInfo->GetAttributeByName(&stream, EquivalentProperties[i].FormatSDKConst, &wmfType, value, &len)))
{
delete[] value;
continue;
}
// Send the data to the equivalent WMDM metadata value.
// First, find the equivalent WMDM type for the WMF type.
switch(wmfType)
{
case WMT_TYPE_BINARY:
wmdmType = WMDM_TYPE_BINARY;
break;
case WMT_TYPE_DWORD:
wmdmType = WMDM_TYPE_DWORD;
break;
case WMT_TYPE_STRING:
wmdmType = WMDM_TYPE_STRING;
break;
case WMT_TYPE_BOOL:
wmdmType = WMDM_TYPE_BOOL;
break;
case WMT_TYPE_QWORD:
wmdmType = WMDM_TYPE_QWORD;
break;
case WMT_TYPE_WORD:
wmdmType = WMDM_TYPE_WORD;
break;
case WMT_TYPE_GUID:
wmdmType = WMDM_TYPE_GUID;
break;
default:
wmdmType = WMDM_TYPE_BINARY;
break;
}
// Don't worry about trapping errors, because there's nothing
// we can do about it.
pMetadata->AddItem(wmdmType,
EquivalentProperties[i].WMDMSDKConst, value, len);
delete[] value;
} // Add next value.
} while (FALSE); // End Do loop error trap.
// Close the file opened with IWMMetadataEditor.
pEditor->Close();
return hr;
}
以下 C++ 示例函数演示如何使用 DirectShow 获取一些文件信息并将其添加到元数据中。
// For IMediaDet, you must link to strmiids.lib. Also include the following:
//#include <Qedit.h> // for IMediaDet declaration.
//#include <Dshow.h> // for VIDEOINFOHEADER declaration.
HRESULT GetFileMetadataFromDShow(IWMDMMetaData* pMetadata, LPCWSTR file)
{
HRESULT hr = S_OK;
// Add file metadata properties from DirectShow.
// This is good for non-ASF files, or to add any information
// that the Format SDK didn't get.
// Do loop to allow easy error trapping. Even if there are no errors,
// the loop executes only once.
do
{
// Create the Media Detector object.
CComPtr<IMediaDet> pIMediaDet;
hr = pIMediaDet.CoCreateInstance(CLSID_MediaDet, NULL);
if (FAILED(hr))
break;
// Open the file.
hr = pIMediaDet->put_Filename(BSTR(file));
if (FAILED(hr))
break;
// Get the media type for the default stream.
AM_MEDIA_TYPE mediaType;
hr = pIMediaDet->get_StreamMediaType(&mediaType);
if (FAILED(hr))
break;
// We have the file open, so start requesting information from the
// Media Detector and adding it to the metadata. When adding
// individual metadata values, ignore the HRESULT, because failure
// to add these metadata values is not a breaking issue.
// Get major and minor types.
WCHAR strMediaType[64];
ZeroMemory(strMediaType, 64);
//Change the major type to a string, then add to IWMDMMetaData.
StringFromGUID2(reinterpret_cast<GUID&>(mediaType.majortype),
(LPOLESTR)strMediaType, 64);
hr = pMetadata->AddItem(WMDM_TYPE_STRING,
g_wszWMDMediaClassPrimaryID,
(BYTE*) strMediaType,
sizeof(strMediaType) / sizeof(strMediaType[0]));
// Clear local string, then retrieve subtype the same way.
ZeroMemory(strMediaType, 64);
StringFromGUID2(reinterpret_cast<GUID&>(mediaType.subtype),
(LPOLESTR)strMediaType, 64);
hr = pMetadata->AddItem(WMDM_TYPE_STRING,
g_wszWMDMMediaClassSecondaryID, (BYTE*) strMediaType,
sizeof(strMediaType) / sizeof(strMediaType[0]));
// Get the duration. Duration is retrieved in seconds, but set
// in 100-nanosecond units.
double duration = 0;
hr = pIMediaDet->get_StreamLength(&duration);
if (duration > 0)
{
duration *= 10E7;
hr = pMetadata->AddItem(WMDM_TYPE_DWORD, g_wszWMDMDuration, (BYTE*) &duration, sizeof(duration));
}
// Get the frame rate.
double frameRate = 0;
hr = pIMediaDet->get_FrameRate(&frameRate);
if (frameRate > 0)
{
hr = pMetadata->AddItem(WMDM_TYPE_DWORD, g_wszWMDMFrameRate,
(BYTE*) &frameRate,
sizeof(frameRate));
}
// Get the structure for the default stream's major type and
// fill in additional information.
if (IsEqualGUID(mediaType.formattype, FORMAT_VideoInfo))
{
VIDEOINFOHEADER* data = (VIDEOINFOHEADER*) mediaType.pbFormat;
hr = pMetadata->AddItem(WMDM_TYPE_DWORD, g_wszWMDMVideoBitrate,
(BYTE*) &data->dwBitRate, sizeof(DWORD));
hr = pMetadata->AddItem(WMDM_TYPE_DWORD, g_wszWMDMHeight,
(BYTE*) &data->bmiHeader.biHeight, sizeof(LONG));
hr = pMetadata->AddItem(WMDM_TYPE_DWORD, g_wszWMDMWidth,
(BYTE*) &data->bmiHeader.biWidth, sizeof(LONG));
}
if (IsEqualGUID(mediaType.formattype, FORMAT_WaveFormatEx))
{
WAVEFORMATEX* data = (WAVEFORMATEX*) mediaType.pbFormat;
hr = pMetadata->AddItem(WMDM_TYPE_WORD, g_wszWMDMBlockAlignment,
(BYTE*) &data->nBlockAlign, sizeof(WORD));
hr = pMetadata->AddItem(WMDM_TYPE_WORD, g_wszWMDMNumChannels,
(BYTE*) &data->nChannels, sizeof(WORD));
}
} while (FALSE); // End of error loop.
return hr;
}
相关主题