在檔案上設定中繼資料
您可以使用 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;
}
相關主題