媒体基础中的属性
属性是键/值对,其中键为 GUID,值为 PROPVARIANT。 在整个 Microsoft Media Foundation 中使用属性来配置对象、描述媒体格式、查询对象属性和其他目的。
本主题包含以下各节:
关于属性
属性是键/值对,其中键为 GUID,值为 PROPVARIANT。 属性值限制为以下数据类型:
- 无符号 32 位整数 (UINT32) 。
- 无符号 64 位整数 (UINT64) 。
- 64 位浮点数。
- GUID。
- 以 Null 结尾的宽字符字符串。
- 字节数组。
- IUnknown 指针。
这些类型在 MF_ATTRIBUTE_TYPE 枚举中定义。 若要设置或检索属性值,请使用 IMFAttributes 接口。 此接口包含用于按数据类型获取和设置值的类型安全方法。 例如,若要设置 32 位整数,请调用 IMFAttributes::SetUINT32。 属性键在 对象中是唯一的。 如果设置两个具有相同键的不同值,则第二个值将覆盖第一个值。
多个媒体基础接口继承 IMFAttributes 接口。 公开此接口的对象具有应用程序应在对象上设置的可选或必需属性,或者具有应用程序可以检索的属性。 此外,某些方法和函数将 IMFAttributes 指针作为参数,使应用程序能够设置配置信息。 应用程序必须创建属性存储来保存配置属性。 若要创建空的属性存储,请调用 MFCreateAttributes。
以下代码显示了两个函数。 第一个创建一个新的属性存储区,并使用字符串值设置名为 MY_ATTRIBUTE 的假设属性。 第二个函数检索此属性的值。
extern const GUID MY_ATTRIBUTE;
HRESULT ShowCreateAttributeStore(IMFAttributes **ppAttributes)
{
IMFAttributes *pAttributes = NULL;
const UINT32 cElements = 10; // Starting size.
// Create the empty attribute store.
HRESULT hr = MFCreateAttributes(&pAttributes, cElements);
// Set the MY_ATTRIBUTE attribute with a string value.
if (SUCCEEDED(hr))
{
hr = pAttributes->SetString(
MY_ATTRIBUTE,
L"This is a string value"
);
}
// Return the IMFAttributes pointer to the caller.
if (SUCCEEDED(hr))
{
*ppAttributes = pAttributes;
(*ppAttributes)->AddRef();
}
SAFE_RELEASE(pAttributes);
return hr;
}
HRESULT ShowGetAttributes()
{
IMFAttributes *pAttributes = NULL;
WCHAR *pwszValue = NULL;
UINT32 cchLength = 0;
// Create the attribute store.
HRESULT hr = ShowCreateAttributeStore(&pAttributes);
// Get the attribute.
if (SUCCEEDED(hr))
{
hr = pAttributes->GetAllocatedString(
MY_ATTRIBUTE,
&pwszValue,
&cchLength
);
}
CoTaskMemFree(pwszValue);
SAFE_RELEASE(pAttributes);
return hr;
}
有关媒体基础属性的完整列表,请参阅 媒体基础属性。 其中记录了每个属性的预期数据类型。
序列化属性
Media Foundation 有两个用于序列化属性存储的函数。 一个将属性写入字节数组,另一个将属性写入支持 IStream 接口的流。 每个函数都有一个加载数据的相应函数。
Operation | 字节数组 | IStream |
---|---|---|
保存 | MFGetAttributesAsBlob | MFSerializeAttributesToStream |
加载 | MFInitAttributesFromBlob | MFDeserializeAttributesFromStream |
若要将属性存储的内容写入字节数组,请调用 MFGetAttributesAsBlob。 忽略具有 IUnknown 指针值的属性。 若要将属性加载回属性存储中,请调用 MFInitAttributesFromBlob。
若要将属性存储写入流,请调用 MFSerializeAttributesToStream。 此函数可以封送 IUnknown 指针值。 调用方必须提供实现 IStream 接口的流对象。 若要从流加载属性存储,请调用 MFDeserializeAttributesFromStream。
实现 IMFAttributes
媒体基础提供 IMFAttributes 的库存实现,该实现通过调用 MFCreateAttributes 函数获得。 在大多数情况下,应使用此实现,而不是提供自己的自定义实现。
有一种情况可能需要实现 IMFAttributes 接口:如果实现继承 IMFAttributes 的第二个接口。 在这种情况下,必须为第二个接口继承的 IMFAttributes 方法提供实现。
在这种情况下,建议包装 货币基金组织现有媒体基金会实施方案。 以下代码显示了一个类模板,该模板保存 IMFAttributes 指针并包装每个 IMFAttributes 方法( IUnknown 方法除外)。
#include <assert.h>
// Helper class to implement IMFAttributes.
// This is an abstract class; the derived class must implement the IUnknown
// methods. This class is a wrapper for the standard attribute store provided
// in Media Foundation.
// template parameter:
// The interface you are implementing, either IMFAttributes or an interface
// that inherits IMFAttributes, such as IMFActivate
template <class IFACE=IMFAttributes>
class CBaseAttributes : public IFACE
{
protected:
IMFAttributes *m_pAttributes;
// This version of the constructor does not initialize the
// attribute store. The derived class must call Initialize() in
// its own constructor.
CBaseAttributes() : m_pAttributes(NULL)
{
}
// This version of the constructor initializes the attribute
// store, but the derived class must pass an HRESULT parameter
// to the constructor.
CBaseAttributes(HRESULT& hr, UINT32 cInitialSize = 0) : m_pAttributes(NULL)
{
hr = Initialize(cInitialSize);
}
// The next version of the constructor uses a caller-provided
// implementation of IMFAttributes.
// (Sometimes you want to delegate IMFAttributes calls to some
// other object that implements IMFAttributes, rather than using
// MFCreateAttributes.)
CBaseAttributes(HRESULT& hr, IUnknown *pUnk)
{
hr = Initialize(pUnk);
}
virtual ~CBaseAttributes()
{
if (m_pAttributes)
{
m_pAttributes->Release();
}
}
// Initializes the object by creating the standard Media Foundation attribute store.
HRESULT Initialize(UINT32 cInitialSize = 0)
{
if (m_pAttributes == NULL)
{
return MFCreateAttributes(&m_pAttributes, cInitialSize);
}
else
{
return S_OK;
}
}
// Initializes this object from a caller-provided attribute store.
// pUnk: Pointer to an object that exposes IMFAttributes.
HRESULT Initialize(IUnknown *pUnk)
{
if (m_pAttributes)
{
m_pAttributes->Release();
m_pAttributes = NULL;
}
return pUnk->QueryInterface(IID_PPV_ARGS(&m_pAttributes));
}
public:
// IMFAttributes methods
STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue)
{
assert(m_pAttributes);
return m_pAttributes->GetItem(guidKey, pValue);
}
STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType)
{
assert(m_pAttributes);
return m_pAttributes->GetItemType(guidKey, pType);
}
STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult)
{
assert(m_pAttributes);
return m_pAttributes->CompareItem(guidKey, Value, pbResult);
}
STDMETHODIMP Compare(
IMFAttributes* pTheirs,
MF_ATTRIBUTES_MATCH_TYPE MatchType,
BOOL* pbResult
)
{
assert(m_pAttributes);
return m_pAttributes->Compare(pTheirs, MatchType, pbResult);
}
STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue)
{
assert(m_pAttributes);
return m_pAttributes->GetUINT32(guidKey, punValue);
}
STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue)
{
assert(m_pAttributes);
return m_pAttributes->GetUINT64(guidKey, punValue);
}
STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue)
{
assert(m_pAttributes);
return m_pAttributes->GetDouble(guidKey, pfValue);
}
STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue)
{
assert(m_pAttributes);
return m_pAttributes->GetGUID(guidKey, pguidValue);
}
STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength)
{
assert(m_pAttributes);
return m_pAttributes->GetStringLength(guidKey, pcchLength);
}
STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength)
{
assert(m_pAttributes);
return m_pAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
}
STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength)
{
assert(m_pAttributes);
return m_pAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
}
STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize)
{
assert(m_pAttributes);
return m_pAttributes->GetBlobSize(guidKey, pcbBlobSize);
}
STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize)
{
assert(m_pAttributes);
return m_pAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
}
STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize)
{
assert(m_pAttributes);
return m_pAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
}
STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv)
{
assert(m_pAttributes);
return m_pAttributes->GetUnknown(guidKey, riid, ppv);
}
STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value)
{
assert(m_pAttributes);
return m_pAttributes->SetItem(guidKey, Value);
}
STDMETHODIMP DeleteItem(REFGUID guidKey)
{
assert(m_pAttributes);
return m_pAttributes->DeleteItem(guidKey);
}
STDMETHODIMP DeleteAllItems()
{
assert(m_pAttributes);
return m_pAttributes->DeleteAllItems();
}
STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue)
{
assert(m_pAttributes);
return m_pAttributes->SetUINT32(guidKey, unValue);
}
STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue)
{
assert(m_pAttributes);
return m_pAttributes->SetUINT64(guidKey, unValue);
}
STDMETHODIMP SetDouble(REFGUID guidKey, double fValue)
{
assert(m_pAttributes);
return m_pAttributes->SetDouble(guidKey, fValue);
}
STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue)
{
assert(m_pAttributes);
return m_pAttributes->SetGUID(guidKey, guidValue);
}
STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue)
{
assert(m_pAttributes);
return m_pAttributes->SetString(guidKey, wszValue);
}
STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize)
{
assert(m_pAttributes);
return m_pAttributes->SetBlob(guidKey, pBuf, cbBufSize);
}
STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown)
{
assert(m_pAttributes);
return m_pAttributes->SetUnknown(guidKey, pUnknown);
}
STDMETHODIMP LockStore()
{
assert(m_pAttributes);
return m_pAttributes->LockStore();
}
STDMETHODIMP UnlockStore()
{
assert(m_pAttributes);
return m_pAttributes->UnlockStore();
}
STDMETHODIMP GetCount(UINT32* pcItems)
{
assert(m_pAttributes);
return m_pAttributes->GetCount(pcItems);
}
STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue)
{
assert(m_pAttributes);
return m_pAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
}
STDMETHODIMP CopyAllItems(IMFAttributes* pDest)
{
assert(m_pAttributes);
return m_pAttributes->CopyAllItems(pDest);
}
// Helper functions
HRESULT SerializeToStream(DWORD dwOptions, IStream* pStm)
// dwOptions: Flags from MF_ATTRIBUTE_SERIALIZE_OPTIONS
{
assert(m_pAttributes);
return MFSerializeAttributesToStream(m_pAttributes, dwOptions, pStm);
}
HRESULT DeserializeFromStream(DWORD dwOptions, IStream* pStm)
{
assert(m_pAttributes);
return MFDeserializeAttributesFromStream(m_pAttributes, dwOptions, pStm);
}
// SerializeToBlob: Stores the attributes in a byte array.
//
// ppBuf: Receives a pointer to the byte array.
// pcbSize: Receives the size of the byte array.
//
// The caller must free the array using CoTaskMemFree.
HRESULT SerializeToBlob(UINT8 **ppBuffer, UINT32 *pcbSize)
{
assert(m_pAttributes);
if (ppBuffer == NULL)
{
return E_POINTER;
}
if (pcbSize == NULL)
{
return E_POINTER;
}
*ppBuffer = NULL;
*pcbSize = 0;
UINT32 cbSize = 0;
BYTE *pBuffer = NULL;
HRESULT hr = MFGetAttributesAsBlobSize(m_pAttributes, &cbSize);
if (FAILED(hr))
{
return hr;
}
pBuffer = (BYTE*)CoTaskMemAlloc(cbSize);
if (pBuffer == NULL)
{
return E_OUTOFMEMORY;
}
hr = MFGetAttributesAsBlob(m_pAttributes, pBuffer, cbSize);
if (SUCCEEDED(hr))
{
*ppBuffer = pBuffer;
*pcbSize = cbSize;
}
else
{
CoTaskMemFree(pBuffer);
}
return hr;
}
HRESULT DeserializeFromBlob(const UINT8* pBuffer, UINT cbSize)
{
assert(m_pAttributes);
return MFInitAttributesFromBlob(m_pAttributes, pBuffer, cbSize);
}
HRESULT GetRatio(REFGUID guidKey, UINT32* pnNumerator, UINT32* punDenominator)
{
assert(m_pAttributes);
return MFGetAttributeRatio(m_pAttributes, guidKey, pnNumerator, punDenominator);
}
HRESULT SetRatio(REFGUID guidKey, UINT32 unNumerator, UINT32 unDenominator)
{
assert(m_pAttributes);
return MFSetAttributeRatio(m_pAttributes, guidKey, unNumerator, unDenominator);
}
// Gets an attribute whose value represents the size of something (eg a video frame).
HRESULT GetSize(REFGUID guidKey, UINT32* punWidth, UINT32* punHeight)
{
assert(m_pAttributes);
return MFGetAttributeSize(m_pAttributes, guidKey, punWidth, punHeight);
}
// Sets an attribute whose value represents the size of something (eg a video frame).
HRESULT SetSize(REFGUID guidKey, UINT32 unWidth, UINT32 unHeight)
{
assert(m_pAttributes);
return MFSetAttributeSize (m_pAttributes, guidKey, unWidth, unHeight);
}
};
以下代码演示如何从此模板派生类:
#include <shlwapi.h>
class MyObject : public CBaseAttributes<>
{
MyObject() : m_nRefCount(1) { }
~MyObject() { }
long m_nRefCount;
public:
// IUnknown
STDMETHODIMP MyObject::QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] =
{
QITABENT(MyObject, IMFAttributes),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) MyObject::AddRef()
{
return InterlockedIncrement(&m_nRefCount);
}
STDMETHODIMP_(ULONG) MyObject::Release()
{
ULONG uCount = InterlockedDecrement(&m_nRefCount);
if (uCount == 0)
{
delete this;
}
return uCount;
}
// Static function to create an instance of the object.
static HRESULT CreateInstance(MyObject **ppObject)
{
HRESULT hr = S_OK;
MyObject *pObject = new MyObject();
if (pObject == NULL)
{
return E_OUTOFMEMORY;
}
// Initialize the attribute store.
hr = pObject->Initialize();
if (FAILED(hr))
{
delete pObject;
return hr;
}
*ppObject = pObject;
(*ppObject)->AddRef();
return S_OK;
}
};
必须调用 CBaseAttributes::Initialize
来创建属性存储。 在前面的示例中,该操作在静态创建函数中完成。
模板参数是接口类型,默认为 IMFAttributes。 如果对象实现继承 IMFAttributes 的接口(如 IMFActivate),请将模板参数设置为派生接口的名称。
相关主题