#include "pch.h" #include "thisdll.h" #include "wmwrap.h" #include "MediaProp.h" #include "ids.h" // declr property set storage enum class CMediaPropSetEnum : public IEnumSTATPROPSETSTG { public: CMediaPropSetEnum(const PROPSET_INFO *propsets, ULONG cpropset, ULONG pos); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IEnumSTATPROPSETSTG STDMETHODIMP Next(ULONG celt, STATPROPSETSTG *rgelt, ULONG *pceltFetched); STDMETHODIMP Skip(ULONG celt); STDMETHODIMP Reset(); STDMETHODIMP Clone(IEnumSTATPROPSETSTG **ppenum); private: ~CMediaPropSetEnum(); LONG _cRef; ULONG _pos, _size; const PROPSET_INFO *_propsets; }; // property set storage enum STDMETHODIMP_(ULONG) CMediaPropSetEnum::AddRef() { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CMediaPropSetEnum::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CMediaPropSetEnum::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CMediaPropSetEnum, IEnumSTATPROPSETSTG), { 0 }, }; return QISearch(this, qit, riid, ppv); } // IEnum STDMETHODIMP CMediaPropSetEnum::Next(ULONG celt, STATPROPSETSTG *rgelt, ULONG *pceltFetched) { ULONG cFetched = 0; for (ULONG i = 0; i < celt && _pos < _size; i++) { ZeroMemory(&rgelt[i], sizeof(STATPROPSETSTG)); rgelt[i].fmtid = _propsets[_pos].fmtid; _pos++; cFetched++; } if (pceltFetched) *pceltFetched = cFetched; return cFetched == celt ? S_OK : S_FALSE; } STDMETHODIMP CMediaPropSetEnum::Skip(ULONG celt) { HRESULT hr; if (_pos + celt > _size) { hr = S_FALSE; _pos = _size; } else { hr = S_OK; _pos += celt; } return hr; } STDMETHODIMP CMediaPropSetEnum::Reset() { _pos = 0; return S_OK; } STDMETHODIMP CMediaPropSetEnum::Clone(IEnumSTATPROPSETSTG **ppenum) { HRESULT hr; CMediaPropSetEnum *penum = new CMediaPropSetEnum(_propsets, _size, _pos); if (penum) { hr = penum->QueryInterface(IID_PPV_ARG(IEnumSTATPROPSETSTG, ppenum)); penum->Release(); } else hr = STG_E_INSUFFICIENTMEMORY; return hr; } CMediaPropSetEnum::CMediaPropSetEnum(const PROPSET_INFO *propsets, ULONG cpropsets, ULONG pos) : _cRef(1), _propsets(propsets), _size(cpropsets), _pos(pos) { DllAddRef(); } CMediaPropSetEnum::~CMediaPropSetEnum() { DllRelease(); } HRESULT CMediaPropSetStg::_PopulateSlowProperties() { return S_OK; } HRESULT CMediaPropSetStg::_PopulateProperty(const COLMAP *pPInfo, PROPVARIANT *pvar) { CMediaPropStorage *pps; HRESULT hr = _ResolveFMTID(pPInfo->pscid->fmtid, &pps); if (SUCCEEDED(hr)) { PROPSPEC spec; spec.ulKind = PRSPEC_PROPID; spec.propid = pPInfo->pscid->pid; hr = pps->SetProperty(&spec, pvar); } PropVariantClear(pvar); return hr; } // Internal enumeration class used when populating properties. CEnumAllProps::CEnumAllProps(const PROPSET_INFO *pPropSets, UINT cPropSets) : _pPropSets(pPropSets), _cPropSets(cPropSets), _iPropSetPos(0), _iPropPos(0) { } const COLMAP *CEnumAllProps::Next() { const COLMAP *pcmReturn = NULL; while (_iPropSetPos < _cPropSets) { if (_iPropPos < _pPropSets[_iPropSetPos].cNumProps) { // Go to next property. pcmReturn = _pPropSets[_iPropSetPos].pcmProps[_iPropPos]; _iPropPos++; break; } else { // Go to next property set. _iPropSetPos++; _iPropPos = 0; } } return pcmReturn; } // Base media property set storage STDMETHODIMP_(ULONG) CMediaPropSetStg::AddRef() { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CMediaPropSetStg::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CMediaPropSetStg::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CMediaPropSetStg, IPropertySetStorage), QITABENT(CMediaPropSetStg, IPersistFile), QITABENTMULTI(CMediaPropSetStg, IPersist, IPersistFile), QITABENT(CMediaPropSetStg, IWMReaderCallback), { 0 }, }; return QISearch(this, qit, riid, ppv); } // IPersist STDMETHODIMP CMediaPropSetStg::GetClassID(CLSID *pClassID) { return E_NOTIMPL; } // IPersistFile STDMETHODIMP CMediaPropSetStg::IsDirty(void) { return S_FALSE;// sniff for uncommitted changed? } #define STGM_OPENMODE (STGM_READ | STGM_WRITE | STGM_READWRITE) // Any stuff we have to do at 'load time' HRESULT CMediaPropSetStg::_PreCheck() { return S_OK; } STDMETHODIMP CMediaPropSetStg::Load(LPCOLESTR pszFileName, DWORD dwMode) { // Allow Load only on existing files. if (dwMode & (STGM_CREATE | STGM_CONVERT | STGM_FAILIFTHERE)) return STG_E_INVALIDFLAG; EnterCriticalSection(&_cs); DWORD dwFlags = dwMode & STGM_OPENMODE; _dwMode = dwMode; HRESULT hr = StringCchCopy(_wszFile, ARRAYSIZE(_wszFile), pszFileName); if (SUCCEEDED(hr)) { _bHasBeenPopulated = FALSE; _bSlowPropertiesExtracted = FALSE; _hrPopulated = S_OK; _bIsWritable = (dwFlags & (STGM_WRITE | STGM_READWRITE)); _ResetPropertySet(); hr = _PreCheck(); } LeaveCriticalSection(&_cs); return hr; } STDMETHODIMP CMediaPropSetStg::Save(LPCOLESTR pszFileName, BOOL fRemember) { return E_NOTIMPL; } STDMETHODIMP CMediaPropSetStg::SaveCompleted(LPCOLESTR pszFileName) { return E_NOTIMPL; } STDMETHODIMP CMediaPropSetStg::GetCurFile(LPOLESTR *ppszFileName) { EnterCriticalSection(&_cs); HRESULT hr = SHStrDupW(_wszFile, ppszFileName); LeaveCriticalSection(&_cs); return hr; } // IPropertySetStorage methods STDMETHODIMP CMediaPropSetStg::Create(REFFMTID fmtid, const CLSID *pclsid, DWORD grfFlags, DWORD grfMode, IPropertyStorage** ppPropStg) { return E_NOTIMPL; } STDMETHODIMP CMediaPropSetStg::Open(REFFMTID fmtid, DWORD grfMode, IPropertyStorage** ppPropStg) { EnterCriticalSection(&_cs); HRESULT hr = _PopulatePropertySet(); if (SUCCEEDED(hr)) { DWORD dwPssMode = _dwMode & STGM_OPENMODE; switch (grfMode & STGM_OPENMODE) { case STGM_READ: break; case STGM_WRITE: if (!_bIsWritable || (dwPssMode == STGM_READ)) hr = E_FAIL; break; case STGM_READWRITE: if (!_bIsWritable || (dwPssMode != STGM_READWRITE)) hr = E_FAIL; break; default: hr = E_INVALIDARG; } if (SUCCEEDED(hr)) { CMediaPropStorage *pps; hr = _ResolveFMTID(fmtid, &pps); if (SUCCEEDED(hr)) { hr = pps->Open(STGM_SHARE_EXCLUSIVE, grfMode & STGM_OPENMODE, ppPropStg); } } } LeaveCriticalSection(&_cs); return hr; } STDMETHODIMP CMediaPropSetStg::Delete(REFFMTID fmtid) { return E_NOTIMPL; } STDMETHODIMP CMediaPropSetStg::Enum(IEnumSTATPROPSETSTG** ppenum) { HRESULT hr; CMediaPropSetEnum *psenum = new CMediaPropSetEnum(_pPropStgInfo, _cPropertyStorages, 0); if (psenum) { hr = psenum->QueryInterface(IID_PPV_ARG(IEnumSTATPROPSETSTG, ppenum)); psenum->Release(); } else hr = STG_E_INSUFFICIENTMEMORY; return hr; } CMediaPropSetStg::CMediaPropSetStg() : _cRef(1), _bHasBeenPopulated(FALSE), _dwMode(STGM_READ), _propStg(NULL) { _wszFile[0] = 0; DllAddRef(); } // The only place this is called is at creation time. HRESULT CMediaPropSetStg::Init() { HRESULT hr = E_FAIL; InitializeCriticalSection(&_cs); _hFileOpenEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (_hFileOpenEvent != NULL) { hr = _CreatePropertyStorages(); if (SUCCEEDED(hr)) { hr = _ResetPropertySet(); } } return hr; } CMediaPropSetStg::~CMediaPropSetStg() { if (_propStg) { for (ULONG i = 0; i < _cPropertyStorages; i++) { ATOMICRELEASE(_propStg[i]); } LocalFree(_propStg); } if (_hFileOpenEvent) { CloseHandle(_hFileOpenEvent); } DeleteCriticalSection(&_cs); DllRelease(); } BOOL CMediaPropSetStg::_IsSlowProperty(const COLMAP *pPInfo) { return FALSE; } HRESULT CMediaPropSetStg::FlushChanges(REFFMTID fmtid, LONG cNumProps, const COLMAP **pcmapInfo, PROPVARIANT *pVarProps, BOOL *pbDirtyFlags) { return E_NOTIMPL; } //returns success if we support that FMTID // ppps and ppcmPropInfo are optional HRESULT CMediaPropSetStg::_ResolveFMTID(REFFMTID fmtid, CMediaPropStorage **ppps) { for (ULONG i = 0; i < _cPropertyStorages; i++) { if (IsEqualGUID(_pPropStgInfo[i].fmtid, fmtid)) { if (ppps) *ppps = _propStg[i]; return S_OK; } } return E_FAIL; } HRESULT CMediaPropSetStg::_ResetPropertySet() { for (ULONG i = 0; i < _cPropertyStorages; i++) { _propStg[i]->_ResetPropStorage(); } return S_OK; } HRESULT CMediaPropSetStg::_CreatePropertyStorages() { HRESULT hr = E_OUTOFMEMORY; ASSERT(NULL == _propStg); _propStg = (CMediaPropStorage**)LocalAlloc(LPTR, sizeof(CMediaPropStorage*) * _cPropertyStorages); if (_propStg) { for (ULONG i = 0; i < _cPropertyStorages; i++) { ASSERTMSG(_pPropStgInfo[i].pcmProps != NULL, "CMediaPropSetStg::_CreatePropertyStorages: my COLMAP structure is null"); // We want to give each property storage a list of the COLMAPs that it supports. // This information is contained in _pPropStgInfo[i].ppids and cpids. // We'll make a new array of COLMAPS _propStg[i] = new CMediaPropStorage(this, NULL, _pPropStgInfo[i].fmtid, _pPropStgInfo[i].pcmProps, _pPropStgInfo[i].cNumProps, _dwMode, &_cs); if (!_propStg[i]) break; } hr = S_OK; } return hr; } HRESULT CMediaPropSetStg::_PopulatePropertySet() { return E_NOTIMPL; } STDMETHODIMP CMediaPropSetStg::OnStatus(WMT_STATUS Status, HRESULT hr, WMT_ATTR_DATATYPE dwType, BYTE *pValue, void *pvContext) { // This is callback from WMSDK while we're holding a critical section on the main thread, // waiting for this event to be set. switch(Status) { case WMT_OPENED: SetEvent(_hFileOpenEvent); break; } return S_OK; } STDMETHODIMP CMediaPropSetStg::OnSample(DWORD dwOutputNum, QWORD cnsSampleTime, QWORD cnsSampleDuration, DWORD dwFlags, INSSBuffer *pSample, void* pcontext) { return S_OK; }