summaryrefslogtreecommitdiffstats
path: root/dxsdk/Include/dmoimpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'dxsdk/Include/dmoimpl.h')
-rw-r--r--dxsdk/Include/dmoimpl.h645
1 files changed, 645 insertions, 0 deletions
diff --git a/dxsdk/Include/dmoimpl.h b/dxsdk/Include/dmoimpl.h
new file mode 100644
index 00000000..8ba6e3a8
--- /dev/null
+++ b/dxsdk/Include/dmoimpl.h
@@ -0,0 +1,645 @@
+//------------------------------------------------------------------------------
+// File: DMOImpl.h
+//
+// Desc: Classes to implement a DMO.
+//
+// Copyright (c) 2000-2001, Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------------------------
+
+
+#ifndef _dmoimpl_h_
+#define _dmoimpl_h_
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+// Class to implement a DMO
+//
+//
+// Assumes the number of input and output streams is fixed
+// (these are template parameters)
+//
+// Provides following services:
+//
+// Basic parameter checking and locking
+// Fully implements :
+// GetStreamCount
+// SetInputType
+// SetOutputType
+// GetCurrentInputType
+// GetCurrentOutputType
+//
+// Checks if all types are set before streaming
+// Automatically calls AllocateStreamingResources before streaming
+// if it's not been called already
+// Prevents streaming until the types on all non-optional streams
+// have been set
+//
+//
+// Derived class implements the following methods :
+//
+/*
+ HRESULT InternalGetInputStreamInfo(DWORD dwInputStreamIndex, DWORD *pdwFlags);
+ HRESULT InternalGetOutputStreamInfo(DWORD dwOutputStreamIndex, DWORD *pdwFlags);
+ HRESULT InternalCheckInputType(DWORD dwInputStreamIndex, const DMO_MEDIA_TYPE *pmt);
+ HRESULT InternalCheckOutputType(DWORD dwOutputStreamIndex, const DMO_MEDIA_TYPE *pmt);
+ HRESULT InternalGetInputType(DWORD dwInputStreamIndex, DWORD dwTypeIndex,
+ DMO_MEDIA_TYPE *pmt);
+ HRESULT InternalGetOutputType(DWORD dwOutputStreamIndex, DWORD dwTypeIndex,
+ DMO_MEDIA_TYPE *pmt);
+ HRESULT InternalGetInputSizeInfo(DWORD dwInputStreamIndex, DWORD *pcbSize,
+ DWORD *pcbMaxLookahead, DWORD *pcbAlignment);
+ HRESULT InternalGetOutputSizeInfo(DWORD dwOutputStreamIndex, DWORD *pcbSize,
+ DWORD *pcbAlignment);
+ HRESULT InternalGetInputMaxLatency(DWORD dwInputStreamIndex, REFERENCE_TIME *prtMaxLatency);
+ HRESULT InternalSetInputMaxLatency(DWORD dwInputStreamIndex, REFERENCE_TIME rtMaxLatency);
+ HRESULT InternalFlush();
+ HRESULT InternalDiscontinuity(DWORD dwInputStreamIndex);
+ HRESULT InternalAllocateStreamingResources();
+ HRESULT InternalFreeStreamingResources();
+ HRESULT InternalProcessInput(DWORD dwInputStreamIndex, IMediaBuffer *pBuffer,
+ DWORD dwFlags, REFERENCE_TIME rtTimestamp,
+ REFERENCE_TIME rtTimelength);
+ HRESULT InternalProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount,
+ DMO_OUTPUT_DATA_BUFFER *pOutputBuffers,
+ DWORD *pdwStatus);
+ HRESULT InternalAcceptingInput(DWORD dwInputStreamIndex);
+ void Lock();
+ void Unlock();
+
+ Notes:
+ The derived class is meant to do most work to initialize streaming
+ in AllocateStreamingResources rather than when types are set.
+
+ This centralizes the work to one
+ clear place based on the types set for all streams.
+
+ The derived class implements locking.
+
+ The derived class implements the IUnknown methods
+
+ Usage example (1 input and 1 output) :
+ class CMyDMO : public IMediaObjectImpl<CMyDmo, 1, 1>,
+ ...
+*/
+
+
+#define INTERNAL_CALL(_T_, _X_) \
+ static_cast<_T_ *>(this)->Internal##_X_
+
+template <class _DERIVED_, int NUMBEROFINPUTS, int NUMBEROFOUTPUTS>
+class IMediaObjectImpl : public IMediaObject
+{
+private:
+ // Member variables
+ struct {
+ DWORD fTypeSet:1;
+ DWORD fIncomplete:1;
+ DMO_MEDIA_TYPE CurrentMediaType;
+ } m_InputInfo[NUMBEROFINPUTS], m_OutputInfo[NUMBEROFOUTPUTS];
+
+ bool m_fTypesSet;
+ bool m_fFlushed;
+ bool m_fResourcesAllocated;
+
+protected:
+
+ // Helpers
+ bool InputTypeSet(DWORD ulInputStreamIndex) const
+ {
+ _ASSERTE(ulInputStreamIndex < NUMBEROFINPUTS);
+ return 0 != m_InputInfo[ulInputStreamIndex].fTypeSet;
+ }
+
+ bool OutputTypeSet(DWORD ulOutputStreamIndex) const
+ {
+ _ASSERTE(ulOutputStreamIndex < NUMBEROFOUTPUTS);
+ return 0 != m_OutputInfo[ulOutputStreamIndex].fTypeSet;
+ }
+ const DMO_MEDIA_TYPE *InputType(DWORD ulInputStreamIndex)
+ {
+ if (!InputTypeSet(ulInputStreamIndex)) {
+ return NULL;
+ }
+ return &m_InputInfo[ulInputStreamIndex].CurrentMediaType;
+ }
+ const DMO_MEDIA_TYPE *OutputType(DWORD ulOutputStreamIndex)
+ {
+ if (!OutputTypeSet(ulOutputStreamIndex)) {
+ return NULL;
+ }
+ return &m_OutputInfo[ulOutputStreamIndex].CurrentMediaType;
+ }
+
+
+ class LockIt
+ {
+ public:
+ LockIt(_DERIVED_ *p) : m_p(p)
+ {
+ static_cast<_DERIVED_ *>(m_p)->Lock();
+ }
+ ~LockIt()
+ {
+ static_cast<_DERIVED_ *>(m_p)->Unlock();
+ }
+ _DERIVED_ *const m_p;
+ };
+
+ bool CheckTypesSet()
+ {
+ m_fTypesSet = false;
+ DWORD dw;
+ for (dw = 0; dw < NUMBEROFINPUTS; dw++) {
+ if (!InputTypeSet(dw)) {
+ return false;
+ }
+ }
+ for (dw = 0; dw < NUMBEROFOUTPUTS; dw++) {
+ if (!OutputTypeSet(dw)) {
+ // Check if it's optional
+ DWORD dwFlags;
+#ifdef _DEBUG
+ dwFlags = 0xFFFFFFFF;
+#endif
+ INTERNAL_CALL(_DERIVED_, GetOutputStreamInfo)(dw, &dwFlags);
+ _ASSERTE(0 == (dwFlags & ~(DMO_OUTPUT_STREAMF_WHOLE_SAMPLES |
+ DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER |
+ DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE |
+ DMO_OUTPUT_STREAMF_DISCARDABLE |
+ DMO_OUTPUT_STREAMF_OPTIONAL)));
+ if (!(dwFlags & DMO_OUTPUT_STREAMF_OPTIONAL)) {
+ return false;
+ }
+ }
+ }
+ m_fTypesSet = true;
+ return true;
+ }
+
+
+ IMediaObjectImpl() :
+ m_fTypesSet(false),
+ m_fFlushed(true),
+ m_fResourcesAllocated(false)
+ {
+ ZeroMemory(&m_InputInfo, sizeof(m_InputInfo));
+ ZeroMemory(&m_OutputInfo, sizeof(m_OutputInfo));
+ }
+
+ virtual ~IMediaObjectImpl() {
+ DWORD dwCurrentType;
+
+ for (dwCurrentType = 0; dwCurrentType < NUMBEROFINPUTS; dwCurrentType++) {
+ if(InputTypeSet(dwCurrentType)) {
+ MoFreeMediaType(&m_InputInfo[dwCurrentType].CurrentMediaType);
+ }
+ }
+
+ for (dwCurrentType = 0; dwCurrentType < NUMBEROFOUTPUTS; dwCurrentType++) {
+ if(OutputTypeSet(dwCurrentType)) {
+ MoFreeMediaType(&m_OutputInfo[dwCurrentType].CurrentMediaType);
+ }
+ }
+ }
+
+
+ // IMediaObject methods
+
+
+ //
+ // IMediaObject methods
+ //
+ STDMETHODIMP GetStreamCount(unsigned long *pulNumberOfInputStreams, unsigned long *pulNumberOfOutputStreams)
+ {
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (pulNumberOfInputStreams == NULL ||
+ pulNumberOfOutputStreams == NULL) {
+ return E_POINTER;
+ }
+ *pulNumberOfInputStreams = NUMBEROFINPUTS;
+ *pulNumberOfOutputStreams = NUMBEROFOUTPUTS;
+ return S_OK;
+ }
+
+ STDMETHODIMP GetInputStreamInfo(ULONG ulStreamIndex, DWORD *pdwFlags)
+ {
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (pdwFlags == NULL) {
+ return E_POINTER;
+ }
+ HRESULT hr = INTERNAL_CALL(_DERIVED_, GetInputStreamInfo)(ulStreamIndex, pdwFlags);
+ _ASSERTE(0 == (*pdwFlags & ~(DMO_INPUT_STREAMF_WHOLE_SAMPLES |
+ DMO_INPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER |
+ DMO_INPUT_STREAMF_FIXED_SAMPLE_SIZE |
+ DMO_INPUT_STREAMF_HOLDS_BUFFERS)));
+ return hr;
+ }
+
+ STDMETHODIMP GetOutputStreamInfo(ULONG ulStreamIndex, DWORD *pdwFlags)
+ {
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (ulStreamIndex >= NUMBEROFOUTPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (pdwFlags == NULL) {
+ return E_POINTER;
+ }
+ HRESULT hr = INTERNAL_CALL(_DERIVED_, GetOutputStreamInfo)(ulStreamIndex, pdwFlags);
+ _ASSERTE(0 == (*pdwFlags & ~(DMO_OUTPUT_STREAMF_WHOLE_SAMPLES |
+ DMO_OUTPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER |
+ DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE |
+ DMO_OUTPUT_STREAMF_DISCARDABLE |
+ DMO_OUTPUT_STREAMF_OPTIONAL)));
+ return hr;
+ }
+
+ STDMETHODIMP GetInputType(ULONG ulStreamIndex, ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ return INTERNAL_CALL(_DERIVED_, GetInputType)(ulStreamIndex, ulTypeIndex, pmt);
+ }
+
+ STDMETHODIMP GetOutputType(ULONG ulStreamIndex, ULONG ulTypeIndex, DMO_MEDIA_TYPE *pmt) {
+ if (ulStreamIndex >= NUMBEROFOUTPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ return INTERNAL_CALL(_DERIVED_, GetOutputType)(ulStreamIndex, ulTypeIndex, pmt);
+ }
+
+ STDMETHODIMP GetInputCurrentType(ULONG ulStreamIndex, DMO_MEDIA_TYPE *pmt) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (NULL == pmt) {
+ return E_POINTER;
+ }
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (InputTypeSet(ulStreamIndex))
+ return MoCopyMediaType(pmt,
+ &m_InputInfo[ulStreamIndex].CurrentMediaType);
+ else
+ return DMO_E_TYPE_NOT_SET;
+ }
+
+ STDMETHODIMP GetOutputCurrentType(ULONG ulStreamIndex, DMO_MEDIA_TYPE *pmt) {
+ if (ulStreamIndex >= NUMBEROFOUTPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (NULL == pmt) {
+ return E_POINTER;
+ }
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (OutputTypeSet(ulStreamIndex))
+ return MoCopyMediaType(pmt,
+ &m_OutputInfo[ulStreamIndex].CurrentMediaType);
+ else
+ return DMO_E_TYPE_NOT_SET;
+ }
+
+ STDMETHODIMP GetInputSizeInfo(ULONG ulStreamIndex, ULONG *pulSize, ULONG *pcbMaxLookahead, ULONG *pulAlignment) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (NULL == pulSize || NULL == pulAlignment ||
+ NULL == pcbMaxLookahead) {
+ return E_POINTER;
+ }
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (!InputTypeSet(ulStreamIndex)) {
+ return DMO_E_TYPE_NOT_SET;
+ }
+ return INTERNAL_CALL(_DERIVED_, GetInputSizeInfo)(ulStreamIndex, pulSize, pcbMaxLookahead, pulAlignment);
+ }
+
+ STDMETHODIMP GetOutputSizeInfo(ULONG ulStreamIndex, ULONG *pulSize, ULONG *pulAlignment) {
+ if (ulStreamIndex >= NUMBEROFOUTPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (NULL == pulSize || NULL == pulAlignment) {
+ return E_POINTER;
+ }
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (!m_fTypesSet || !OutputTypeSet(ulStreamIndex)) {
+ return DMO_E_TYPE_NOT_SET;
+ }
+ return INTERNAL_CALL(_DERIVED_, GetOutputSizeInfo)(ulStreamIndex, pulSize, pulAlignment);
+ }
+
+ STDMETHODIMP SetInputType(ULONG ulStreamIndex, const DMO_MEDIA_TYPE *pmt, DWORD dwFlags) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (dwFlags & ~ (DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY)) {
+ return E_INVALIDARG;
+ }
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ if (dwFlags & DMO_SET_TYPEF_CLEAR) {
+ MoFreeMediaType(&m_InputInfo[ulStreamIndex].CurrentMediaType);
+ m_InputInfo[ulStreamIndex].fTypeSet = FALSE;
+ if (!CheckTypesSet()) {
+ Flush();
+ FreeStreamingResources();
+ }
+ return NOERROR;
+ }
+ if (NULL == pmt) {
+ return E_POINTER;
+ }
+ HRESULT hr = INTERNAL_CALL(_DERIVED_, CheckInputType)(ulStreamIndex, pmt);
+ if (FAILED(hr))
+ return hr;
+
+ if (dwFlags & DMO_SET_TYPEF_TEST_ONLY) {
+ return NOERROR;
+ }
+
+
+ // actually set the type
+ DMO_MEDIA_TYPE mtTemp;
+ if (S_OK == MoCopyMediaType(&mtTemp, pmt)) {
+ // Free any previous mediatype
+ if (InputTypeSet(ulStreamIndex)) {
+ MoFreeMediaType(&m_InputInfo[ulStreamIndex].CurrentMediaType);
+ }
+ m_InputInfo[ulStreamIndex].CurrentMediaType = mtTemp;
+ m_InputInfo[ulStreamIndex].fTypeSet = TRUE;
+ CheckTypesSet();
+ } else {
+ return E_OUTOFMEMORY;
+ }
+
+ return NOERROR;
+ }
+
+ STDMETHODIMP SetOutputType(ULONG ulStreamIndex, const DMO_MEDIA_TYPE *pmt, DWORD dwFlags) {
+ if (ulStreamIndex >= NUMBEROFOUTPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (dwFlags & ~ (DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY)) {
+ return E_INVALIDARG;
+ }
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ if (dwFlags & DMO_SET_TYPEF_CLEAR) {
+ MoFreeMediaType(&m_OutputInfo[ulStreamIndex].CurrentMediaType);
+ m_OutputInfo[ulStreamIndex].fTypeSet = FALSE;
+ if (!CheckTypesSet()) {
+ Flush();
+ FreeStreamingResources();
+ }
+ return NOERROR;
+ }
+ if (NULL == pmt) {
+ return E_POINTER;
+ }
+ HRESULT hr = INTERNAL_CALL(_DERIVED_, CheckOutputType)(ulStreamIndex, pmt);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ if (dwFlags & DMO_SET_TYPEF_TEST_ONLY) {
+ return NOERROR;
+ }
+
+
+ // actually set the type
+ DMO_MEDIA_TYPE mtTemp;
+ if (S_OK == MoCopyMediaType(&mtTemp, pmt)) {
+ // Free any previous mediatype
+ if (OutputTypeSet(ulStreamIndex)) {
+ MoFreeMediaType(&m_OutputInfo[ulStreamIndex].CurrentMediaType);
+ }
+ m_OutputInfo[ulStreamIndex].CurrentMediaType = mtTemp;
+ m_OutputInfo[ulStreamIndex].fTypeSet = TRUE;
+ CheckTypesSet();
+ } else {
+ return E_OUTOFMEMORY;
+ }
+
+ return NOERROR;
+ }
+
+ STDMETHODIMP GetInputStatus(
+ ULONG ulStreamIndex,
+ DWORD *pdwStatus
+ ) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (NULL == pdwStatus) {
+ return E_POINTER;
+ }
+ *pdwStatus = 0;
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ if (!m_fTypesSet) {
+ return DMO_E_TYPE_NOT_SET;
+ }
+
+ if (INTERNAL_CALL(_DERIVED_, AcceptingInput)(ulStreamIndex) == S_OK) {
+ *pdwStatus |= DMO_INPUT_STATUSF_ACCEPT_DATA;
+ }
+ return NOERROR;
+ }
+
+ STDMETHODIMP GetInputMaxLatency(unsigned long ulStreamIndex, REFERENCE_TIME *prtLatency) {
+
+ if (prtLatency == NULL) {
+ return E_POINTER;
+ }
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ return INTERNAL_CALL(_DERIVED_, GetInputMaxLatency)(ulStreamIndex, prtLatency);
+ }
+
+ STDMETHODIMP SetInputMaxLatency(unsigned long ulStreamIndex, REFERENCE_TIME rtLatency) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ return INTERNAL_CALL(_DERIVED_, SetInputMaxLatency)(ulStreamIndex, rtLatency);
+ }
+
+ STDMETHODIMP Discontinuity(ULONG ulStreamIndex) {
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ if (!m_fTypesSet) {
+ return DMO_E_TYPE_NOT_SET;
+ }
+
+ if (S_OK != INTERNAL_CALL(_DERIVED_, AcceptingInput)(ulStreamIndex)) {
+ return DMO_E_NOTACCEPTING;
+ }
+
+ return INTERNAL_CALL(_DERIVED_, Discontinuity)(ulStreamIndex);
+ }
+
+ STDMETHODIMP Flush()
+ {
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ if (!m_fTypesSet) {
+ return S_OK;
+ }
+ if (m_fFlushed) {
+ return S_OK;
+ }
+ HRESULT hr = INTERNAL_CALL(_DERIVED_, Flush)();
+ m_fFlushed = true;
+ return hr;
+ }
+
+ STDMETHODIMP AllocateStreamingResources() {
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (!m_fTypesSet) {
+ return DMO_E_TYPE_NOT_SET;
+ }
+ if (m_fResourcesAllocated) {
+ return S_OK;
+ }
+ HRESULT hr = INTERNAL_CALL(_DERIVED_, AllocateStreamingResources)();
+ if (SUCCEEDED(hr)) {
+ m_fResourcesAllocated = true;
+ }
+ return hr;
+ }
+
+ STDMETHODIMP FreeStreamingResources()
+ {
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+ if (m_fResourcesAllocated) {
+ m_fResourcesAllocated = false;
+ INTERNAL_CALL(_DERIVED_, Flush)();
+ return INTERNAL_CALL(_DERIVED_, FreeStreamingResources)();
+ }
+ return S_OK;
+ }
+
+ //
+ // Processing methods - public entry points
+ //
+ STDMETHODIMP ProcessInput(
+ DWORD ulStreamIndex,
+ IMediaBuffer *pBuffer, // [in], must not be NULL
+ DWORD dwFlags, // [in] - discontinuity, timestamp, etc.
+ REFERENCE_TIME rtTimestamp, // [in], valid if flag set
+ REFERENCE_TIME rtTimelength // [in], valid if flag set
+ ) {
+ if (!pBuffer) {
+ return E_POINTER;
+ }
+ if (ulStreamIndex >= NUMBEROFINPUTS) {
+ return DMO_E_INVALIDSTREAMINDEX;
+ }
+ if (dwFlags & ~(DMO_INPUT_DATA_BUFFERF_SYNCPOINT |
+ DMO_INPUT_DATA_BUFFERF_TIME |
+ DMO_INPUT_DATA_BUFFERF_TIMELENGTH)) {
+ return E_INVALIDARG;
+ }
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ // Make sure all streams have media types set and resources are allocated
+ HRESULT hr = AllocateStreamingResources();
+ if (FAILED(hr)) {
+ return hr;
+ }
+ if (INTERNAL_CALL(_DERIVED_, AcceptingInput)(ulStreamIndex) != S_OK) {
+ return DMO_E_NOTACCEPTING;
+ }
+
+ m_fFlushed = false;
+
+ return INTERNAL_CALL(_DERIVED_, ProcessInput)(
+ ulStreamIndex,
+ pBuffer,
+ dwFlags,
+ rtTimestamp,
+ rtTimelength);
+ }
+
+ STDMETHODIMP ProcessOutput(
+ DWORD dwFlags,
+ DWORD ulOutputBufferCount,
+ DMO_OUTPUT_DATA_BUFFER *pOutputBuffers,
+ DWORD *pdwStatus)
+ {
+ if (pdwStatus == NULL) {
+ return E_POINTER;
+ }
+
+
+ if (ulOutputBufferCount != NUMBEROFOUTPUTS || (dwFlags & ~DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER)) {
+ return E_INVALIDARG;
+ }
+
+ if (NUMBEROFOUTPUTS != 0 && pOutputBuffers == NULL) {
+ return E_POINTER;
+ }
+
+ *pdwStatus = 0;
+
+ LockIt lck(static_cast<_DERIVED_ *>(this));
+
+ HRESULT hr = AllocateStreamingResources();
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ for (DWORD dw = 0; dw < NUMBEROFOUTPUTS; dw++) {
+ pOutputBuffers[dw].dwStatus = 0;
+ }
+
+ hr = INTERNAL_CALL(_DERIVED_, ProcessOutput)(
+ dwFlags,
+ ulOutputBufferCount,
+ pOutputBuffers,
+ pdwStatus);
+
+ // remember the DMO's incomplete status
+ for (dw = 0; dw < NUMBEROFOUTPUTS; dw++) {
+ if (pOutputBuffers[dw].dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE) {
+ m_OutputInfo[dw].fIncomplete = TRUE;
+ } else {
+ m_OutputInfo[dw].fIncomplete = FALSE;
+ }
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP DMOLock(LONG lLock)
+ {
+ if (lLock) {
+ static_cast<_DERIVED_ *>(this)->Lock();
+ } else {
+ static_cast<_DERIVED_ *>(this)->Unlock();
+ }
+ return S_OK;
+ }
+};
+
+#endif // _dmoimpl_h_
+