Definindo metadados em um arquivo
Você pode definir metadados em um arquivo antes de escrevê-lo no dispositivo (ao usar IWMDMStorageControl3::Insert3) ou em um armazenamento existente (chamando IWMDMStorage3::SetMetadata). Você pode definir atributos somente em um armazenamento existente (chamando IWMDMStorage::SetAttributes ou IWMDMStorage2::SetAttributes2).
A configuração de metadados é feita criando e preenchendo uma interface IWMDMetaData que é passada para IWMDMStorageControl3::Insert3. No entanto, esse método pode limpar todos os metadados existentes no arquivo, além de metadados embutidos em código armazenados no próprio sistema de arquivos, como nome ou tamanho do arquivo. Portanto, você deve copiar todos os metadados existentes que deseja reter na interface IWMDMMetaData enviada. Como o Windows Media Gerenciador de Dispositivos não pode ser usado para recuperar metadados de arquivos locais, você deve usar o SDK do Windows Media Format (ou alguma outra ferramenta) para recuperar esses metadados.
Para usar o SDK do Windows Media Format para recuperar as propriedades do arquivo ASF, siga estas etapas:
- Crie um objeto editor de metadados chamando WMCreateEditor e solicitando uma interface IWMMetadataEditor .
- Abra o arquivo para leitura de metadados chamando IWMMetadataEditor::Open.
- Se o arquivo for um arquivo ASF válido e puder ser aberto, consulte o editor para obter a interface IWMHeaderInfo .
- Recupere as propriedades do arquivo chamando IWMHeaderInfo::GetAttributeByName, passando a constante de propriedade desejada do SDK do Windows Media Format. Uma lista de constantes do SDK de Formato com constantes equivalentes do SDK do Windows Media Gerenciador de Dispositivos é fornecida na tabela a seguir.
Constante do SDK de Formato de Mídia do Windows | Constante do SDK do Windows Media Gerenciador de Dispositivos |
---|---|
g_wszWMTitle | g_wszWMDMTitle |
g_wszWMAuthor | g_wszWMDMAuthor |
g_wszWMAlbumTitle | g_wszWMDMAlbumTitle |
g_wszWMGenre | g_wszWMDMGenre |
g_wszWMYear | g_wszWMDMYear |
g_wszWMTrackNumber ou 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 ou g_wszVideoFourCCCodec |
O código de exemplo C++ a seguir demonstra como recuperar várias propriedades de metadados de um arquivo ASF usando o SDK do Windows Media Format e convertê-las nos valores equivalentes do Windows Media Gerenciador de Dispositivos.
// 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;
}
A função de exemplo C++ a seguir mostra como usar o DirectShow para obter algumas informações de arquivo e adicioná-la aos metadados.
// 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;
}
Tópicos relacionados