Attribute in Media Foundation
Ein Attribut ist ein Schlüssel-/Wertpaar, bei dem der Schlüssel eine GUID ist und der Wert ein PROPVARIANT ist. Attribute werden in Microsoft Media Foundation verwendet, um Objekte zu konfigurieren, Medienformate, Abfrageobjekteigenschaften und andere Zwecke zu konfigurieren.
Dieses Thema enthält folgende Abschnitte:
Info zu Attributen
Ein Attribut ist ein Schlüssel-/Wertpaar, bei dem der Schlüssel eine GUID ist und der Wert ein PROPVARIANT ist. Attributwerte sind auf die folgenden Datentypen beschränkt:
- Nicht signierte 32-Bit-Ganzzahl (UINT32).
- Nicht signierte 64-Bit-Ganzzahl (UINT64).
- 64-Bit-Gleitkommanummer.
- GUID.
- Auf NULL endende Zeichenfolge für breite Zeichen.
- Bytearray.
- IUnknown-Zeiger .
Diese Typen werden in der MF_ATTRIBUTE_TYPE-Aufzählung definiert. Um Attributwerte festzulegen oder abzurufen, verwenden Sie die IMFAttributes-Schnittstelle . Diese Schnittstelle enthält typsichere Methoden zum Abrufen und Festlegen von Werten nach Datentyp. Um beispielsweise eine 32-Bit-Ganzzahl festzulegen, rufen Sie IMFAttributes::SetUINT32 auf. Attributschlüssel sind innerhalb eines Objekts eindeutig. Wenn Sie zwei verschiedene Werte mit demselben Schlüssel festlegen, überschreibt der zweite Wert den ersten Wert.
Mehrere Media Foundation-Schnittstellen erben die IMFAttributes-Schnittstelle . Objekte, die diese Schnittstelle verfügbar machen, verfügen über optionale oder obligatorische Attribute, die die Anwendung auf dem Objekt festlegen sollte, oder attribute haben, die die Anwendung abrufen kann. Außerdem nehmen einige Methoden und Funktionen einen IMFAttributes-Zeiger als Parameter auf, wodurch die Anwendung Konfigurationsinformationen festlegen kann. Die Anwendung muss einen Attributspeicher erstellen, um die Konfigurationsattribute zu halten. Um einen leeren Attributspeicher zu erstellen, rufen Sie MFCreateAttributes auf.
Der folgende Code zeigt zwei Funktionen. Der erste erstellt einen neuen Attributspeicher und legt ein hypothetisches Attribut namens MY_ATTRIBUTE mit einem Zeichenfolgenwert fest. Die zweite Funktion ruft den Wert dieses Attributs ab.
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;
}
Eine vollständige Liste der Media Foundation-Attribute finden Sie unter Media Foundation-Attribute. Der erwartete Datentyp für jedes Attribut wird dort dokumentiert.
Serialisieren von Attributen
Media Foundation verfügt über zwei Funktionen zum Serialisieren von Attributspeichern. Eine schreibt die Attribute in ein Bytearray, der andere schreibt sie in einen Datenstrom, der die IStream-Schnittstelle unterstützt. Jede Funktion verfügt über eine entsprechende Funktion, die die Daten lädt.
Vorgang | Byte-Array | IStream |
---|---|---|
Speichern | MFGetAttributesAsBlob | MFSerializeAttributesToStream |
Laden | MFInitAttributesFromBlob | MFDeserializeAttributesFromStream |
Um den Inhalt eines Attributspeichers in ein Bytearray zu schreiben, rufen Sie MFGetAttributesAsBlob auf. Attribute mit IUnknown-Zeigerwerten werden ignoriert. Um die Attribute wieder in einen Attributspeicher zu laden, rufen Sie MFInitAttributesFromBlob auf.
Um einen Attributspeicher in einen Stream zu schreiben, rufen Sie MFSerializeAttributesToStream auf. Diese Funktion kann IUnknown-Zeigerwerte ermischen. Der Aufrufer muss ein Streamobjekt bereitstellen, das die IStream-Schnittstelle implementiert. Um einen Attributspeicher aus einem Stream zu laden, rufen Sie MFDeserializeAttributesFromStream auf.
Implementieren von IMFAttributes
Media Foundation stellt eine Aktienimplementierung von IMFAttributes bereit, die durch Aufrufen der MFCreateAttributes-Funktion abgerufen wird. In den meisten Fällen sollten Sie diese Implementierung verwenden und keine eigene benutzerdefinierte Implementierung bereitstellen.
Es gibt eine Situation, in der Sie möglicherweise die IMFAttributes-Schnittstelle implementieren müssen: Wenn Sie eine zweite Schnittstelle implementieren, die IMFAttributes erbt. In diesem Fall müssen Sie Implementierungen für die von der zweiten Schnittstelle geerbten IMFAttributes-Methoden bereitstellen.
In dieser Situation wird empfohlen, die vorhandene Media Foundation-Implementierung von IMFAttributes umzuschließen. Der folgende Code zeigt eine Klassenvorlage, die einen IMFAttributes-Zeiger enthält und jede IMFAttributes-Methode umschließt, außer für die IUnknown-Methoden.
#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);
}
};
Der folgende Code zeigt, wie eine Klasse aus dieser Vorlage abgeleitet wird:
#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;
}
};
Sie müssen aufrufen CBaseAttributes::Initialize
, um den Attributspeicher zu erstellen. Im vorherigen Beispiel wird dies in einer statischen Erstellungsfunktion ausgeführt.
Das Vorlagenargument ist ein Schnittstellentyp, der standardmäßig auf IMFAttributes festgelegt ist. Wenn Ihr Objekt eine Schnittstelle implementiert, die IMFAttributes erbt, z. B. IMFActivate, legt das Vorlagenargument den Namen der abgeleiteten Schnittstelle fest.
Zugehörige Themen