Media Foundation 中的屬性
屬性是索引鍵/值組,其中索引鍵是 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;
}
如需媒體基礎屬性的完整清單,請參閱 媒體基礎屬性。 每個屬性的預期資料類型都會記載于該處。
序列化屬性
媒體基礎有兩個函式可序列化屬性存放區。 其中一個會將屬性寫入位元組陣列,另一個則會將它們寫入支援 IStream 介面的資料流程。 每個函式都有一個對應的函式,可載入資料。
作業 | 位元組陣列 | IStream |
---|---|---|
儲存 | MFGetAttributesAsBlob | MFSerializeAttributesToStream |
載入 | MFInitAttributesFromBlob | MFDeserializeAttributesFromStream |
若要將屬性存放區的內容寫入位元組陣列,請呼叫 MFGetAttributesAsBlob。 忽略具有 IUnknown 指標值的屬性。 若要將屬性載入回屬性存放區,請呼叫 MFInitAttributesFromBlob。
若要將屬性存放區寫入資料流程,請呼叫 MFSerializeAttributesToStream。 此函式可以封送處理 IUnknown 指標值。 呼叫端必須提供實作 IStream 介面的資料流程物件。 若要從資料流程載入屬性存放區,請呼叫 MFDeserializeAttributesFromStream。
實作 IMFAttributes
媒體基礎提供 IMFAttributes的庫存實作,這是藉由呼叫 MFCreateAttributes 函式來取得的。 在大部分情況下,您應該使用此實作,而不是提供您自己的自訂實作。
在某些情況下,您可能需要實作 IMFAttributes 介面:如果您實作繼承 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,請將範本引數設定為等於衍生介面的名稱。
相關主題