Microsoft DirectX 8.1 (C++) |
DirectX Media Objects (DMOs) manage buffer memory using a COM object that supports the IMediaBuffer interface, called a media buffer.
Media buffers serve a function similar to media samples in DirectShow, except that media samples are created and managed by an allocator object, which itself is provided by a filter. With DMOs, the client of the DMO is responsible for creating the media buffer object.
The following code show an minimal implementation of a media buffer object.
// CMediaBuffer object
#include <new>
#include <dmo.h>
class CMediaBuffer : public IMediaBuffer
{
private:
DWORD m_cbLength;
const DWORD m_cbMaxLength;
LONG m_cRef;
BYTE *m_pbData;
public:
CMediaBuffer(DWORD cbMaxLength) :
m_cRef(0),
m_cbMaxLength(cbMaxLength),
m_cbLength(0),
m_pbData(NULL)
{
m_pbData = new BYTE[cbMaxLength];
if (!m_pbData) throw std::bad_alloc();
}
~CMediaBuffer()
{
if (m_pbData) {
delete [] m_pbData;
}
}
// Creation function
static HRESULT CreateBuffer(long cbMaxLength, REFIID iid, void **ppUnk)
{
try {
CMediaBuffer *pBuffer = new CMediaBuffer(cbMaxLength);
return pBuffer->QueryInterface(iid, ppUnk);
}
catch (std::bad_alloc)
{
return E_OUTOFMEMORY;
}
}
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
if (ppv == NULL) {
return E_POINTER;
}
if (riid == IID_IMediaBuffer || riid == IID_IUnknown) {
*ppv = static_cast<IMediaBuffer *>(this);
AddRef();
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
LONG lRef = InterlockedDecrement(&m_cRef);
if (lRef == 0) {
delete this;
}
return lRef;
}
// IMediaBuffer methods
STDMETHODIMP SetLength(DWORD cbLength)
{
if (cbLength > m_cbMaxLength) {
return E_INVALIDARG;
} else {
m_cbLength = cbLength;
return S_OK;
}
}
STDMETHODIMP GetMaxLength(DWORD *pcbMaxLength)
{
if (pcbMaxLength == NULL) {
return E_POINTER;
}
*pcbMaxLength = m_cbMaxLength;
return S_OK;
}
STDMETHODIMP GetBufferAndLength(BYTE **ppbBuffer, DWORD *pcbLength)
{
if (ppbBuffer == NULL || pcbLength == NULL) {
return E_POINTER;
}
*ppbBuffer = m_pbData;
*pcbLength = m_cbLength;
return S_OK;
}
};